Threads Game of Life - Threads

blueJisCrap

Mitglied
Hallo zusammen,
ich habe nach gescheiterten Versuchen ein performantes Conway's Game of Life zu implementieren das ganze neu geschrieben und versucht es mit mehr als 2 Threads umzusetzen. Bis dahin hat's auch noch ganz gut geklappt, nur wollte ich das Zeichnen des Feldes jetzt eben auch noch aufteilen, und dabei ist mir evtl. ein Deadlock untergekommen.
Nur bin ich mir da nicht so sicher, ich sehe nämlich den konkreten (Denk-)Fehler nicht, nur dass es eben nicht läuft.

Also, hier mal der gesamte Code:

Klasse Conway:
Java:
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;

public class Conway extends JFrame implements Runnable
{
    public static final String prefix = "Beta";
    public static final String edition = "MT";
    public static final String version = "2.0";

    public static final int SCALE = 1;
    public static final int WIDTH = 1800;
    public static final int HEIGHT = 900;

    public static final boolean RANDOMIZED = false;
    public static final int BORDER = 20;

    private volatile boolean running = true;
    private World map;

    public Conway()
    {
        super("Conway's Game of Life" + " " + edition + " " + prefix + " " + version);
        map = new World(WIDTH, HEIGHT);
        setSize(WIDTH*SCALE + 2*BORDER, HEIGHT*SCALE + 4*BORDER);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().setBackground(Color.WHITE);
        setLocationRelativeTo(getParent());
        setResizable(false);
        setVisible(true);
    }

    public static void main(String[] args)
    {
        Conway con = new Conway();
        Thread thread = new Thread(con, "Conway");
        thread.start();
    }

    public void run()
    {
        map.start();
        while(running)
        {
            tick();
            System.out.println(getName() + " completed tick");
        }
    }

    private void tick()
    {
        repaint();
    }

    public void paint(Graphics g)
    {
        map.paint(g);
    }

    public void quit()
    {
        map.quit();
        running = false;
        System.out.println("All threads should be terminated...");
        System.exit(0);
    }
}

World:
Java:
import java.util.Random;
import java.awt.*;
import java.awt.image.BufferedImage;

public class World extends Thread
{
    private int width, height;
    private boolean[][] map, nextMap;

    public volatile boolean done = false;
    private volatile boolean running = true;

    private Random rnd;
    private RenderAssistant[] assistants;
    private BufferedImage bImage;

    public World(int x, int y)
    {
        super("World");
        width = x;
        height = y;
        map = new boolean[width][height];
        nextMap = new boolean[width][height];
        
        int amount = 0;
        amount = height%3 > 0 ? height/3 + 1 : height/3;
        assistants = new RenderAssistant[amount];
        int restHeight = height;
        for(int i = 0; i < amount; i++)
        {
            assistants[i] = new RenderAssistant(width, restHeight/(amount - i), i+1);
            restHeight -= restHeight/(amount - i);
        }
        
        rnd = new Random();
        if (Conway.RANDOMIZED)
        {
            for(int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    map[i][j] = rnd.nextBoolean();
                }
            }
        }

        bImage = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR); 
        Graphics2D g2 = bImage.createGraphics();
        g2.setColor(Color.RED);
        g2.fillRect(0 , 0, width, height);
    }

    public void run()
    {
        while(running)
        {
            tick();
            System.out.println(getName() + " completed tick");
        }
    }

    private synchronized void tick()
    {
        while(done)
        {
            try
            {
                wait();
            }
            catch(InterruptedException e)
            {

            }
        }
        
        nextStep();
        
        int tHeight = 0;
        for(RenderAssistant r : assistants)
        {
            int y = r.getY();
            boolean[][] temp = new boolean[width][y];
            for(int i = 0; i < width; i++)
            {
                for(int j = 0; j < y; j++)
                {
                    temp[i][j] = nextMap[i][j + tHeight];
                }
            }
            r.setWork(temp);
            tHeight += y;
        }
        map = nextMap;
        /*
        for(int i = 0; i < width; i++)
        {
            for (int j = 0; j < height; j++)
            {
                if(map[i][j] != nextMap[i][j])
                {
                    map[i][j] = nextMap[i][j];
                    if(map[i][j])
                    {
                        bImage.setRGB(i, j, 0xff000000); //black
                    }
                    else
                    {
                        bImage.setRGB(i, j, 0xffff0000); //red
                    }
                }
            }
        }
        */
       
        done = true;
        notify();
    }

    public synchronized void paint(Graphics g)
    {
        while(!done)
        {
            try
            {
                wait();
            }
            catch(InterruptedException e)
            {

            }
        }
        
        Graphics2D g2 = bImage.createGraphics();
        int tHeight = 0;
        for(RenderAssistant r : assistants)
        {
            g2.drawImage(r.getResult(), 0, 0, null);
            tHeight += r.getY();
        }
        g.drawImage(bImage, Conway.BORDER, 3*Conway.BORDER, width*Conway.SCALE, height*Conway.SCALE, null);
        
        done = false;
        notify();
    }

    public void quit()
    {
        for(RenderAssistant r : assistants)
        {
            quit();
        }
        
        running = false;
    }

    private int getAmountOfNeighbors(int x, int y)
    {
        int n = 0;
        if ((x < width) && (y < height) && (y >= 0) && (x >= 0))
        {
            for(int i =  x-1; i <= x+1; i++)
            {
                for(int j =  y-1; j <= y+1; j++)
                {
                    if(getState(i, j))
                    {
                        n++;
                    }
                }
            }
        }
        return n;
    }

    private boolean getState(int x, int y)
    {
        if ((x < width) && (y < height) && (y >= 0) && (x >= 0))
        {
            return map[x][y];
        }
        else if (Conway.RANDOMIZED)
        {
            return false;
        }
        else
        {
            return true;
        }
    }

    private boolean getNextState(int x, int y)
    {
        if ((x < width) && (y < height) && (y >= 0) && (x >= 0))
        {
            if(getState(x, y))
            {
                switch(getAmountOfNeighbors(x, y) - 1)
                {
                    case 2: case 3: {return true;}
                    default: {return false;}
                }
            }
            else
            {
                if(getAmountOfNeighbors(x, y) == 3)
                {
                    return true;
                }
                return false;
            }
        }
        return false;
    }

    private void nextStep()
    {
        for(int i = 0; i < width; i++)
        {
            for (int j = 0; j < height; j++)
            {
                nextMap[i][j] = getNextState(i, j);
            }
        }
    }
}

RenderAssistant:
Java:
import java.awt.image.BufferedImage;

public class RenderAssistant extends Thread
{
    private int width, height;
    private boolean[][] toRender;
    public BufferedImage bImage;
    public boolean done, assigned;
    public volatile boolean running = true;

    public RenderAssistant(int x, int y, int index)
    {
        super("RenderAssistant " + index);
        width = x;
        height = y;
        toRender = new boolean[width][height];
        bImage = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR); 
    }

    public int getY()
    {
        return height;
    }
    
    public void run()
    {
        while(running)
        {
            render();
            System.out.println(getName() + " completed render");
        }
    }
    
    public synchronized void setWork(boolean[][] work)
    {
        while(assigned)
        {
            try
            {
                wait();
            }
            catch(InterruptedException e)
            {

            }
        }
        toRender = work;
        assigned = true;
        done = false;
        notify();
    }

    public synchronized void render()
    {
        while(done || !assigned)
        {
            try
            {
                wait();
            }
            catch(InterruptedException e)
            {

            }
        }

        for(int i = 0; i < width; i++)
        {
            for (int j = 0; j < height; j++)
            {
                if(toRender[i][j])
                {
                    bImage.setRGB(i, j, 0xff000000); //black
                }
                else
                {
                    bImage.setRGB(i, j, 0xffff0000); //red
                }
            }
        }
        done = true;
        notify();
    }

    public synchronized BufferedImage getResult()
    {
        while(!done)
        {
            try
            {
                wait();
            }
            catch(InterruptedException e)
            {

            }
        }
        
        assigned = false;
        notify();
        return bImage;
    }

    public void quit()
    {
        running = false;
    }
}

Der Fehler müsste entweder in World oder RenderAssistant liegen, da ich ab der funktionierenden Version an Conway nichts geändert habe. Der Vollständigkeit halber habe ich halt mal alles gepostet.

Ach, der Konsolenoutput ist eine endlose Reihe von
Code:
frame0 completed tick
.
 
Zuletzt bearbeitet von einem Moderator:

Marco13

Top Contributor
Bei einem Deadlock würde ich gar nichts mehr tun, aber... die Ausgabe kommt daher, dass dort ein Thread volle Pulle ständig "repaint" aufruft. Bedenke, dass "repaint" NICHT neu zeichnet, sondern NUR sagt, dass (irgendwann später) neu gezeichnet werden soll...
 

Marco13

Top Contributor
Das ist durch drüberlesen schwer zu erkennen. Falls es nicht hilft, ein paar
Java:
System.out.println("Waiting on "+xxx);
xxx.wait();
System.out.println("Waiting on "+xxx+" DONE");
etc. Debug-Ausgaben einbauen, kann man ja mal versuchen, es zu starten...
 

faetzminator

Gesperrter Benutzer
das ist gut zu wissen, wie kann ich das umgehen?
Sprich: Wie kann ich direkt neu zeichnen?

AFAIK gar nicht. Musst du aber auch nicht. Wenn dein Programm irgendwelche GUI-Elemente neu zeichnen will, aber das Fenster z.B. minimiert wurde, dann muss das GUI nicht neu gezeichnet werden. Es wird neu gezeichnet, wenns wieder in den Vordergrund kommt.
 

Marco13

Top Contributor
Naja, es gibt zwar "paintImmediately", aber ... die Fälle, in denen man das braucht oder es sinnvoll ist, sind doch SEHR begrenzt...
 

blueJisCrap

Mitglied
Ich möchte es aber mit ca. 60 fps neu zeichnen...

Das ändert aber effektiv nichts daran, dass mein Programm letzten Endes nicht das tut was es tun soll, unabhängig vom repaint.
 
S

SlaterB

Gast
mit den Ausgaben von Marco13 ist das sehr schnell entdeckt,
und wenn du schon sowas wie wait/notify in die paint-Methode schreibst kannst du ruhig auch erklären, was du dir das vorstellst,
wer soll da warten (der AWT-Thread?) wer soll wen wann warum aufwecken usw.

wie stellst du dir einerseits bisher den Codeablauf vor und evtl. davon abweichend was ist dein Gesamtkonzept für das Programm,

ziemlich viel davon ist offensichtlich und ich könnte in 20 Zeilen hier alles mögliche hinschreiben, vor allem was daran nicht funktioniert,
aber dann hättest du ja gar keine Arbeit..

oder etwas kürzer doch gleich Hilfe:
vergiss es, mit dem AWT-Thread zu synchronisieren, jedenfalls auf diese Weise,
wenn gezeichnet wird, dann wird immer genau das gezeichnet was aktuell da ist, Ende der Diskussion

zu zeichnende Daten werden sicherlich separat von Threads geändert, dabei gilt aber grundsätzlich zu beachten:
1.
die nebenläufigen Threads arbeiten auf Kopien von Daten oder ändern sie zumindest nicht sondern merken sich die Änderungen während der langen Bearbeitungszeit in Datenbestandteilen, die im paint nicht verwendet werden,

2.
wenn es nötig ist, dann wird für einen möglichst kurzen Moment der AWT-Thread zum Zeichnen unterbrochen und die kritischen Daten geändert
(nicht in langen Berechnungen, weil die GUI solange pausiert, sondern die angesammelten schnellen Änderungen)

das passiert aber nicht über wait/ notify, obwohl möglich, sondern doch besser mit dem extra dafür vorhandenen Konzept SwingUtilities.invokeLater(), such dazu mal Quellen,
oder auch SwingWorker als noch neueres, kenne ich nicht so genau


so, wenn du es richtig machen willst, dann sind die bisherigen Fehler relativ unerheblich, kommt alles weg,
wenn du dich doch über den wait/ notify-Ablauf unterhalten willst, dann wie gesagt bitte erstmal selber was erzählen,
1 Zeile Frage - 20 Zeilen Antwort, das mag ich nie ;)
 
Zuletzt bearbeitet von einem Moderator:

blueJisCrap

Mitglied
Also gut, nun wohl etwas ausführlicher:

Grundsätzlich ist mein Ziel, eine eigene Version von Conway's Game of Life zu implementieren.
Das hat auch funktioniert, war nur nicht ganz so schnell wie ich mir das vorgestellt habe.
D.h. es war zwar bei kleinen Feldern (600x600) noch recht schnell, aber eben bei großen (1800x900) doch relativ langsam.
Diese funktionierende Version besteht aus 2 Threads: Der eine zeichnet und wartet dann (bei 60fps ca. 16ms), der andere berechnet während dieser Wartezeit die nächste Generation des (Spiel-)feldes und schreibt die Ergebnisse auch schon in ein BufferedImage.

Nachdem ich bei großen Feldern immer noch keine idealen Ergebnisse bekomme, dachte ich mir, man könnte das Erstellen des BufferedImage auch nochmal aufteilen ( --> RenderAssistant), und daran bin ich grandios gescheitert.

Insgesamt ziele ich bei einem Feld von 1800x900 30fps, im Idealfall 60 an, momentan bekomme ich auf meinem Rechner schlappe 15 (und das ist keine alte Mühle ;-) )

Hier zum Vergleich die - leicht aktualisierte - 2-Thread-Lösung, die auch ohne weiteres funktionieren sollte:

Conway:
Java:
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;

public class Conway extends JFrame implements Runnable
{
    public static final String prefix = "Beta";
    public static final String edition = "MT";
    public static final String version = "2.0";

    public static final int SCALE = 1;
    public static final int WIDTH = 1800;
    public static final int HEIGHT = 900;

    public static final boolean RANDOMIZED = false;
    public static final int BORDER = 20;

    private volatile boolean running = true;
    private World map;

    private static final int framerate = 60;

    public Conway()
    {
        super("Conway's Game of Life" + " " + edition + " " + prefix + " " + version);
        map = new World(WIDTH, HEIGHT);
        setSize(WIDTH*SCALE + 2*BORDER, HEIGHT*SCALE + 4*BORDER);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().setBackground(Color.WHITE);
        setLocationRelativeTo(getParent());
        setResizable(false);
        setVisible(true);
    }

    public static void main(String[] args)
    {
        Conway con = new Conway();
        Thread thread = new Thread(con, "Conway");
        thread.start();
    }

    public void run()
    {
        map.start();
        long nanosPerTick = (long) (1000000000 / framerate);
        while(running)
        {
            tick();
            //System.out.println(getName() + " completed tick");

            try
            {
                Thread.sleep(nanosPerTick/1000000, (int) (nanosPerTick%1000000));
            }
            catch(InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }

    private void tick()
    {
        paint(getGraphics());
    }

    public void paint(Graphics g)
    {
        map.paint(g);
    }

    public void quit()
    {
        map.quit();
        running = false;
        System.out.println("All threads should be terminated...");
        System.exit(0);
    }
}

World:
Java:
import java.util.Random;
import java.awt.*;
import java.awt.image.BufferedImage;

public class World extends Thread
{
    private int width, height;
    private boolean[][] map, nextMap;

    public volatile boolean done = false;
    private volatile boolean running = true;

    private Random rnd;
    private BufferedImage bImage;

    public World(int x, int y)
    {
        super("World");
        width = x;
        height = y;
        map = new boolean[width][height];
        nextMap = new boolean[width][height];
        
        int amount = 0;
        amount = height%3 > 0 ? height/3 + 1 : height/3;
        
        rnd = new Random();
        if (Conway.RANDOMIZED)
        {
            for(int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    map[i][j] = rnd.nextBoolean();
                }
            }
        }

        bImage = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR); 
        Graphics2D g2 = bImage.createGraphics();
        g2.setColor(Color.RED);
        g2.fillRect(0 , 0, width, height);
    }

    public void run()
    {
        while(running)
        {
            tick();
            //System.out.println(getName() + " completed tick");
        }
    }

    private synchronized void tick()
    {
        while(done)
        {
            try
            {
                wait();
            }
            catch(InterruptedException e)
            {

            }
        }
        
        nextStep();
        for(int i = 0; i < width; i++)
        {
            for (int j = 0; j < height; j++)
            {
                if(map[i][j] != nextMap[i][j])
                {
                    map[i][j] = nextMap[i][j];
                    if(map[i][j])
                    {
                        bImage.setRGB(i, j, 0xff000000); //black
                    }
                    else
                    {
                        bImage.setRGB(i, j, 0xffff0000); //red
                    }
                }
            }
        }
       
        done = true;
        notify();
    }

    public synchronized void paint(Graphics g)
    {
        while(!done)
        {
            try
            {
                wait();
            }
            catch(InterruptedException e)
            {

            }
        }
        
        Graphics2D g2 = bImage.createGraphics();
        int tHeight = 0;
        g.drawImage(bImage, Conway.BORDER, 3*Conway.BORDER, width*Conway.SCALE, height*Conway.SCALE, null);
        
        done = false;
        notify();
    }

    public void quit()
    {
        running = false;
    }

    private int getAmountOfNeighbors(int x, int y)
    {
        int n = 0;
        if ((x < width) && (y < height) && (y >= 0) && (x >= 0))
        {
            for(int i =  x-1; i <= x+1; i++)
            {
                for(int j =  y-1; j <= y+1; j++)
                {
                    if(getState(i, j))
                    {
                        n++;
                    }
                }
            }
        }
        return n;
    }

    private boolean getState(int x, int y)
    {
        if ((x < width) && (y < height) && (y >= 0) && (x >= 0))
        {
            return map[x][y];
        }
        else if (Conway.RANDOMIZED)
        {
            return false;
        }
        else
        {
            return true;
        }
    }

    private boolean getNextState(int x, int y)
    {
        if ((x < width) && (y < height) && (y >= 0) && (x >= 0))
        {
            if(getState(x, y))
            {
                switch(getAmountOfNeighbors(x, y) - 1)
                {
                    case 2: case 3: {return true;}
                    default: {return false;}
                }
            }
            else
            {
                if(getAmountOfNeighbors(x, y) == 3)
                {
                    return true;
                }
                return false;
            }
        }
        return false;
    }

    private void nextStep()
    {
        for(int i = 0; i < width; i++)
        {
            for (int j = 0; j < height; j++)
            {
                nextMap[i][j] = getNextState(i, j);
            }
        }
    }
}
 
S

SlaterB

Gast
ok, wenn du schon so ein gut laufendes Programm hast, dann revidiere ich etwas meine Meinung

ich habe jetzt bisschen genauer nachgeschaut,
du musst zum einen die erzeugten Renderer auch als Thread starten,
damit kommen schon Unmengen an Ausgaben, wenn auch nicht unbedingt so schöne Bilder wie bisher,
aber das kann ja noch korrigiert werden

mit dem paint bin ich skeptisch, da würde ich einen direkten Aufruf paint(getGraphics())
(so sehr auch allgemein getGraphics() abzulehnen ist) noch eher vertrauen,
als dass bei repaint() auch wirklich immer ein paint-Aufruf kommt,
falls der irgendwann ausbleibt kann alles stocken?
na bisher läuft es wohl

paint(getGraphics())
kann anderseits noch schlimmer sein, falls das dein Thread macht und nebenbei auch noch Swing paint() aufruft,
dann sind dort evtl. zwei die gleichzeitig warten, beim notify wird (zufällig) der Swing-AWT-Thread als erster Warter aktiv und kommt raus während der Conway-Thread erst danach dran kommt und dann wegen geänderten done weiter warten muss,
aber ok, das scheint gar nicht mal schlimm zu sein, würde sonst ja beim nächsten Durchlauf auch wieder dort warten ;)
oder andersrum schlecht wenn der AWT-Thread warten muss?...
 
Zuletzt bearbeitet von einem Moderator:

blueJisCrap

Mitglied
Vielen Dank, das mit den zu startenden Threads habe ich in der Zwischenzeit auch schon bemerkt :oops:
Debug-Ausgaben haben das ziemlich schnell an's Licht gebracht.

Nun, nach der Korrektur einiger (mittel-)schwerer Fehler sieht es aber so aus, als wäre ich immer noch nicht am Ziel.
Das Bild bleibt rot, ohne schwarz, und das obwohl inzwischen alle Threads (theoretisch) so schön zusammenarbeiten.

Zu dem paint: Es ist immerhin eine zuverlässige Methode um sicherzustellen, dass neu gezeichnet wird. Wenn der Rest halbwegs das tut was er soll muss ich mir dafür auch noch was anderes einfallen lassen.

Am Code sollte sich - abgesehen davon, dass ich alles mit Debug-Output zugepflastert habe - nur in World was geändert haben, d.h. die aktuelle Version besteht aus Conway (s. vorheriger Post), RenderAssistant (s. erster Post) und der neuen Version von World:

Java:
import java.util.Random;
import java.awt.*;
import java.awt.image.BufferedImage;

public class World extends Thread
{
    private int width, height;
    private boolean[][] map, nextMap;

    public volatile boolean done = false;
    private volatile boolean running = true;

    private Random rnd;
    private RenderAssistant[] assistants;
    private BufferedImage bImage;

    public World(int x, int y)
    {
        super("World");
        width = x;
        height = y;
        map = new boolean[width][height];
        nextMap = new boolean[width][height];
        
        int amount = 0;
        int maxHeight = 300;
        amount = height%maxHeight > 0 ? height/maxHeight + 1 : height/maxHeight;
        assistants = new RenderAssistant[amount];
        int restHeight = height;
        for(int i = 0; i < amount; i++)
        {
            int tempHeight = restHeight/maxHeight > 1 ? maxHeight : restHeight;
            assistants[i] = new RenderAssistant(width, tempHeight, i+1);
            restHeight -= restHeight - tempHeight;
        }
        
        rnd = new Random();
        if (Conway.RANDOMIZED)
        {
            for(int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    map[i][j] = rnd.nextBoolean();
                }
            }
        }

        bImage = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR); 
        Graphics2D g2 = bImage.createGraphics();
        g2.setColor(Color.RED);
        g2.fillRect(0 , 0, width, height);
    }

    public void run()
    {
        for(RenderAssistant r : assistants)
        {
            r.start();
        }
        while(running)
        {
            System.out.println(getName() + " waiting for tick");
            tick();
            System.out.println(getName() + " completed tick");
        }
    }

    private synchronized void tick()
    {
        while(done)
        {
            try
            {
                wait();
            }
            catch(InterruptedException e)
            {

            }
        }
        
        nextStep();
        /*
        int tHeight = 0;
        for(RenderAssistant r : assistants)
        {
            int y = r.getY();
            boolean[][] temp = new boolean[width][y];
            for(int i = 0; i < width; i++)
            {
                for(int j = 0; j < y; j++)
                {
                    temp[i][j] = nextMap[i][j + tHeight];
                }
            }
            r.setWork(temp);
            System.out.println("Work for " + r.getName() + " SET");
            tHeight += y;
        } */
        
        Graphics2D g2 = bImage.createGraphics();
        int tHeight = 0;
        for(RenderAssistant r : assistants)
        {
            g2.drawImage(r.getResult(), 0, tHeight, null);
            System.out.println(getName() + " got result from " + r.getName());
            tHeight += r.getY();
        }
        
        map = nextMap;
       
        done = true;
        notify();
    }

    public synchronized void paint(Graphics g)
    {
        while(!done)
        {
            try
            {
                wait();
            }
            catch(InterruptedException e)
            {

            }
        }
        /*
        Graphics2D g2 = bImage.createGraphics();
        int tHeight = 0;
        for(RenderAssistant r : assistants)
        {
            g2.drawImage(r.getResult(), 0, 0, null);
            tHeight += r.getY();
        } */
        g.drawImage(bImage, Conway.BORDER, 3*Conway.BORDER, width*Conway.SCALE, height*Conway.SCALE, null);
        
        done = false;
        notify();
    }

    public void quit()
    {
        for(RenderAssistant r : assistants)
        {
            quit();
        }
        
        running = false;
    }

    private int getAmountOfNeighbors(int x, int y)
    {
        int n = 0;
        if ((x < width) && (y < height) && (y >= 0) && (x >= 0))
        {
            for(int i =  x-1; i <= x+1; i++)
            {
                for(int j =  y-1; j <= y+1; j++)
                {
                    if(getState(i, j))
                    {
                        n++;
                    }
                }
            }
        }
        return n;
    }

    private boolean getState(int x, int y)
    {
        if ((x < width) && (y < height) && (y >= 0) && (x >= 0))
        {
            return map[x][y];
        }
        else if (Conway.RANDOMIZED)
        {
            return false;
        }
        else
        {
            return true;
        }
    }

    private boolean getNextState(int x, int y)
    {
        if ((x < width) && (y < height) && (y >= 0) && (x >= 0))
        {
            if(getState(x, y))
            {
                switch(getAmountOfNeighbors(x, y) - 1)
                {
                    case 2: case 3: {return true;}
                    default: {return false;}
                }
            }
            else
            {
                if(getAmountOfNeighbors(x, y) == 3)
                {
                    return true;
                }
                return false;
            }
        }
        return false;
    }

    private void nextStep()
    {
        for(int i = 0; i < width; i++)
        {
            for (int j = 0; j < height; j++)
            {
                nextMap[i][j] = getNextState(i, j);
            }
        }
        System.out.println(getName() + " calculated next step");
        int tHeight = 0;
        for(RenderAssistant r : assistants)
        {
            int y = r.getY();
            boolean[][] temp = new boolean[width][y];
            for(int i = 0; i < width; i++)
            {
                for(int j = 0; j < y; j++)
                {
                    temp[i][j] = nextMap[i][j + tHeight];
                }
            }
            r.setWork(temp);
            System.out.println("Work for " + r.getName() + " assigned");
            tHeight += y;
        }
    }
}
Changelog (zur Übersicht):
  • Zuteilung der Threads zum Zeichnen korrigiert
  • Einzelne Aufgaben innerhalb der Klasse verschoben
  • Threads werden gestartet

btw dieses Forum könnte BB-Codes für Spoiler vertragen ;-)
 

blueJisCrap

Mitglied
Oh, ich hatte damit gerechnet, dass solche Standardfunktionen auch im Editor aufgeführt sind, aber danke für den Hinweis ;-)

Um unnötige Versuche mein nettes kleines Programm zu tunen vorwegzunehmen:
Kann ich überhaupt noch großartige Leistungssteigerungen erwarten?
Wenn ja, wo ist (womöglich) das Bottleneck?

Bitte, detaillierte Benchmarks wären zuviel verlangt, Einschätzungen würden mir völlig genügen.
 
S

SlaterB

Gast
> restHeight -= restHeight - tempHeight;
ist falsch

ein großer Fehler ist im Moment
> map = nextMap;
ohne eine neue nextMap anzulegen, damit zeigen beide Variablen auf dieselbe Map, deshalb funktionieren die Updates nicht mehr,
mit
> nextMap = new boolean[width][height];
gehts wieder, allerdings fördert das sicher nicht die Geschwindigkeit, dann wohl lieber wieder kopieren,
obwohl das auch langsam sein kann,

vielleicht ist es performant, kompliziert mit mehr Zuständen zu arbeiten,
das Programm wechselt generell zwischen zwei Schaltungen A und B, kann ein boolean sein,

Zustände pro Feld 00, 01, 10, 11 (als 4 ints, 0, 1, 10, 11):
Zustand 00, aus Sicht A: Feld ist aktuell (Zustand A) leer, bleibt es auch im nächsten (B)
Zustand 00, aus Sicht B: Feld ist aktuell (B) leer, bleibt es auch im nächsten (A)
Zustand 01, aus Sicht A: Feld ist aktuell (A) leer, wird dann aber belegt im nächsten (B)
Zustand 01, aus Sicht B: Feld ist aktuell (B) belegt, wird dann aber leer im nächsten (A)
usw.

also die erste Ziffer beschreibt Sicht A, die andere Sicht B,
beim Zeichen bzw. in getState()-Methode beides prüfen:
boolean gefüllt = (A && (10 || 11)) || (B && (01 || 11));

beim Ändern eben aufpassen dass aktuell nichts kaputt gemacht wird,
wenn gerade A ist und das Feld aktuell leer ist (00 oder 01, zweite Stelle egal, war der vorherige Stand),
und im nächsten Schritt gefüllt werden soll, dann auf 01 setzen,
so bleibt es aktuell bei 0, paint bzw. weitere Berechnung wird nicht gestört wenn vor dem nächsten Umschalten noch liest,
(sogar falls paint parallel läuft, Trennung evtl. nicht mehr nötig),
und wann immer B drankommt ist dann die neue Information gleich vorhanden,
wichtig: anderenfalls auf 00 setzen, nicht vergessen, es muss immer gesetzt werden

(edit: zwei boolean-2D-Arrays, zwischen denen gewechselt sind, gehen natürlich genauso, unnötig aufwendig..)

wer weiß ob durch diese Komplexität bei den Abfragen und Wechsel auf int statt boolean das ganze nicht langsamer wird..,
dass das wait/notify und manche Threads evtl. wegfallen könnte schon eher günstig sein, allerdings ist das nicht direkt davon abhängig,

wichtiger Punkt du beachten: falls du nicht gerade mit mehreren CPUs arbeiten kannst, was ich bei Java-Threads bisher immer eher bezweifle,
so gilt grundsätzlich dass mit Threads nichts schneller wird,
jeder Befehl muss irgendwann ausgeführt werden, es kommen nicht zwei gleichzeitig dran (außer vielleicht mit mehreren CPUs)

das Umschalten der Threads ist sogar noch ein immenser Arbeitsaufwand,
der in solch trivialen Fällen selbst bei theoretischer Mehr-CPU-Unterstützung allen Gewinn zunichte machen könnte
(Vermutung, wobei natürlich bei einer CPU pro Thread vielleicht gar nicht mehr umgeschaltet wird,
Umschalten heißt ja gerade mehrere Threads im Wechsel auf einer CPU..)

in erster Linie (in den einfachen Programmen hier im Forum) sind Threads eine Konkrollstruktur,
einfache Formulierung verschiedene Aktionen in eigenen Bereichen,
erkauft mit eher langsamerer Ausführung statt schnellerer,

zwischen dem AWT-Thread und deiner Arbeit umzuschalten ist so ein Beispiel, ohne Thread wäre es schwierig das alles abzustimmmen,
aber ich glaube nicht dass dein RendererAssistand irgendwas bringt, sobald einer von denen etwas macht müssen die anderen Threads warten.. (falls nicht mehrere CPUs),
ein Thread parallel zur GUI, der alles macht, reicht in der Regel

falls du auf das komplizierte neue Array umsteigst, ist wichtig, dass nicht zwischen A und B umgeschaltet wird solange das Array in einem Durchgang bearbeitet wird oder solange gerade gepaintet wird,
für wait/notify ist durchaus noch Bedarf

interessantes Programm
 
Zuletzt bearbeitet von einem Moderator:

Marco13

Top Contributor
wichtiger Punkt du beachten: falls du nicht gerade mit mehreren CPUs arbeiten kannst, was ich bei Java-Threads bisher immer eher bezweifle,
so gilt grundsätzlich dass mit Threads nichts schneller wird,
jeder Befehl muss irgendwann ausgeführt werden, es kommen nicht zwei gleichzeitig dran (außer vielleicht mit mehreren CPUs)

Der Thread hier liegt auch schon in meiner TODO-Liste, aber dazu ganz kurz: Praktisch jeder Rechner, den man heute kauft, hat mindestens 4 physische (und mit Hyperthreading dann 8 virtuelle) Cores - und diese Anzahl wird sich alle 18 Monate verdoppeln. Gerade bei so etwas "emarassingly parallelen" wie dem Conway können sich mehrere Threads auf jeden Fall lohnen! (Genau deswegen wollte ich anläßlich dieses Threads mal so einen Parallelen Conway implementieren - schon um zu seheh, wie viel man da tatsächlich rausholen kann :) )
 
S

SlaterB

Gast
vielleicht gehts ja wirklich, stelle ich mir nur schwer vor auch mit gemeinsamen Variablen,
separate Programme, die über Sockets kommunizieren, das passt eher in mein Bild

gibts irgendwo ein Standardbeispiel zu kopieren mit Ausgabe direkt hintereinander
"Berechnung X in einem Thread = 5,000 sec"
"Berechnung X in zwei Threads = 2,600 sec"
? ;)
wobei Benchmarks ja kritisch gesehen werden, aber wenn Threads was bringen sollen, muss das ja möglich sein
 
S

SlaterB

Gast
oder selbst gemacht:
Java:
public class Test
{

    public static void main(String[] args)
        throws InterruptedException
    {
        test(1);
        test(2);
    }

    static void test(int c)
        throws InterruptedException
    {
        long time = System.currentTimeMillis();
        int n = 100000000;
        int k = n / c;
        List<Run> list = new ArrayList<Run>();
        for (int i = 0; i < c; i++)
        {
            Run r = new Run();
            r.min = i * k;
            r.max = (i + 1) * k;
            r.start();
            list.add(r);
        }

        for (Run r : list)
        {
            r.join();
        }


        BigDecimal sum = BigDecimal.ZERO;
        for (Run r : list)
        {
            sum = sum.add(r.sum);
        }
        time = System.currentTimeMillis() - time;
        System.out.println(time + ", for c: " + c + " - " + sum);
    }
}


class Run
    extends Thread
{

    BigDecimal sum = BigDecimal.ZERO;
    int min;
    int max;

    public void run()
    {
        for (int i = min; i < max; i++)
        {
            sum = sum.add(new BigDecimal(i));
        }
    }

}
Ausgabe:
Code:
8173, for c: 1 - 4999999950000000
9530, for c: 2 - 4999999950000000
in beiden Fällen 8-10 sec,
keine Verbesserung durch zwei Threads, mag an meinem PC/ alter Java-Version liegen,
mag im Programm noch zu ändern sein, geht es irgendwo?

hoffe nicht zu Offtopic wenn es hier um Performance geht
 

faetzminator

Gesperrter Benutzer
Irgendwie witzig:
Code:
procs: 4
7188, for c: 1 - 4999999950000000
3828, for c: 2 - 4999999950000000
3578, for c: 3 - 4999999850000001
4437, for c: 4 - 4999999950000000
5047, for c: 5 - 4999999950000000
2266, for c: 6 - 4999999550000010
 
S

SlaterB

Gast
die Fehler in der Summe sind nicht schlimm, liegen an meiner zu einfachen Aufteilung,
nun gut, dann werde ich von nun an wohl nicht ganz so doll auf Threads schimpfen
 

Marco13

Top Contributor
Ja, ich hatte dazu schon ein paar Tests gemacht, es ging da um Matrixmultiplikationen und Permutationen, oder auch für die Berechnungen in jocl.org - Cloth simulation demo . Es lohnt sich wirklich, und ist mit Dingen wie ExecutorService etc. auch leicht zu verwenden. Ein KSKB müßte ich auch erst basteln, aber vielleicht komme ich ja in den nächsten Tagen mal dazu, einen Multithreaded Conway zu implementieren.
 

blueJisCrap

Mitglied
Um mich auch mal wieder zu Wort zu melden:

Ich hab das ganze jetzt mit zwei abwechselnd verwendeten boolean Arrays zum Laufen gebracht (wie es mir auch an anderer Stelle schonmal vorgeschlagen wurde) und ein paar Tests durchgeführt:
So erreiche ich doch mit der neuen Version gegenüber der alten bei 1800x900 eine Geschwindigkeitssteigerung von sage und schreibe -43% (CPU: 4x 3,4 GHz).
Im Ernst, so wie es jetzt umgesetzt ist hat's der Aufwand überhaupt nicht gebracht.

Entweder ich habe an der falschen Stelle versucht zu optimieren oder es ist einfach nicht mehr herauszuholen. Oder aber ich habe an der richtigen Stelle gekratzt, bloß meine Herangehensweise war von Grund auf verkehrt?
 
G

Guest2

Gast
Moin,

als KSKB würde ich das in etwa so runterschreiben:

Java:
package jf.Conway;

import java.awt.Canvas;
import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import javax.swing.JFrame;

public class Conway extends ComponentAdapter implements Runnable {

    private static final int                   COLOR    = 0xFF5533;

    private static final GraphicsConfiguration G_CONFIG = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();

    private final ExecutorService              pool     = Executors.newCachedThreadPool();
    private final Future<?>[]                  futures  = new Future[2 * Runtime.getRuntime().availableProcessors()];

    private final Random                       random   = new Random(System.nanoTime());

    private final JFrame                       frame    = new JFrame();
    private final Canvas                       canvas   = new Canvas();
    private final BufferStrategy               bs;

    private long                               time;

    private int                                width;
    private int                                height;
    private int                                blockSize;

    private BufferedImage                      frontImage;
    private BufferedImage                      backImage;

    private int[]                              frontData;
    private int[]                              backData;


    public Conway() {

        canvas.addComponentListener(this);

        frame.setSize(1800, 900);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(canvas);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        canvas.setIgnoreRepaint(true);
        canvas.createBufferStrategy(2);
        bs = canvas.getBufferStrategy();

    }


    @Override
    public void componentResized(final ComponentEvent e) {

        width = canvas.getWidth();
        height = canvas.getHeight();

        blockSize = (int) Math.ceil((double) height / futures.length);

        frontImage = G_CONFIG.createCompatibleImage(canvas.getWidth(), canvas.getHeight());
        backImage = G_CONFIG.createCompatibleImage(canvas.getWidth(), canvas.getHeight());

        frontData = ((DataBufferInt) (frontImage.getRaster().getDataBuffer())).getData();
        backData = ((DataBufferInt) (backImage.getRaster().getDataBuffer())).getData();

        for (int i = 0; i < width * height; i++)
            if (random.nextInt(100) > 85)
                frontData[i] = backData[i] = COLOR;

    }


    private void rules(final int cell, final int sum) {

        if (frontData[cell] == 0) {

            if (sum == 3)
                backData[cell] = COLOR;

            else
                backData[cell] = 0;

        } else if (sum == 2 || sum == 3)
            backData[cell] = COLOR;

        else
            backData[cell] = 0;

    }


    private Runnable block(final int start) {

        return new Runnable() {

            @Override
            public void run() {

                for (int y = start * blockSize; (y < (1 + start) * blockSize) && (y < height); y += 2)
                    for (int x = 0; x < width; x += 2) {

                        int sum11 = 0;
                        int sum12 = 0;
                        int sum21 = 0;
                        int sum22 = 0;

                        final int row1 = ((y - 1 + height) % height) * width;
                        final int row2 = y * width;
                        final int row3 = ((y + 1) % height) * width;
                        final int row4 = ((y + 2) % height) * width;

                        final int col1 = ((x - 1 + width) % width);
                        final int col2 = x;
                        final int col3 = ((x + 1) % width);
                        final int col4 = ((x + 2) % width);

                        final int e11 = frontData[row1 + col1];
                        final int e12 = frontData[row1 + col2];
                        final int e13 = frontData[row1 + col3];
                        final int e14 = frontData[row1 + col4];
                        final int e21 = frontData[row2 + col1];
                        final int e22 = frontData[row2 + col2];
                        final int e23 = frontData[row2 + col3];
                        final int e24 = frontData[row2 + col4];
                        final int e31 = frontData[row3 + col1];
                        final int e32 = frontData[row3 + col2];
                        final int e33 = frontData[row3 + col3];
                        final int e34 = frontData[row3 + col4];
                        final int e41 = frontData[row4 + col1];
                        final int e42 = frontData[row4 + col2];
                        final int e43 = frontData[row4 + col3];
                        final int e44 = frontData[row4 + col4];

                        sum11 += e11;
                        sum11 += e12;
                        sum11 += e13;
                        sum11 += e21;
                        sum11 += e23;
                        sum11 += e31;
                        sum11 += e32;
                        sum11 += e33;

                        sum12 += e12;
                        sum12 += e13;
                        sum12 += e14;
                        sum12 += e22;
                        sum12 += e24;
                        sum12 += e32;
                        sum12 += e33;
                        sum12 += e34;

                        sum21 += e21;
                        sum21 += e22;
                        sum21 += e23;
                        sum21 += e31;
                        sum21 += e33;
                        sum21 += e41;
                        sum21 += e42;
                        sum21 += e43;

                        sum22 += e22;
                        sum22 += e23;
                        sum22 += e24;
                        sum22 += e32;
                        sum22 += e34;
                        sum22 += e42;
                        sum22 += e43;
                        sum22 += e44;

                        sum11 /= COLOR;
                        sum12 /= COLOR;
                        sum21 /= COLOR;
                        sum22 /= COLOR;

                        rules(row2 + col2, sum11);
                        rules(row2 + col3, sum12);
                        rules(row3 + col2, sum21);
                        rules(row3 + col3, sum22);

                    }
            }
        };

    }


    private void swap() {

        final BufferedImage dummyImage = frontImage;
        final int[] dummyData = frontData;

        frontImage = backImage;
        frontData = backData;

        backImage = dummyImage;
        backData = dummyData;

    }


    private void step() {

        for (int block = 0; block < futures.length; block++)
            futures[block] = pool.submit(block(block));

    }


    private void sync() {

        for (final Future<?> future : futures)

            try {

                future.get();

            } catch (final InterruptedException e) {

                e.printStackTrace();

            } catch (final ExecutionException e) {

                // ArrayIndexOutOfBoundsException: resize ignore it now

            }

    }


    private void draw() {

        Graphics2D g = null;
        try {

            g = (Graphics2D) bs.getDrawGraphics();

            g.drawImage(frontImage, 0, 0, null);

            if (!bs.contentsLost())
                bs.show();

        } catch (final IllegalStateException e) {

        } finally {

            if (g != null)
                g.dispose();

        }

        Toolkit.getDefaultToolkit().sync();

    }


    @Override
    public void run() {

        int frame = 0;

        while (true) {

            if (frame++ > 100) {

                System.out.println("FPS: " + frame / ((-(time - (time = System.nanoTime()))) / 1000000000.0));

                frame = 0;

            }


            swap();
            step();
            draw();
            sync();

            Thread.yield();

        }

    }


    public static void main(final String[] args) {

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {

                final Conway conway = new Conway();
                conway.pool.execute(conway);

            }
        });


    }


}

Damit läuft das hier, in den geforderten 1800x900, mit etwa 100fps (auf einer 64Bit VM die 32Bit mit -server ist etwa 10fps langsamer). Das ist aber mit Sicherheit auch nicht das Ende der Fahnenstange und man könnte es mit Sicherheit auch wesentlich sauberer implementieren.

(Um so mehr bin ich gespannt, falls Marco sein Multithreaded Conway präsentiert ;))

Viele Grüße,
Fancy
 

Marco13

Top Contributor
Na toll ... da bastelt man, und denkt dann "Joa, mehr als 60 FPS, passt" - und schaut dann ins Forum, um sehen zu müssen, dass man mit 100 FPS konkurrieren muss :mad: ;)

Hab' jetzt dann mal auf die schnelle mal den Canvas von dir geklaut, und auch den Array aus dem BufferedImage direkt in meine World-Klasse gepresst - das ist dann nochmal eine etwas deutlichere Beschleunigung gebracht, als ich vermutet hätte (hier ca. 75 FPS mit JPanel und manuellem Kopieren, und ca. 100 FPS mit den Canvas und halbherzigem Datensharen - die Verwendung des Canvas ist im Moment auskommentiert, [c]//useCanvas = true;[/c] reinmachen um umzuschalten). Das unmanaged-werden des BufferedImages trägt auch wieder mehr dazu bei, als ich vermutet hatte.

Ansonsten gibt es mal wieder den Trade-off zwischen Abstraktion/Allgemeingültigkeit und Performance: Natürlich hatte ich zuerst ein "interface World", wo man nur mit get/set zugreifen konnte, und IMMER Bounds-Checks gemacht wurden - aber es hat sich dann schrittweise der Verwendung des rohen int-Arrays angenähert, um noch mehr FPS rauszuholen. Die Daten tatsächlich zwischen dem Modell (der World) und der View (dem BufferedImage) zu sharen hatte ich dann aber doch nicht über mein MVC-Herz gebracht - auch wenn das Kopieren Zeit kostet ;)

Wie auch immer, hier mal alles als RIEEESIGES "K"SKB zusammengeklatscht:
Java:
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferInt;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;

public class ConwayMain
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }
    
    private static void createAndShowGUI()
    {
        JFrame frame = new JFrame("Yet another Conway");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        ConwayComputer conwayComputer = new ConwayComputer();
        ConwayGUI conwayGUI = new ConwayGUI(conwayComputer);
        
        frame.getContentPane().add(conwayGUI);
        frame.setSize(1850, 950);
        frame.setVisible(true);
    }
    
}


class ConwayComputer
{
    private static final Random random = new Random(0);
    
    private int numThreads;
    private World world;
    private World newWorld;
    private ExecutorService executorService;
    
    public ConwayComputer()
    {
    }
    
    public void init(int sizeX, int sizeY, int numThreads) 
    {
        this.numThreads = numThreads;
        world = new World(sizeX, sizeY);
        newWorld = world.copy();
        
        executorService = Executors.newFixedThreadPool(numThreads);
    }
    
    public void randomize()
    {
        if (world == null)
        {
            return;
        }
        for (int y=0; y<world.getSizeY(); y++)
        {
            for (int x=0; x<world.getSizeX(); x++)
            {
                int value = States.DEAD;
                if (random.nextBoolean())
                {
                    value = States.ALIVE;
                }
                world.set(x, y, value);
            }
        }
    }
    
    public World getWorld()
    {
        return world;
    }
    
    public void executeStep()
    {
        if (world == null)
        {
            return;
        }
        List<Callable<Object>> callables = new ArrayList<Callable<Object>>();
        int chunkSize = (int)Math.ceil((double)world.getSizeY()/numThreads);
        for (int i=0; i<numThreads; i++)
        {
            final int minY = 1+i*chunkSize;
            final int maxY = Math.min(world.getSizeY()-1, minY + chunkSize);
            Callable<Object> callable = new Callable<Object>()
            {
                @Override
                public Object call() throws Exception
                {
                    computeInner(1, minY, world.getSizeX()-1, maxY);
                    return null;
                }
            };
            callables.add(callable);
        }
        Callable<Object> callable = new Callable<Object>()
        {
            @Override
            public Object call() throws Exception
            {
                computeBorder();
                return null;
            }
        };
        callables.add(callable);
        long before = System.nanoTime();
        try
        {
            executorService.invokeAll(callables);
        }
        catch (InterruptedException e)
        {
            Thread.currentThread().interrupt();
        }
        long after = System.nanoTime();
        //System.out.println("Step took "+((after-before)/1e6)+" ms for "+world.getSizeX()+"*"+world.getSizeY());
        World oldWorld = world;
        world = newWorld;
        newWorld = oldWorld;
    }
    
    private void computeInner(int minX, int minY, int maxX, int maxY)
    {
        int array[] = newWorld.getArray();
        int w = world.getSizeX();
        for (int y=minY; y<maxY; y++)
        {
            for (int x=minX; x<maxX; x++)
            {
                array[x+y*w] = getNextStateInner(x, y);
            }
        }
    }
    
    private int getNextStateInner(int x, int y)
    {
        int array[] = world.getArray();
        int w = world.getSizeX();

        int aliveNeighbors = 0;

        int index = (y - 1) * w + x - 1;
        if (array[index++] == States.ALIVE) aliveNeighbors++;
        if (array[index++] == States.ALIVE) aliveNeighbors++;
        if (array[index++] == States.ALIVE) aliveNeighbors++;

        index += w - 3;
        if (array[index++] == States.ALIVE) aliveNeighbors++;
        int previousState = array[index++];
        if (array[index++] == States.ALIVE) aliveNeighbors++;

        index += w - 3;
        if (array[index++] == States.ALIVE) aliveNeighbors++;
        if (array[index++] == States.ALIVE) aliveNeighbors++;
        if (array[index++] == States.ALIVE) aliveNeighbors++;

        return stateFor(previousState, aliveNeighbors);
    }    
    

    private void computeBorder()
    {
        int array[] = newWorld.getArray();
        int w = world.getSizeX();
        int h = world.getSizeY();
        for (int x=0; x<w; x++)
        {
            array[x] = getNextState(x, 0);
            array[x+(h-1)*w] = getNextState(x, h-1);
        }
        for (int y=0; y<h; y++)
        {
            array[y*w] = getNextState(0, y);
            array[w-1+y*w] = getNextState(w-1, y);
        }
    }
    
    private int getNextState(int x, int y)
    {
        int aliveNeighbors = 0;
        if (world.get(x-1, y-1) == States.ALIVE) aliveNeighbors++;
        if (world.get(x  , y-1) == States.ALIVE) aliveNeighbors++;
        if (world.get(x+1, y-1) == States.ALIVE) aliveNeighbors++;

        if (world.get(x-1, y  ) == States.ALIVE) aliveNeighbors++;
        int previousState = world.get(x, y);
        if (world.get(x+1, y  ) == States.ALIVE) aliveNeighbors++;

        if (world.get(x-1, y+1) == States.ALIVE) aliveNeighbors++;
        if (world.get(x  , y+1) == States.ALIVE) aliveNeighbors++;
        if (world.get(x+1, y+1) == States.ALIVE) aliveNeighbors++;
        
        return stateFor(previousState, aliveNeighbors);
    }
    
    private static int stateFor(int previousState, int aliveNeighbors)
    {
        // As from Wikipedia:
        //Any live cell with fewer than two live neighbors dies
        //Any live cell with two or three live neighbors lives on
        //Any live cell with more than three live neighbors dies
        //Any dead cell with exactly three live neighbors becomes a live cell
        if (previousState == States.ALIVE)
        {
            if (aliveNeighbors == 2 || aliveNeighbors == 3)
            {
                return States.ALIVE; 
            }
        }
        else
        {
            if (aliveNeighbors == 3)
            {
                return States.ALIVE; 
            }
        }
        return States.DEAD;
    }
    
    
}


class ConwayGUI extends JPanel
{
    private static final long serialVersionUID = 944940378249119427L;

    private ConwayComputer conwayComputer;
    private WorldPainter worldPainter;
    private ConwayRunner conwayRunner;
    
    public ConwayGUI(ConwayComputer conwayComputer)
    {
        super(new BorderLayout());
        this.conwayComputer = conwayComputer;
        
        boolean useCanvas = false;
        //useCanvas = true;
        if (useCanvas)
        {
            WorldCanvas worldCanvas = new WorldCanvas();
            add(worldCanvas, BorderLayout.CENTER);
            worldPainter = worldCanvas;
        }
        else
        {
            WorldPanel worldPanel = new WorldPanel();
            add(worldPanel, BorderLayout.CENTER);
            worldPainter = worldPanel;
        }
        
        JPanel controlPanel = createControlPanel();
        add(controlPanel, BorderLayout.SOUTH);
        
        conwayRunner = new ConwayRunner(conwayComputer, worldPainter);
    }
    
    private JPanel createControlPanel()
    {
        JPanel controlPanel = new JPanel(new GridLayout(1,0));
        
        controlPanel.add(new JLabel("Size X"));
        final JTextField textFieldSizeX = new JTextField("1800");
        controlPanel.add(textFieldSizeX);

        controlPanel.add(new JLabel("Size Y"));
        final JTextField textFieldSizeY = new JTextField("900");
        controlPanel.add(textFieldSizeY);

        controlPanel.add(new JLabel("Threads"));
        final JTextField textFieldThreads = new JTextField("4");
        controlPanel.add(textFieldThreads);
        
        JButton initButton = new JButton("Init");
        initButton.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                int sizeX = Integer.parseInt(textFieldSizeX.getText());
                int sizeY = Integer.parseInt(textFieldSizeY.getText());
                int threads = Integer.parseInt(textFieldThreads.getText());
                conwayComputer.init(sizeX, sizeY, threads);
                worldPainter.setWorld(conwayComputer.getWorld());
                worldPainter.updateImage();
            }
        });
        controlPanel.add(initButton);

        JButton randomizeButton = new JButton("Randomize");
        randomizeButton.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                conwayComputer.randomize();
                worldPainter.setWorld(conwayComputer.getWorld());
                worldPainter.updateImage();
            }
        });
        controlPanel.add(randomizeButton);
        
        final JToggleButton runButton = new JToggleButton("Run");
        runButton.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                conwayRunner.setRunning(runButton.isSelected());
            }
        });
        controlPanel.add(runButton);
        
        
        return controlPanel;
    }
    
}

class ConwayRunner
{
    private ConwayComputer conwayComputer;
    private WorldPainter worldPainter;
    private boolean running = false;
    
    public ConwayRunner(ConwayComputer conwayComputer, WorldPainter worldPainter)
    {
        this.conwayComputer = conwayComputer;
        this.worldPainter = worldPainter;
        
        Thread thread = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                doRun();
            }
        });
        thread.start();
    }
    
    public synchronized void setRunning(boolean running)
    {
        this.running = running;
        notify();
    }
    
    private void doRun()
    {
        while (true)
        {
            while (!running)
            {
                synchronized (this)
                {
                    try
                    {
                        wait();
                    }
                    catch (InterruptedException e)
                    {
                        Thread.currentThread().interrupt();
                        return;
                    }
                }
            }
            while (running)
            {
                conwayComputer.executeStep();
                worldPainter.setWorld(conwayComputer.getWorld());
                worldPainter.updateImage();
            }
        }
    }
    
}


class States
{
    public static final int ALIVE = 0xFF00FF00;
    public static final int DEAD = 0xFF000000;
}

class World
{
    private final int sizeX;
    private final int sizeY;
    private int array[];
    
    public World(int sizeX, int sizeY)
    {
        this.sizeX = sizeX;
        this.sizeY = sizeY;
        this.array = new int[sizeX*sizeY];
        Arrays.fill(array, States.DEAD);
    }
    
    public World copy()
    {
        World result = new World(sizeX, sizeY);
        result.array = array.clone();
        return result;
    }
    
    public int[] getArray()
    {
        return array;
    }

    public void setArray(int array[])
    {
        this.array = array;
    }

    private int warp(int value, int size)
    {
        if (value < 0) 
        {
            value += size;
        }
        if (value >= size) 
        {
            value -= size;
        }
        return value;
    }
    
    public int get(int x, int y)
    {
        x = warp(x, sizeX);
        y = warp(y, sizeY);
        return array[x+y*sizeX];
    }

    public void set(int x, int y, int value)
    {
        x = warp(x, sizeX);
        y = warp(y, sizeY);
        array[x+y*sizeX] = value;
    }

    public int getSizeX()
    {
        return sizeX;
    }

    public int getSizeY()
    {
        return sizeY;
    }

}



interface WorldPainter
{
    void setWorld(World world);
    void updateImage();
}


class WorldPanel extends JPanel implements WorldPainter
{
    private static final long serialVersionUID = -8242549491078094398L;
    
    private BufferedImage bufferedImage;
    private int imageData[];
    private World world;
    private int frameCounter = 0;
    private long time = 0;
    
    public WorldPanel()
    {
        MouseAdapter mouseAdapter = new MouseAdapter()
        {
            @Override
            public void mouseDragged(MouseEvent event)
            {
                enableCell(event.getX(), event.getY());
            }

            @Override
            public void mousePressed(MouseEvent event)
            {
                toggleCell(event.getX(), event.getY());
            }

        };
        addMouseListener(mouseAdapter);
        addMouseMotionListener(mouseAdapter);
    }
    
    @Override
    public void setWorld(World world)
    {
        this.world = world;
    }
    
    @Override
    public void updateImage()
    {
        if (world == null)
        {
            return;
        }
        if (bufferedImage == null || 
            bufferedImage.getWidth() != world.getSizeX() || 
            bufferedImage.getHeight() != world.getSizeY())
        {
            bufferedImage = new BufferedImage(
                world.getSizeX(), world.getSizeY(), 
                BufferedImage.TYPE_INT_ARGB);
            DataBuffer dataBuffer = bufferedImage.getRaster().getDataBuffer();
            DataBufferInt dataBufferInt = (DataBufferInt)dataBuffer;
            imageData = dataBufferInt.getData();
        }
        int array[] = world.getArray();
        System.arraycopy(array, 0, imageData, 0, array.length);
        repaint();
    }
    
    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        if (bufferedImage != null)
        {
            frameCounter++;
            long passed = System.nanoTime() - time;
            if (passed > 1000000000)
            {
                System.out.println("FPS: "+frameCounter);
                time = System.nanoTime();
                frameCounter = 0;
            }
            g.drawImage(bufferedImage, 0, 0, null);
        }
    }
    
    
    private void enableCell(int vx, int vy)
    {
        if (world == null)
        {
            return;
        }
        float scaleX = (float)getWidth()/world.getSizeX();
        float scaleY = (float)getHeight()/world.getSizeY();
        int wx = (int)(vx / scaleX);
        int wy = (int)(vy / scaleY);
        world.set(wx, wy, States.ALIVE);
        updateImage();
    }
    private void toggleCell(int vx, int vy)
    {
        if (world == null)
        {
            return;
        }
        float scaleX = (float)getWidth()/world.getSizeX();
        float scaleY = (float)getHeight()/world.getSizeY();
        int wx = (int)(vx / scaleX);
        int wy = (int)(vy / scaleY);
        int oldState = world.get(wx, wy);
        if (oldState == States.ALIVE)
        {
            world.set(wx, wy, States.DEAD);
        }
        else
        {
            world.set(wx, wy, States.ALIVE);
        }
        updateImage();
    }
    

}



class WorldCanvas extends Canvas implements WorldPainter
{
    private static final long serialVersionUID = -8242549491078094398L;
    
    private static final GraphicsConfiguration GRAPHICS_CONFIGURATION = 
        GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
    private BufferedImage bufferedImage;
    private BufferStrategy bufferStrategy;
    private int imageData[];
    private World world;
    private int frameCounter = 0;
    private long time = 0;
    
    public WorldCanvas()
    {
        setIgnoreRepaint(true);
    }
    
    @Override
    public void setWorld(World world)
    {
        this.world = world;
    }
    
    @Override
    public void updateImage()
    {
        if (world == null)
        {
            return;
        }
        if (bufferStrategy == null)
        {
            createBufferStrategy(2);
            bufferStrategy = getBufferStrategy();
        }
        if (bufferedImage == null || 
            bufferedImage.getWidth() != world.getSizeX() || 
            bufferedImage.getHeight() != world.getSizeY())
        {
            bufferedImage = GRAPHICS_CONFIGURATION.createCompatibleImage(
                world.getSizeX(), world.getSizeY());
            imageData = ((DataBufferInt) (bufferedImage.getRaster().getDataBuffer())).getData();

            int array[] = world.getArray();
            System.arraycopy(array, 0, imageData, 0, array.length);
            world.setArray(imageData);
        }
        draw();
    }

    private void draw()
    {
        Graphics2D g = null;
        try
        {
            g = (Graphics2D)bufferStrategy.getDrawGraphics();
            g.drawImage(bufferedImage, 0, 0, null);
            if (!bufferStrategy.contentsLost())
            {
                bufferStrategy.show();
            }

            frameCounter++;
            long passed = System.nanoTime() - time;
            if (passed > 1000000000)
            {
                System.out.println("FPS: "+frameCounter);
                time = System.nanoTime();
                frameCounter = 0;
            }
            
        }
        catch (final IllegalStateException e)
        {
        }
        finally
        {
            if (g != null)
            {
                g.dispose();
            }
        }
        Toolkit.getDefaultToolkit().sync();
    }
    

}
 

blueJisCrap

Mitglied
Hat euch schonmal jemand gesagt, dass ihr wahnsinnig seid?
Ich werde mich morgen, oder vlt. auch erst übermorgen genauer mit euren Umsetzungen auseinandersetzen können.

Was ich aber bei euch beiden vermisse, das ist der zweite Modus den meins bereitstellt, d.h. leeres Startfeld und 'lebender' Rand. Das ergibt mMn. viel schönere Muster ;)
Leistung hin oder her, ein FPS-Cap ist auch nicht schlecht, v.a. wenn man die Entwicklung beobachten können möchte.

Bisher habe ich beide Versionen getestet und die Lösung von unserem Gast überflogen - Marco sei mir nicht böse aber bei dir hab ich's erstmal bei einem Durchscrollen belassen.

Übrigens läuft auf meinem Rechner die Version von Marco deutlich schneller: 100FPS vs. 70FPS bei Standardeinstellungen.

Noch 2 Fragen in den Raum:
1. Wie lange habt ihr daran gesessen?
2. Gibt es einen grundlegenden Unterschied der eure Lösung so viel schneller macht oder ist es das Gesamtbild?

Aber alles in Allem, und nach dem was ich bis jetzt darüber sagen kann sieht das sehr beeindruckend aus und ich denke ich werde wohl meine Herangehensweisen im Allgemeinen gründlich überdenken müssen. Auf der anderen Seite ist euch die API auch viel geläufiger als mir und mit einfachem Schulunterricht (3 Jahre Java im Informatikunterricht) kommt man einfach nicht auf Höchstleistungen.
 

Marco13

Top Contributor
Das mit dem "Modus" hab' ich nicht ganz kapiert - geht es da nur um den Anfangszustand? Statt des "Randomize"-Buttons könnte man natürlich auch einen "Make the Border Alive"-Button einfügen. Genauso wie einen Einzelschritt-Button, der im Prinzip das einmal ausführen müßte, was der Runner eben in einem eigenen Thread so schnell wie möglich macht. Das Beispiel würde übrigens deutlich übersichtlicher, wenn man es in einzelne Dateien packen würde :oops: aber für's Forum ist so ein einzelner Copy&Paste-Block IMHO praktischer. Die benötigte Zeit...? Naja, ca. von 19:00 bis zum posten, einschließlich ein bißchen rumprobieren (der besagte Weg vom abstrakten zum performanten), und einer kleinen "Grml-da-hat-jemand-was-schnelleres-gepostet"-Verzögerung als ich eigentlich die erste Verison posten wollte ;) Wo der gravierende Unterschied zu deiner Version liegt... da müßte ich mir die auch erstmal genauer ansehen... aber... da... "hab ich's erstmal bei einem Durchscrollen belassen" ;) (Naja, einbißchen gelesen schon, aber wohl noch nicht detailliert genug)
 
G

Guest2

Gast
Gebraucht habe ich nicht ganz so lange wie Marco. Marco hat sich aber auch bemüht gewisse Softwaredesignprinzipien (soweit eben noch sinnvoll) aufrechtzuerhalten, während ich die offensichtlich schon bei der Klassendeklaration über den Haufen geworfen habe. ;)

Das Prinzip hinter beiden Varianten ist aber gleich, wir beide teilen die "Welt" in Streifen und lassen jeden Streifen parallel von einem Thread berechnen. Das Iterieren über die Welt ist das, was sich in Conways relativ einfach parallelisieren lässt, da sich eben der neue Zustand jeder Zelle unabhängig der anderen Zellen berechnen lässt (für den alt Zustand der Nachbarzellen ist keine Synchronisation notwendig).

Viele Grüße,
Fancy
 

blueJisCrap

Mitglied
Das mit dem Modus ist prinzipiell relativ einfach:
Modus 1 (Standard Conway): Feld wird zufällig gefüllt und Rand (das was außerhalb der Welt liegt) als tot angesehen.
Modus 2: Leeres Startfeld, nur der Rand ist jetzt lebendig, und zwar durchgehend, also nicht nur am Anfang.

Marco, deinen Code habe ich mir jetzt mal angeschaut.
Der Hammer, echt!
Ich hab erst beim Lesen festgestellt, dass man auch in dein Fenster reinmalen kann ^^
Übrigens stimmt die Berechnung der Zeigerposition nicht, da werden die Ränder unten und rechts nicht berücksichtigt. Eine einfache Möglichkeit das zu korrigieren wäre über ein schlichtes if zu prüfen ob die Position im Panel liegt und das scaling einfach ganz zu lassen.
Auch erst bei der Lektüre aufgefallen ist mir, dass du diesen 2. Modus gar nicht so einfach umsetzen könntest, da du grundsätzlich keinen Bereich außerhalb der Welt vorsiehst, sondern eben vom einen zum anderen Rand 'warpst'.

Nach dem was ich jetzt so gesehen habe liegt euer Vorteil darin, dass ihr auch die Berechnung der nächsten 'Generation' aufgeteilt habt. Außerdem geht ihr insgesamt weniger Umwege, da die Arrays direkt die Farbwerte speichern. Wenn ich was grundlegendes übersehen habe weist mich bitte darauf hin.
 

Marco13

Top Contributor
Die Position stimmt, wenn man das Bild mit
g.drawImage(bufferedImage, 0, 0, getWidth(), getHeight(), null);
malt - also immer das Fenster komplett ausfüllend, egal, wie groß es eigentlich ist. (Das hatte ich ursprünglich so, und die Mauskoordinaten werden noch entsprechend umgerechnet - vergessen das anzupassen...)
 

Marco13

Top Contributor
Hab' gerade mal probiert, ob man da noch was machen kann, indem man die Daten mit LWJGL in ein PBO packt und als Textur auf ein Rechteck klatscht, und dann die PBO-Daten durch buffer-sharing an OpenCL weiterreicht um damit die neue Generation zu berechnen. Mit dem ersten, naiven Ansatz ist es etwa genausoschnell wie vorher :( Aber es gibt da noch einiges an Optimierungspotential. Mal schauen ob ich da nächste Woche weitermachen kann.
 

blueJisCrap

Mitglied
Man kann es auch künstlich aufblasen...

Das erinnert mich an die Physik-Seminararbeit (G8-Facharbeit) einer meiner Mitschülerinnen, die in eine Schaltung einen Mikroprozessor gebaut hat obwohl man die gesamte Schaltung auch aus 8 analogen Bauteilen hätte bauen können.

Fühl dich da jetzt bitte nicht angegriffen. Man lernt sicherlich was dabei wenn man versucht ein Programm nur auf Leistung zu trimmen. Aber wo liegt in diesem Fall der praktische Nutzen wenn man auch noch LWJGL einbindet?
 
G

Guest2

Gast
Man kann dann die Conway Berechnungen auch auf der GPU ausführen, das bietet sich eben an da Conway massiv parallel berechnet werden kann. Das sollte wesentlich schneller als auf der CPU sein. Ich bastel vielleicht mal heute Abend eine OpenGL/GLSL Variante, die könnte man dann mit Marcos OpenGL/OpenCL Variante vergleichen ;).

Viele Grüße,
Fancy
 
G

Guest2

Gast
Ich hab das jetzt Mal als OpenGL/GLSL in 4.2 Core geschrieben. Macht hier auf dem Rechner ~1450fps. Wenn Marcos Lösung wesentlich schneller wird, muss ich vielleicht noch mal einen prüfenden Blick draufwerfen und ggf. versuchen nachzulegen. ;)

Java:
package jf.conway;

import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_FALSE;
import static org.lwjgl.opengl.GL11.GL_FLOAT;
import static org.lwjgl.opengl.GL11.GL_NEAREST;
import static org.lwjgl.opengl.GL11.GL_REPEAT;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_MAG_FILTER;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_MIN_FILTER;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_S;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_T;
import static org.lwjgl.opengl.GL11.GL_TRIANGLES;
import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE;
import static org.lwjgl.opengl.GL11.glBindTexture;
import static org.lwjgl.opengl.GL11.glClear;
import static org.lwjgl.opengl.GL11.glDeleteTextures;
import static org.lwjgl.opengl.GL11.glDrawArrays;
import static org.lwjgl.opengl.GL11.glGenTextures;
import static org.lwjgl.opengl.GL11.glTexImage2D;
import static org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER;
import static org.lwjgl.opengl.GL15.GL_STATIC_DRAW;
import static org.lwjgl.opengl.GL15.glBindBuffer;
import static org.lwjgl.opengl.GL15.glBufferData;
import static org.lwjgl.opengl.GL15.glDeleteBuffers;
import static org.lwjgl.opengl.GL15.glGenBuffers;
import static org.lwjgl.opengl.GL20.GL_COMPILE_STATUS;
import static org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER;
import static org.lwjgl.opengl.GL20.GL_INFO_LOG_LENGTH;
import static org.lwjgl.opengl.GL20.GL_LINK_STATUS;
import static org.lwjgl.opengl.GL20.GL_VERTEX_SHADER;
import static org.lwjgl.opengl.GL20.glAttachShader;
import static org.lwjgl.opengl.GL20.glCompileShader;
import static org.lwjgl.opengl.GL20.glCreateProgram;
import static org.lwjgl.opengl.GL20.glCreateShader;
import static org.lwjgl.opengl.GL20.glDeleteProgram;
import static org.lwjgl.opengl.GL20.glDeleteShader;
import static org.lwjgl.opengl.GL20.glDetachShader;
import static org.lwjgl.opengl.GL20.glEnableVertexAttribArray;
import static org.lwjgl.opengl.GL20.glGetProgram;
import static org.lwjgl.opengl.GL20.glGetProgramInfoLog;
import static org.lwjgl.opengl.GL20.glGetShader;
import static org.lwjgl.opengl.GL20.glGetShaderInfoLog;
import static org.lwjgl.opengl.GL20.glLinkProgram;
import static org.lwjgl.opengl.GL20.glShaderSource;
import static org.lwjgl.opengl.GL20.glUseProgram;
import static org.lwjgl.opengl.GL20.glVertexAttribPointer;
import static org.lwjgl.opengl.GL30.GL_COLOR_ATTACHMENT0;
import static org.lwjgl.opengl.GL30.GL_FRAMEBUFFER;
import static org.lwjgl.opengl.GL30.glBindFramebuffer;
import static org.lwjgl.opengl.GL30.glDeleteFramebuffers;
import static org.lwjgl.opengl.GL30.glFramebufferTexture2D;
import static org.lwjgl.opengl.GL30.glGenFramebuffers;
import static org.lwjgl.opengl.GL33.glBindSampler;
import static org.lwjgl.opengl.GL33.glDeleteSamplers;
import static org.lwjgl.opengl.GL33.glGenSamplers;
import static org.lwjgl.opengl.GL33.glSamplerParameteri;

import java.io.UnsupportedEncodingException;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Random;

import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.ContextAttribs;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.PixelFormat;


public final class GPUConway {


    private static final String VERTEX_SHADER  = "" +
            "#version 420 core                                                                       \n" +
            "                                                                                        \n" +
            "layout(location = 0) in vec4 position;                                                  \n" +
            "                                                                                        \n" +
            "void main() {                                                                           \n" +
            "                                                                                        \n" +
            "    gl_Position = position;                                                             \n" +
            "                                                                                        \n" +
            "}                                                                                       \n";

    private static final String DISPLAY_SHADER = "" +
            "#version 420 core                                                                       \n" +
            "                                                                                        \n" +
            "layout(binding=0) uniform sampler2D texture;                                            \n" +
            "layout(location = 0) out vec4 color;                                                    \n" +
            "                                                                                        \n" +
            "void main() {                                                                           \n" +
            "                                                                                        \n" +
            "   color = texelFetch(texture, ivec2(gl_FragCoord.x, gl_FragCoord.y), 0);               \n" +
            "                                                                                        \n" +
            "}                                                                                       \n";

    private static final String CONWAY_SHADER  = "" +
            "#version 420 core                                                                       \n" +
            "                                                                                        \n" +
            "layout(binding=0) uniform sampler2D texture;                                            \n" +
            "layout(location = 0) out vec4 color;                                                    \n" +
            "                                                                                        \n" +
            "void main() {                                                                           \n" +
            "                                                                                        \n" +
            "    float n = texelFetch(texture, ivec2(gl_FragCoord.x  - 1, gl_FragCoord.y - 1), 0).r; \n" +
            "    n += texelFetch(texture, ivec2(gl_FragCoord.x - 0, gl_FragCoord.y - 1), 0).r;       \n" +
            "    n += texelFetch(texture, ivec2(gl_FragCoord.x + 1, gl_FragCoord.y - 1), 0).r;       \n" +
            "    n += texelFetch(texture, ivec2(gl_FragCoord.x - 1, gl_FragCoord.y - 0), 0).r;       \n" +
            "    n += texelFetch(texture, ivec2(gl_FragCoord.x + 1, gl_FragCoord.y - 0), 0).r;       \n" +
            "    n += texelFetch(texture, ivec2(gl_FragCoord.x - 1, gl_FragCoord.y + 1), 0).r;       \n" +
            "    n += texelFetch(texture, ivec2(gl_FragCoord.x - 0, gl_FragCoord.y + 1), 0).r;       \n" +
            "    n += texelFetch(texture, ivec2(gl_FragCoord.x + 1, gl_FragCoord.y + 1), 0).r;       \n" +
            "                                                                                        \n" +
            "    int i = int(n);                                                                     \n" +
            "    if(texelFetch(texture, ivec2(gl_FragCoord.x, gl_FragCoord.y), 0).r > 0) {           \n" +
            "        if(i == 2 || i == 3) {                                                          \n" +
            "            color = vec4(1,1,1,1);                                                      \n" +
            "        }                                                                               \n" +
            "    } else {                                                                            \n" +
            "        if(i == 3) {                                                                    \n" +
            "            color = vec4(1,1,1,1);                                                      \n" +
            "        }                                                                               \n" +
            "     }                                                                                  \n" +
            "}                                                                                       \n";

    private static final int    COLOR         = 0xFFFFFF;
    private static final int    WIDTH         = 1800;
    private static final int    HEIGHT        = 900;

    private final Program       display       = new Program(new Program.Shader(VERTEX_SHADER, GL_VERTEX_SHADER), new Program.Shader(DISPLAY_SHADER, GL_FRAGMENT_SHADER));
    private final Program       conway         = new Program(new Program.Shader(VERTEX_SHADER, GL_VERTEX_SHADER), new Program.Shader(CONWAY_SHADER, GL_FRAGMENT_SHADER));
    private final Quad          quad          = new Quad();
    private final Texture       front         = new Texture();
    private final Texture       back          = new Texture();
    private final FBO           fbo           = new FBO();

    private int                 frame         = 0;
    private long                time          = 0;


    public void init() throws LWJGLException, UnsupportedEncodingException {

        Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
        Display.create(new PixelFormat(), new ContextAttribs(4, 2).withProfileCore(true).withForwardCompatible(true));

        display.init();
        conway.init();
        quad.init();
        front.init();
        back.init();
        fbo.init();

    }


    private void step(final Texture back, final Texture front) {

        if (frame++ > 500) {

            System.out.println("FPS: " + frame / ((-(time - (time = System.nanoTime()))) / 1000000000.0));

            frame = 0;

        }

        conway.use();
        fbo.bind();
        back.attachToFBO();
        front.bind();
        glClear(GL_COLOR_BUFFER_BIT);
        quad.draw();
        fbo.unbind();

        display.use();
        back.bind();
        quad.draw();

        Display.update();

    }


    public void display() {

        while (!Display.isCloseRequested()) {

            step(back, front);
            step(front, back);

        }

        display.delete();
        conway.delete();
        quad.delete();
        front.delete();
        back.delete();
        fbo.delete();

        Display.destroy();

    }


    private static class Program {

        private static class Shader {

            private final String code;
            private final int    type;

            private int          handle;


            public Shader(final String code, final int type) {

                this.code = code;
                this.type = type;

            }


            private void init() {

                handle = glCreateShader(type);
                glShaderSource(handle, code);
                glCompileShader(handle);

                if (glGetShader(handle, GL_COMPILE_STATUS) == GL_FALSE) {

                    final int length = glGetShader(handle, GL_INFO_LOG_LENGTH);
                    System.err.println(glGetShaderInfoLog(handle, length));

                    handle = -1;

                }

            }


            private void attach(final int program) {

                glAttachShader(program, handle);

            }


            private void detach(final int program) {

                glDetachShader(program, handle);

            }


            private void delete() {

                glDeleteShader(handle);

            }

        }


        private final Shader[] shaders;

        private int            handle;


        public Program(final Shader... shaders) {

            this.shaders = shaders;

        }


        public void init() {

            handle = glCreateProgram();

            for (final Shader shader : shaders) {

                shader.init();
                shader.attach(handle);

            }

            glLinkProgram(handle);

            if (glGetProgram(handle, GL_LINK_STATUS) == GL_FALSE) {

                final int length = glGetProgram(handle, GL_INFO_LOG_LENGTH);
                System.err.println(glGetProgramInfoLog(handle, length));

                handle = -1;

            }

            for (final Shader shader : shaders) {

                shader.detach(handle);
                shader.delete();

            }

        }


        public void use() {

            glUseProgram(handle);

        }


        public void delete() {

            glDeleteProgram(handle);

        }

    }


    private static class Quad {

        private static final float[] QUAD = new float[] { -1, -1, +1, +1, -1, +1, -1, -1, +1, -1, +1, +1 };

        private int                  handle;


        public void init() {

            final FloatBuffer quad = BufferUtils.createFloatBuffer(QUAD.length);
            quad.put(QUAD);
            quad.rewind();

            handle = glGenBuffers();
            glBindBuffer(GL_ARRAY_BUFFER, handle);
            glBufferData(GL_ARRAY_BUFFER, quad, GL_STATIC_DRAW);

            glEnableVertexAttribArray(0);
            glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);

        }


        public void draw() {

            glDrawArrays(GL_TRIANGLES, 0, 6);

        }


        public void delete() {

            glDeleteBuffers(handle);

        }

    }


    private static class Texture {

        private int sampler;
        private int handle;


        public void init() {

            sampler = glGenSamplers();
            glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
            glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
            glSamplerParameteri(sampler, GL_TEXTURE_WRAP_S, GL_REPEAT);
            glSamplerParameteri(sampler, GL_TEXTURE_WRAP_T, GL_REPEAT);
            glBindSampler(0, sampler);

            final Random random = new Random(0);
            final IntBuffer data = BufferUtils.createIntBuffer(WIDTH * HEIGHT);
            for (int i = 0; i < data.capacity(); i++)
                if (random.nextInt(100) > 90)
                    data.put(i, COLOR);

            handle = glGenTextures();
            glBindTexture(GL_TEXTURE_2D, handle);
            glTexImage2D(GL_TEXTURE_2D, 0, GL11.GL_RGBA8, Display.getDisplayMode().getWidth(), Display.getDisplayMode().getHeight(), 0, GL12.GL_BGRA, GL_UNSIGNED_BYTE, data);

        }


        public void bind() {

            glBindTexture(GL_TEXTURE_2D, handle);

        }


        public void attachToFBO() {

            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, handle, 0);

        }


        public void delete() {

            glDeleteSamplers(sampler);
            glDeleteTextures(handle);

        }

    }

    private static class FBO {

        private int handle;


        public void init() {

            handle = glGenFramebuffers();


        }


        public void bind() {

            glBindFramebuffer(GL_FRAMEBUFFER, handle);

        }


        public void unbind() {

            glBindFramebuffer(GL_FRAMEBUFFER, 0);

        }


        public void delete() {

            glDeleteFramebuffers(handle);

        }

    }


    public static void main(final String[] args) throws LWJGLException, UnsupportedEncodingException {

        final GPUConway main = new GPUConway();

        main.init();
        main.display();

    }

}

Viele Grüße,
Fancy
 

Marco13

Top Contributor
Man kann es auch künstlich aufblasen...
...
Fühl dich da jetzt bitte nicht angegriffen. Man lernt sicherlich was dabei wenn man versucht ein Programm nur auf Leistung zu trimmen. Aber wo liegt in diesem Fall der praktische Nutzen wenn man auch noch LWJGL einbindet?

Praktischer Nutzen? Bei Conway? Und dem Versuch, die FPS von 10 auf 100 (oder 1000) zu erhöhen? Darum geht's doch nicht :noe: Oder doch? Wenn man versucht ein performantes Conway's Game of Life zu implementieren ... und versucht es mit mehr als 2 Threads umzusetzen schon.

Akademische Spielerei? Vielleicht.

Find dich damit ab: In so einem Forum muss man mit Nerds rechnen :smoke: :D

Hab' heute hochproduktiv 10 Stunden im Meeting gesessen :( werde aber mal schauen, was man mit OpenCL da so machen kann. Vermutlich erstmal nicht viel mehr (sondern potentiell viel weniger) als mit GLSL, weil da das caching bei den Texturzugriffen schon eingebaut ist, und man in CL dafür images verwenden muss (und abgesehen davon meine Detailkenntnisse von "modernerem" GL sehr ausbaufähig sind... ich werde jetzt nicht zugeben, wie lange ich gebraucht habe, um das Einheitsquadrat mit dem einfachst-möglichen Shader auf den Bildschirm zu bringen :oops: )) aber interessant wäre es schon.
 
G

Guest2

Gast
Ich fände den Vergleich zwischen OpenCL und GLSL nicht nur von der reinen Performance, sondern auch von der Architektur her interessant. Leider habe ich nämlich überhaupt kein Gefühl dafür, bis zu welchem Punkt man lieber mit GLSL "dengeln" sollte oder lieber "sauberer"(?) mit OpenCL rangehen sollte (zumindest wenn es nicht gerade ums number crunching geht, sonder z.B. bei der Animation von Haaren oder Kleidung (Deine jocl cloth demo kenn ich ;))).

Hier beim Conway könnte ich mir aber vorstellen, dass die GLSL Variante "einfacher" ist, da der Conway eben ein sehr "bildlicher" Algorithmus ist.


ich werde jetzt nicht zugeben, wie lange ich gebraucht habe, um das Einheitsquadrat mit dem einfachst-möglichen Shader auf den Bildschirm zu bringen :oops:

Ich würde auch nicht zugeben wollen, wie lange ich für die einfachsten CL Dinge brauche... ;)


Aber wo liegt in diesem Fall der praktische Nutzen wenn man auch noch LWJGL einbindet?

Wenn Deine erste Variante mit 15 fps lief und die GLSL Variante oben mit ~1450 fps, dann ist der Nutzen einfach, dass es ca. 100-mal so schnell ist ;)

Viele Grüße,
Fancy
 

Marco13

Top Contributor
Ich fände den Vergleich zwischen OpenCL und GLSL nicht nur von der reinen Performance, sondern auch von der Architektur her interessant. Leider habe ich nämlich überhaupt kein Gefühl dafür, bis zu welchem Punkt man lieber mit GLSL "dengeln" sollte oder lieber "sauberer"(?) mit OpenCL rangehen sollte (zumindest wenn es nicht gerade ums number crunching geht, sonder z.B. bei der Animation von Haaren oder Kleidung (Deine jocl cloth demo kenn ich ;))).

Hmja... der Vergleich wird schwierig. Ich hatte schon länger vor, mal einen "PixelRenderer" zu schreiben, weil ich sowas schon in verschiedenen Zusammenhängen gebraucht hatte. Also irgendwas, wo man sich mit einer einfachen, klaren Schnittstelle entweder
- den gemappten Buffer eines PBO
- oder die PBO-id (für das erzeugen eines cl_mem)
abholen und damit rumpfuschen kann, und der nichts anderes macht, als das, was man da reinsteckt, als Textur auf ein Bildfüllendes Quad zu malen. Dewegen kommt mir dieser Thread gerade recht, weil der Conway ja ein Parade-Anwendungsfall dafür ist.

Intern könnte dieser PixelRenderer wahrscheinlich relativ einfach sein, aber erstens fehlt mir die ... "Versiertheit", um das ganze an den entscheidenden Stellen auf eine vermeintlich simple Folge von aufrufen wie [c]use()/bind()/draw()[/c] zu reduzieren (bzw. es "lohnt" sich nicht, diese inneren Klassen zu erstellen, weil er sowieso nie mehr macht, als das, und diese sprechenden Methoden i.a. ohnehin nur aus einer Zeile bestehen), und zweitens bin ich mir nicht sicher, an welchen Stellen der Versuch, das als einfache API nach außen anzubieten bestimmte Dinge, die für die letzten paar FPS verwantwortlich sind, unmöglich machen könnte.

Wie auch immer, mit diesem PixelRenderer hatte ich eben angefangen, und ich glaube, wenn damit der Conway ("gut" und "leicht") funktioniert, hat er im wesentlichen die Funktionalität, die ich brauche... von daher... mal schauen, was dabei rauskommt - auch wenn es wieder kein Ein-Klassen-KSKB werden wird ;)
 

blueJisCrap

Mitglied
Na das klappt ja super:
Code:
org.lwjgl.LWJGLException: Could not create context (WGL_ARB_create_context)
	at org.lwjgl.opengl.WindowsContextImplementation.nCreate(Native Method)
	at org.lwjgl.opengl.WindowsContextImplementation.create(WindowsContextImplementation.java:50)
	at org.lwjgl.opengl.ContextGL.<init>(ContextGL.java:132)
	at org.lwjgl.opengl.Display.create(Display.java:875)
	at org.lwjgl.opengl.Display.create(Display.java:822)
	at GPUConway.init(GPUConway.java:145)
	at GPUConway.main(GPUConway.java:454)
 

Marco13

Top Contributor
Das liegt wohl am "new ContextAttribs(4, 2)": Dort wird davon ausgegangen, dass man das ALLER-aller-neueste OpenGL hat. @Fancy: Wird dort abgesehen von den "location"-Dingen in den Shadern irgenwas wirklich GL42-Spezifisches verwendet? Das sollte man doch relativ leicht auf 3.2 runterdrücken können (auch wenn's einem GL-Puristen weh tut :D )
 
G

Guest2

Gast
Genau, das layout location als Vermerk für die Vertex-Daten gibt es seit OpenGL 3.3. Das layout binding für den sampler allerdings erst seit 4.2. Und ja, man kann das auch auf ältere OpenGL Versionen stutzen. ;)

Je nach Treiber reicht es, wenn man die Angabe einfach aus dem Shader löscht. Wenn da nix steht, wird oft 0 angenommen. Verlassen sollte man sich da aber imho nicht drauf und spätestens bei mehreren Attributen knallt es sowieso. Man muss dann also die Verbindung zwischen OpenGL und GLSL selbst dengeln. Für die Vertex-Daten z.B. mit glGetAttribLocation(handle, "position") und glVertexAttribPointer(program.getVBOLocation(),...). Und für den Sampler mit glGetUniformLocation(handle, "texture") und glUniform1i(program.getTextureBinding(),...).

Dann blutet aber nicht nur das OpenGL Herz, sondern auch das des OOP. Vorher war die Verbindung zwischen OpenGL und GLSL via Vereinbarung im Shader definiert, nimmt man die nun weg, bekommt man Abhängigkeiten zwischen Program<->Texture und Program<->Quad. Bei größeren Programmen kann das imho hässlich werden.

Nunja, wenn man dann oben noch das Sampler Objekt rauskürzt, kommt man auf OpenGL 3.2 (eigentlich sogar auf 3.0 aber da gab es noch keine Profile).

Wenn ich nichts übersehen habe, sollte das dann etwa so aussehen:

Java:
package jf.conway;

import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_FALSE;
import static org.lwjgl.opengl.GL11.GL_FLOAT;
import static org.lwjgl.opengl.GL11.GL_LINEAR;
import static org.lwjgl.opengl.GL11.GL_REPEAT;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_MAG_FILTER;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_MIN_FILTER;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_S;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_T;
import static org.lwjgl.opengl.GL11.GL_TRIANGLES;
import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE;
import static org.lwjgl.opengl.GL11.glBindTexture;
import static org.lwjgl.opengl.GL11.glClear;
import static org.lwjgl.opengl.GL11.glDeleteTextures;
import static org.lwjgl.opengl.GL11.glDrawArrays;
import static org.lwjgl.opengl.GL11.glGenTextures;
import static org.lwjgl.opengl.GL11.glTexImage2D;
import static org.lwjgl.opengl.GL11.glTexParameteri;
import static org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER;
import static org.lwjgl.opengl.GL15.GL_STATIC_DRAW;
import static org.lwjgl.opengl.GL15.glBindBuffer;
import static org.lwjgl.opengl.GL15.glBufferData;
import static org.lwjgl.opengl.GL15.glDeleteBuffers;
import static org.lwjgl.opengl.GL15.glGenBuffers;
import static org.lwjgl.opengl.GL20.GL_COMPILE_STATUS;
import static org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER;
import static org.lwjgl.opengl.GL20.GL_INFO_LOG_LENGTH;
import static org.lwjgl.opengl.GL20.GL_LINK_STATUS;
import static org.lwjgl.opengl.GL20.GL_VERTEX_SHADER;
import static org.lwjgl.opengl.GL20.glAttachShader;
import static org.lwjgl.opengl.GL20.glCompileShader;
import static org.lwjgl.opengl.GL20.glCreateProgram;
import static org.lwjgl.opengl.GL20.glCreateShader;
import static org.lwjgl.opengl.GL20.glDeleteProgram;
import static org.lwjgl.opengl.GL20.glDeleteShader;
import static org.lwjgl.opengl.GL20.glDetachShader;
import static org.lwjgl.opengl.GL20.glEnableVertexAttribArray;
import static org.lwjgl.opengl.GL20.glGetAttribLocation;
import static org.lwjgl.opengl.GL20.glGetProgram;
import static org.lwjgl.opengl.GL20.glGetProgramInfoLog;
import static org.lwjgl.opengl.GL20.glGetShader;
import static org.lwjgl.opengl.GL20.glGetShaderInfoLog;
import static org.lwjgl.opengl.GL20.glGetUniformLocation;
import static org.lwjgl.opengl.GL20.glLinkProgram;
import static org.lwjgl.opengl.GL20.glShaderSource;
import static org.lwjgl.opengl.GL20.glUniform1i;
import static org.lwjgl.opengl.GL20.glUseProgram;
import static org.lwjgl.opengl.GL20.glVertexAttribPointer;
import static org.lwjgl.opengl.GL30.GL_COLOR_ATTACHMENT0;
import static org.lwjgl.opengl.GL30.GL_FRAMEBUFFER;
import static org.lwjgl.opengl.GL30.glBindFramebuffer;
import static org.lwjgl.opengl.GL30.glDeleteFramebuffers;
import static org.lwjgl.opengl.GL30.glFramebufferTexture2D;
import static org.lwjgl.opengl.GL30.glGenFramebuffers;

import java.io.UnsupportedEncodingException;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Random;

import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.ContextAttribs;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.PixelFormat;


public final class LegacyGPUConway {


    private static final String VERTEX_SHADER  = "" +
            "#version 150 core        // GLSL 1.50 is for OpenGL 3.2                                 \n" +
            "                                                                                        \n" +
            "in vec4 position;                                                                       \n" +
            "                                                                                        \n" +
            "void main() {                                                                           \n" +
            "                                                                                        \n" +
            "    gl_Position = position;                                                             \n" +
            "                                                                                        \n" +
            "}                                                                                       \n";

    private static final String DISPLAY_SHADER = "" +
            "#version 150 core                                                                       \n" +
            "                                                                                        \n" +
            "uniform sampler2D texture;                                                              \n" +
            "out vec4 color;                                                                         \n" +
            "                                                                                        \n" +
            "void main() {                                                                           \n" +
            "                                                                                        \n" +
            "   color = texelFetch(texture, ivec2(gl_FragCoord.x, gl_FragCoord.y), 0);               \n" +
            "                                                                                        \n" +
            "}                                                                                       \n";

    private static final String CONWAY_SHADER  = "" +
            "#version 150 core                                                                       \n" +
            "                                                                                        \n" +
            "uniform sampler2D texture;                                                              \n" +
            "out vec4 color;                                                                         \n" +
            "                                                                                        \n" +
            "void main() {                                                                           \n" +
            "                                                                                        \n" +
            "    float n = texelFetch(texture, ivec2(gl_FragCoord.x  - 1, gl_FragCoord.y - 1), 0).r; \n" +
            "    n += texelFetch(texture, ivec2(gl_FragCoord.x - 0, gl_FragCoord.y - 1), 0).r;       \n" +
            "    n += texelFetch(texture, ivec2(gl_FragCoord.x + 1, gl_FragCoord.y - 1), 0).r;       \n" +
            "    n += texelFetch(texture, ivec2(gl_FragCoord.x - 1, gl_FragCoord.y - 0), 0).r;       \n" +
            "    n += texelFetch(texture, ivec2(gl_FragCoord.x + 1, gl_FragCoord.y - 0), 0).r;       \n" +
            "    n += texelFetch(texture, ivec2(gl_FragCoord.x - 1, gl_FragCoord.y + 1), 0).r;       \n" +
            "    n += texelFetch(texture, ivec2(gl_FragCoord.x - 0, gl_FragCoord.y + 1), 0).r;       \n" +
            "    n += texelFetch(texture, ivec2(gl_FragCoord.x + 1, gl_FragCoord.y + 1), 0).r;       \n" +
            "                                                                                        \n" +
            "    int i = int(n);                                                                     \n" +
            "    if(texelFetch(texture, ivec2(gl_FragCoord.x, gl_FragCoord.y), 0).r > 0) {           \n" +
            "        if(i == 2 || i == 3) {                                                          \n" +
            "            color = vec4(1,1,1,1);                                                      \n" +
            "        }                                                                               \n" +
            "    } else {                                                                            \n" +
            "        if(i == 3) {                                                                    \n" +
            "            color = vec4(1,1,1,1);                                                      \n" +
            "        }                                                                               \n" +
            "     }                                                                                  \n" +
            "}                                                                                       \n";

    private static final int    COLOR          = 0xFFFFFF;
    private static final int    WIDTH          = 1800;
    private static final int    HEIGHT         = 900;

    private final Program       display        = new Program(new Program.Shader(VERTEX_SHADER, GL_VERTEX_SHADER), new Program.Shader(DISPLAY_SHADER, GL_FRAGMENT_SHADER));
    private final Program       conway         = new Program(new Program.Shader(VERTEX_SHADER, GL_VERTEX_SHADER), new Program.Shader(CONWAY_SHADER, GL_FRAGMENT_SHADER));
    private final Quad          quad           = new Quad();
    private final Texture       front          = new Texture();
    private final Texture       back           = new Texture();
    private final FBO           fbo            = new FBO();

    private int                 frame          = 0;
    private long                time           = 0;


    public void init() throws LWJGLException, UnsupportedEncodingException {

        Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
        Display.create(new PixelFormat(), new ContextAttribs(3, 2).withProfileCore(true).withForwardCompatible(true));

        display.init();
        conway.init();
        quad.init();
        front.init();
        back.init();
        fbo.init();

    }


    private void step(final Texture back, final Texture front) {

        if (frame++ > 500) {

            System.out.println("FPS: " + frame / ((-(time - (time = System.nanoTime()))) / 1000000000.0));

            frame = 0;

        }

        conway.use();
        fbo.bind();
        back.attachToFBO();
        front.bind(conway);
        glClear(GL_COLOR_BUFFER_BIT);
        quad.draw(conway);
        fbo.unbind();

        display.use();
        back.bind(display);
        quad.draw(display);

        Display.update();

    }


    public void display() {

        while (!Display.isCloseRequested()) {

            step(back, front);
            step(front, back);

        }

        display.delete();
        conway.delete();
        quad.delete();
        front.delete();
        back.delete();
        fbo.delete();

        Display.destroy();

    }


    private static class Program {

        private static class Shader {

            private final String code;
            private final int    type;

            private int          handle;


            public Shader(final String code, final int type) {

                this.code = code;
                this.type = type;

            }


            private void init() {

                handle = glCreateShader(type);
                glShaderSource(handle, code);
                glCompileShader(handle);

                if (glGetShader(handle, GL_COMPILE_STATUS) == GL_FALSE) {

                    final int length = glGetShader(handle, GL_INFO_LOG_LENGTH);
                    System.err.println(glGetShaderInfoLog(handle, length));

                    handle = -1;

                }

            }


            private void attach(final int program) {

                glAttachShader(program, handle);

            }


            private void detach(final int program) {

                glDetachShader(program, handle);

            }


            private void delete() {

                glDeleteShader(handle);

            }

        }

        private final Shader[] shaders;

        private int            handle;

        private int            textureBinding;
        private int            vboLocation;


        public Program(final Shader... shaders) {

            this.shaders = shaders;

        }


        public void init() {

            handle = glCreateProgram();

            for (final Shader shader : shaders) {

                shader.init();
                shader.attach(handle);

            }

            glLinkProgram(handle);

            textureBinding = glGetUniformLocation(handle, "texture");
            vboLocation = glGetAttribLocation(handle, "position");

            if (glGetProgram(handle, GL_LINK_STATUS) == GL_FALSE) {

                final int length = glGetProgram(handle, GL_INFO_LOG_LENGTH);
                System.err.println(glGetProgramInfoLog(handle, length));

                handle = -1;

            }

            for (final Shader shader : shaders) {

                shader.detach(handle);
                shader.delete();

            }

        }


        public void use() {

            glUseProgram(handle);

        }


        public void delete() {

            glDeleteProgram(handle);

        }


        public int getTextureBinding() {

            return textureBinding;

        }


        public int getVBOLocation() {

            return vboLocation;

        }

    }


    private static class Quad {

        private static final float[] QUAD = new float[] { -1, -1, +1, +1, -1, +1, -1, -1, +1, -1, +1, +1 };

        private int                  handle;


        public void init() {

            final FloatBuffer quad = BufferUtils.createFloatBuffer(QUAD.length);
            quad.put(QUAD);
            quad.rewind();

            handle = glGenBuffers();
            glBindBuffer(GL_ARRAY_BUFFER, handle);
            glBufferData(GL_ARRAY_BUFFER, quad, GL_STATIC_DRAW);


        }


        public void draw(final Program program) {

            glBindBuffer(GL_ARRAY_BUFFER, handle);

            glEnableVertexAttribArray(program.getVBOLocation());
            glVertexAttribPointer(program.getVBOLocation(), 2, GL_FLOAT, false, 0, 0);

            glDrawArrays(GL_TRIANGLES, 0, 6);

        }


        public void delete() {

            glDeleteBuffers(handle);

        }

    }


    private static class Texture {

        private int handle;


        public void init() {

            final Random random = new Random(0);
            final IntBuffer data = BufferUtils.createIntBuffer(WIDTH * HEIGHT);
            for (int i = 0; i < data.capacity(); i++)
                if (random.nextInt(100) > 90)
                    data.put(i, COLOR);

            handle = glGenTextures();
            glBindTexture(GL_TEXTURE_2D, handle);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
            glTexImage2D(GL_TEXTURE_2D, 0, GL11.GL_RGBA8, Display.getDisplayMode().getWidth(), Display.getDisplayMode().getHeight(), 0, GL12.GL_BGRA, GL_UNSIGNED_BYTE, data);

        }


        public void bind(final Program program) {

            glBindTexture(GL_TEXTURE_2D, handle);
            glUniform1i(program.getTextureBinding(), 0);

        }


        public void attachToFBO() {

            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, handle, 0);

        }


        public void delete() {

            glDeleteTextures(handle);

        }

    }

    private static class FBO {

        private int handle;


        public void init() {

            handle = glGenFramebuffers();


        }


        public void bind() {

            glBindFramebuffer(GL_FRAMEBUFFER, handle);

        }


        public void unbind() {

            glBindFramebuffer(GL_FRAMEBUFFER, 0);

        }


        public void delete() {

            glDeleteFramebuffers(handle);

        }

    }


    public static void main(final String[] args) throws LWJGLException, UnsupportedEncodingException {

        final LegacyGPUConway main = new LegacyGPUConway();

        main.init();
        main.display();

    }

}

Viele Grüße,
Fancy
 

GUI-Programmer

Top Contributor
Bei mir funktionieren beide LWJGL Varianten nicht. Das Fenster blitzt kurz auf (alles weiß, nichts zu sehen) und verschwindet dann wieder. Ich werde aus der Exception nicht schlau:
Java:
Exception in thread "main" org.lwjgl.LWJGLException: Could not create context (WGL_ARB_create_context)
	at org.lwjgl.opengl.WindowsContextImplementation.nCreate(Native Method)
	at org.lwjgl.opengl.WindowsContextImplementation.create(WindowsContextImplementation.java:50)
	at org.lwjgl.opengl.ContextGL.<init>(ContextGL.java:132)
	at org.lwjgl.opengl.Display.create(Display.java:875)
	at org.lwjgl.opengl.Display.create(Display.java:822)
	at GPUConway.init(GPUConway.java:145)
	at GPUConway.main(GPUConway.java:454)

Was muss/kann ich ändern, damit es funktioniert?
 

blueJisCrap

Mitglied
@GUI-Programmer
Da hast du wohl das gleiche Problem wie ich: OpenGL zu alt.

Ich für meinen Teil krieg immer noch eine Exception, allerdings eine andere:
Code:
org.lwjgl.opengl.OpenGLException: Invalid operation (1282)
	at org.lwjgl.opengl.Util.checkGLError(Util.java:59)
	at org.lwjgl.opengl.GL20.glVertexAttribPointer(GL20.java:933)
	at LegacyGPUConway$Quad.draw(LegacyGPUConway.java:369)
	at LegacyGPUConway.step(LegacyGPUConway.java:172)
	at LegacyGPUConway.display(LegacyGPUConway.java:188)
	at LegacyGPUConway.main(LegacyGPUConway.java:473)
War wohl die Umstellung noch nicht ganz abgeschlossen.
 
G

Guest2

Gast
Was habt Ihr den für Grafikkarten? Bzw. wenn onboard welches Board?

(Die zweite Exception ist merkwürdig, werd ich mir gleich nochmal ansehen...)

Viele Grüße,
Fancy
 
G

Guest2

Gast
Ok, bezüglich der "Invalid operation": Da fehlte meinerseits noch was ... :oops:

Du könntest mal diese Version versuchen:

Java:
package jf.conway;

import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_FALSE;
import static org.lwjgl.opengl.GL11.GL_FLOAT;
import static org.lwjgl.opengl.GL11.GL_LINEAR;
import static org.lwjgl.opengl.GL11.GL_REPEAT;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_MAG_FILTER;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_MIN_FILTER;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_S;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_T;
import static org.lwjgl.opengl.GL11.GL_TRIANGLES;
import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE;
import static org.lwjgl.opengl.GL11.glBindTexture;
import static org.lwjgl.opengl.GL11.glClear;
import static org.lwjgl.opengl.GL11.glDeleteTextures;
import static org.lwjgl.opengl.GL11.glDrawArrays;
import static org.lwjgl.opengl.GL11.glGenTextures;
import static org.lwjgl.opengl.GL11.glTexImage2D;
import static org.lwjgl.opengl.GL11.glTexParameteri;
import static org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER;
import static org.lwjgl.opengl.GL15.GL_STATIC_DRAW;
import static org.lwjgl.opengl.GL15.glBindBuffer;
import static org.lwjgl.opengl.GL15.glBufferData;
import static org.lwjgl.opengl.GL15.glDeleteBuffers;
import static org.lwjgl.opengl.GL15.glGenBuffers;
import static org.lwjgl.opengl.GL20.GL_COMPILE_STATUS;
import static org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER;
import static org.lwjgl.opengl.GL20.GL_INFO_LOG_LENGTH;
import static org.lwjgl.opengl.GL20.GL_LINK_STATUS;
import static org.lwjgl.opengl.GL20.GL_VERTEX_SHADER;
import static org.lwjgl.opengl.GL20.glAttachShader;
import static org.lwjgl.opengl.GL20.glCompileShader;
import static org.lwjgl.opengl.GL20.glCreateProgram;
import static org.lwjgl.opengl.GL20.glCreateShader;
import static org.lwjgl.opengl.GL20.glDeleteProgram;
import static org.lwjgl.opengl.GL20.glDeleteShader;
import static org.lwjgl.opengl.GL20.glDetachShader;
import static org.lwjgl.opengl.GL20.glEnableVertexAttribArray;
import static org.lwjgl.opengl.GL20.glGetAttribLocation;
import static org.lwjgl.opengl.GL20.glGetProgram;
import static org.lwjgl.opengl.GL20.glGetProgramInfoLog;
import static org.lwjgl.opengl.GL20.glGetShader;
import static org.lwjgl.opengl.GL20.glGetShaderInfoLog;
import static org.lwjgl.opengl.GL20.glGetUniformLocation;
import static org.lwjgl.opengl.GL20.glLinkProgram;
import static org.lwjgl.opengl.GL20.glShaderSource;
import static org.lwjgl.opengl.GL20.glUniform1i;
import static org.lwjgl.opengl.GL20.glUseProgram;
import static org.lwjgl.opengl.GL20.glVertexAttribPointer;
import static org.lwjgl.opengl.GL30.GL_COLOR_ATTACHMENT0;
import static org.lwjgl.opengl.GL30.GL_FRAMEBUFFER;
import static org.lwjgl.opengl.GL30.glBindFramebuffer;
import static org.lwjgl.opengl.GL30.glBindVertexArray;
import static org.lwjgl.opengl.GL30.glDeleteFramebuffers;
import static org.lwjgl.opengl.GL30.glFramebufferTexture2D;
import static org.lwjgl.opengl.GL30.glGenFramebuffers;
import static org.lwjgl.opengl.GL30.glGenVertexArrays;

import java.io.UnsupportedEncodingException;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Random;

import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.ContextAttribs;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.PixelFormat;


public final class LegacyGPUConway {


    private static final String VERTEX_SHADER  = "" +
            "#version 150 core        // GLSL 1.50 is for OpenGL 3.2                                 \n" +
            "                                                                                        \n" +
            "in vec4 position;                                                                       \n" +
            "                                                                                        \n" +
            "void main() {                                                                           \n" +
            "                                                                                        \n" +
            "    gl_Position = position;                                                             \n" +
            "                                                                                        \n" +
            "}                                                                                       \n";

    private static final String DISPLAY_SHADER = "" +
            "#version 150 core                                                                       \n" +
            "                                                                                        \n" +
            "uniform sampler2D texture;                                                              \n" +
            "out vec4 color;                                                                         \n" +
            "                                                                                        \n" +
            "void main() {                                                                           \n" +
            "                                                                                        \n" +
            "   color = texelFetch(texture, ivec2(gl_FragCoord.x, gl_FragCoord.y), 0);               \n" +
            "                                                                                        \n" +
            "}                                                                                       \n";

    private static final String CONWAY_SHADER  = "" +
            "#version 150 core                                                                       \n" +
            "                                                                                        \n" +
            "uniform sampler2D texture;                                                              \n" +
            "out vec4 color;                                                                         \n" +
            "                                                                                        \n" +
            "void main() {                                                                           \n" +
            "                                                                                        \n" +
            "    float n = texelFetch(texture, ivec2(gl_FragCoord.x  - 1, gl_FragCoord.y - 1), 0).r; \n" +
            "    n += texelFetch(texture, ivec2(gl_FragCoord.x - 0, gl_FragCoord.y - 1), 0).r;       \n" +
            "    n += texelFetch(texture, ivec2(gl_FragCoord.x + 1, gl_FragCoord.y - 1), 0).r;       \n" +
            "    n += texelFetch(texture, ivec2(gl_FragCoord.x - 1, gl_FragCoord.y - 0), 0).r;       \n" +
            "    n += texelFetch(texture, ivec2(gl_FragCoord.x + 1, gl_FragCoord.y - 0), 0).r;       \n" +
            "    n += texelFetch(texture, ivec2(gl_FragCoord.x - 1, gl_FragCoord.y + 1), 0).r;       \n" +
            "    n += texelFetch(texture, ivec2(gl_FragCoord.x - 0, gl_FragCoord.y + 1), 0).r;       \n" +
            "    n += texelFetch(texture, ivec2(gl_FragCoord.x + 1, gl_FragCoord.y + 1), 0).r;       \n" +
            "                                                                                        \n" +
            "    int i = int(n);                                                                     \n" +
            "    if(texelFetch(texture, ivec2(gl_FragCoord.x, gl_FragCoord.y), 0).r > 0) {           \n" +
            "        if(i == 2 || i == 3) {                                                          \n" +
            "            color = vec4(1,1,1,1);                                                      \n" +
            "        }                                                                               \n" +
            "    } else {                                                                            \n" +
            "        if(i == 3) {                                                                    \n" +
            "            color = vec4(1,1,1,1);                                                      \n" +
            "        }                                                                               \n" +
            "     }                                                                                  \n" +
            "}                                                                                       \n";

    private static final int    COLOR          = 0xFFFFFF;
    private static final int    WIDTH          = 1800;
    private static final int    HEIGHT         = 900;

    private final Program       display        = new Program(new Program.Shader(VERTEX_SHADER, GL_VERTEX_SHADER), new Program.Shader(DISPLAY_SHADER, GL_FRAGMENT_SHADER));
    private final Program       conway         = new Program(new Program.Shader(VERTEX_SHADER, GL_VERTEX_SHADER), new Program.Shader(CONWAY_SHADER, GL_FRAGMENT_SHADER));
    private final Quad          quad           = new Quad();
    private final Texture       front          = new Texture();
    private final Texture       back           = new Texture();
    private final FBO           fbo            = new FBO();

    private int                 frame          = 0;
    private long                time           = 0;


    public void init() throws LWJGLException, UnsupportedEncodingException {

        Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
        Display.create(new PixelFormat(), new ContextAttribs(3, 2).withProfileCore(true).withForwardCompatible(true));

        display.init();
        conway.init();
        quad.init();
        front.init();
        back.init();
        fbo.init();

    }


    private void step(final Texture back, final Texture front) {

        if (frame++ > 500) {

            System.out.println("FPS: " + frame / ((-(time - (time = System.nanoTime()))) / 1000000000.0));

            frame = 0;

        }

        conway.use();
        fbo.bind();
        back.attachToFBO();
        front.bind(conway);
        glClear(GL_COLOR_BUFFER_BIT);
        quad.draw(conway);
        fbo.unbind();

        display.use();
        back.bind(display);
        quad.draw(display);

        Display.update();

    }


    public void display() {

        while (!Display.isCloseRequested()) {

            step(back, front);
            step(front, back);

        }

        display.delete();
        conway.delete();
        quad.delete();
        front.delete();
        back.delete();
        fbo.delete();

        Display.destroy();

    }


    private static class Program {

        private static class Shader {

            private final String code;
            private final int    type;

            private int          handle;


            public Shader(final String code, final int type) {

                this.code = code;
                this.type = type;

            }


            private void init() {

                handle = glCreateShader(type);
                glShaderSource(handle, code);
                glCompileShader(handle);

                if (glGetShader(handle, GL_COMPILE_STATUS) == GL_FALSE) {

                    final int length = glGetShader(handle, GL_INFO_LOG_LENGTH);
                    System.err.println(glGetShaderInfoLog(handle, length));

                    handle = -1;

                }

            }


            private void attach(final int program) {

                glAttachShader(program, handle);

            }


            private void detach(final int program) {

                glDetachShader(program, handle);

            }


            private void delete() {

                glDeleteShader(handle);

            }

        }

        private final Shader[] shaders;

        private int            handle;

        private int            textureBinding;
        private int            vboLocation;


        public Program(final Shader... shaders) {

            this.shaders = shaders;

        }


        public void init() {

            handle = glCreateProgram();

            for (final Shader shader : shaders) {

                shader.init();
                shader.attach(handle);

            }

            glLinkProgram(handle);

            textureBinding = glGetUniformLocation(handle, "texture");
            vboLocation = glGetAttribLocation(handle, "position");

            if (glGetProgram(handle, GL_LINK_STATUS) == GL_FALSE) {

                final int length = glGetProgram(handle, GL_INFO_LOG_LENGTH);
                System.err.println(glGetProgramInfoLog(handle, length));

                handle = -1;

            }

            for (final Shader shader : shaders) {

                shader.detach(handle);
                shader.delete();

            }

        }


        public void use() {

            glUseProgram(handle);

        }


        public void delete() {

            glDeleteProgram(handle);

        }


        public int getTextureBinding() {

            return textureBinding;

        }


        public int getVBOLocation() {

            return vboLocation;

        }

    }


    private static class Quad {

        private static final float[] QUAD = new float[] { -1, -1, +1, +1, -1, +1, -1, -1, +1, -1, +1, +1 };

        private int                  vao;
        private int                  handle;


        public void init() {

            final FloatBuffer quad = BufferUtils.createFloatBuffer(QUAD.length);
            quad.put(QUAD);
            quad.rewind();

            vao = glGenVertexArrays();
            glBindVertexArray(vao);

            handle = glGenBuffers();
            glBindBuffer(GL_ARRAY_BUFFER, handle);
            glBufferData(GL_ARRAY_BUFFER, quad, GL_STATIC_DRAW);


        }


        public void draw(final Program program) {

            glBindVertexArray(vao);

            glEnableVertexAttribArray(program.getVBOLocation());
            glVertexAttribPointer(program.getVBOLocation(), 2, GL_FLOAT, false, 0, 0);

            glDrawArrays(GL_TRIANGLES, 0, 6);

        }


        public void delete() {

            glDeleteBuffers(handle);

        }

    }


    private static class Texture {

        private int handle;


        public void init() {

            final Random random = new Random(0);
            final IntBuffer data = BufferUtils.createIntBuffer(WIDTH * HEIGHT);
            for (int i = 0; i < data.capacity(); i++)
                if (random.nextInt(100) > 90)
                    data.put(i, COLOR);

            handle = glGenTextures();
            glBindTexture(GL_TEXTURE_2D, handle);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
            glTexImage2D(GL_TEXTURE_2D, 0, GL11.GL_RGBA8, Display.getDisplayMode().getWidth(), Display.getDisplayMode().getHeight(), 0, GL12.GL_BGRA, GL_UNSIGNED_BYTE, data);

        }


        public void bind(final Program program) {

            glBindTexture(GL_TEXTURE_2D, handle);
            glUniform1i(program.getTextureBinding(), 0);

        }


        public void attachToFBO() {

            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, handle, 0);

        }


        public void delete() {

            glDeleteTextures(handle);

        }

    }

    private static class FBO {

        private int handle;


        public void init() {

            handle = glGenFramebuffers();


        }


        public void bind() {

            glBindFramebuffer(GL_FRAMEBUFFER, handle);

        }


        public void unbind() {

            glBindFramebuffer(GL_FRAMEBUFFER, 0);

        }


        public void delete() {

            glDeleteFramebuffers(handle);

        }

    }


    public static void main(final String[] args) throws LWJGLException, UnsupportedEncodingException {

        final LegacyGPUConway main = new LegacyGPUConway();

        main.init();
        main.display();

    }

}

(Merkwürdig das das hier auch ohne läuft, ich hasse sowas....)

Viele Grüße,
Fancy
 

GUI-Programmer

Top Contributor
Ich habe eine ATI Radeon HD 5700 Series mit 2747 MB insgesamt verfügbaren Grafikspeicher.

[OT]
Habe erst einen "Grafik-Total-Crash" hinter mir. Folgendes Szenario:

Angefangen hat alles erst damit, dass seit etwa Mitte - Ende Februar (02.2012) nach Systemstart die Meldung kommt: "Ati Catalyst Control Center: Host Application funktioniert nicht mehr". Allerdings sah alles noch wie vorher aus (also --> keine Problem). Internetrecherchen haben mich dann schließlich dazu gebracht den Grafiktreiber zu aktualisieren. Also: Alten Grafiktreiber deinstallieren (Systemsteuerung > Programm deinstallieren > ATI Catalyst Control Center), dann mit Driver Cleaner auch noch den Rest von ATI entfernen und dann den heruntergeladenen Treiber installieren. Hingegen Ende der Installtion flackerte mein Bildschirm für etwa 5 Sekunden lang und Windows ist abgestürzt. Nach einen neuen Systemstart dann das Schreckliche: Alles wurde viel zu groß angezeigt (maximale Auflösung war 1400 x irgendwas). :shock: Also das ganze von vorn. Diesmal kein Abbruch der Installtion, allerdings nach Systemneustart war die Auflösung zwar wieder 1920 x 1080 laut System, jedoch zentriert, sodass oben, links, rechts und unten jeweils ein schwarzer Rand war. Danach hat es mir entgültig gelangt. :mad:
Systemwiederherstellung vor der Treiberaktualisierung ausgeführt, und nun passte "von Seiten der Grafik" wieder alles, fast wie vorher, nur kommt komischerweise die Fehlermeldung nach Systemstart nicht mehr !?! ???:L

Jedoch gabs dann noch Probleme mit Norton Internet Security :mad: --> Update auf 2012 und auch das war wieder in Ordnung!!!

Das ganze hatte sich ziemlich lange hingezogen :gaen: (2-3 Stunden, dank Downloadgeschwindikeit von 70Kb/s; mittlereweile nachts halb 3) aber schließlich war nun endlich wieder alles so wie es sein sollte. :toll:
[/OT]
 
G

Guest2

Gast
Also normalerweise sollten die HD5700er das problemlos packen. Imho stimmt immer noch was nicht mit Deinem Treiber. Normalerweise würde ich dann empfehlen den aktuellen Treiber zu installieren... aber da das bei Dir beim letzten mal so ins chaos abgedriftet ist... must Du wissen :D

Normalerweise hier saugen, installieren, fertig. Vorher zu deinstallieren ist dabei unnötig.

Viele Grüße,
Fancy
 

GUI-Programmer

Top Contributor
Also normalerweise sollten die HD5700er das problemlos packen. Imho stimmt immer noch was nicht mit Deinem Treiber. Normalerweise würde ich dann empfehlen den aktuellen Treiber zu installieren... aber da das bei Dir beim letzten mal so ins chaos abgedriftet ist... must Du wissen :D

Normalerweise hier saugen, installieren, fertig. Vorher zu deinstallieren ist dabei unnötig.

Viele Grüße,
Fancy

Werds nochmals probieren, so wie du es sagst, ohne vorherige Deinstallation - nur diesmal mir nen Wiederherstellungspunkt manuell einrichten...

[EDIT]
Das selbe schreckliche Ergebnis:

Nach misslunger Grafikreiberinstallation:
Nach%20misslunger%20Grafikreiberinstallation.jpg


Nach gelunger Systemwiederherstellung:
Nach%20Systemwiederherstellung.jpg


[/EDIT]
 
Zuletzt bearbeitet:

Marco13

Top Contributor
Hab' nochmal geschaut wegen der OpenCL-Implementierung: Erstmal ist das ein ziemliches Gefrickel (bzw. um es "flüssig runterimplementieren" zu können hätte man Dinge wissen müssen, die ich nicht wußte - z.B. dass "write_imageui" schlicht und einfach keine Auswirkung hat wenn das Image aus einer OpenGL-Textur erstellt wurde :autsch: ich würde sagen, dass ist ein Bug...). Und wenn es dann (mit write_imagef) funktioniert, ist es relativ langsam: 300 FPS auf meiner GeForce 8800 (im Vergleich zu 750 mit dem GLSL-Beispiel). Das ist wohl "lokaler" - man hantiert ja nur mit FBOs und Texturen rum (und die sind das gleiche). Ich werd' aber trotzdem mal zusehen, ob ich den "PixelRenderer" irgendwann fertig bekomme (auch wenn es inzwischen 3 Wege gibt, die Daten rüberzuschaufeln: Mit einer Textur, mit einem PBO oder mit einem gemappten IntBuffer - mal sehen, wie man das unter einen Hut bringen kann :reflect: ).
 
G

Guest2

Gast
Das klingt ja nicht sonderlich prickelnd, also weder von der Architektur noch von der Performance. Hm, das ist dann natürlich blöde...

Viele Grüße,
Fancy
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
J Game of Life Randproblematik Allgemeine Java-Themen 9
S Conway's Game of Life Logarithmiusfehler Allgemeine Java-Themen 16
B Game of life Ein und Ausgabe Configurations Datei Allgemeine Java-Themen 17
Q Game of Life "unendlichkeits" Problem Allgemeine Java-Themen 4
T Game of Life Aktualität? Allgemeine Java-Themen 4
Kirby.exe Framework für Game Design Allgemeine Java-Themen 8
B Game Of Live Allgemeine Java-Themen 4
T Java Game Development Buch Allgemeine Java-Themen 10
J Erste Schritte Mehrere Mauszeiger für Ping Pong Game Allgemeine Java-Themen 7
C game-server GUI erstellen Allgemeine Java-Themen 13
T Tile Game Performance Allgemeine Java-Themen 32
B Starthilfe 2D Game Allgemeine Java-Themen 5
rode45e Java Threads Allgemeine Java-Themen 4
M Threads Allgemeine Java-Themen 1
L Threads Threads in Chatroom Allgemeine Java-Themen 30
berserkerdq2 run-methode eines Threads so programmieren, dass 30x die Sekunde etwas ausgeführt wird. Allgemeine Java-Themen 44
berserkerdq2 Threads, wie genau läuft das in Java ab? (Ich kann Threads erstellen und nutzen, nur das Verständnis) Allgemeine Java-Themen 6
CptK Backpropagation parallelisieren: Kommunikation zwischen den Threads Allgemeine Java-Themen 7
J Eine Frage zu den Threads und Task Allgemeine Java-Themen 1
W Wieviele Threads sind sinnvoll? Allgemeine Java-Themen 8
W Alternative für Threads Allgemeine Java-Themen 6
V Threads Probleme beim Aufrufen von Methoden einer anderen Klasse (Threads) Allgemeine Java-Themen 14
T Multithreading: Wie viele Threads sollte ich erstellen? Allgemeine Java-Themen 12
G Threads vom Mainprogramm steuern Allgemeine Java-Themen 8
S BlockingQueue mit dynamischer Anpassung der Anzahl von Producer und Consumer Threads Allgemeine Java-Themen 1
x46 Threads Threads anhalten Allgemeine Java-Themen 1
J Threads verbessern die Performance NICHT ? Allgemeine Java-Themen 8
W Threads Problem Allgemeine Java-Themen 15
T Threads Tic Tac Toe mit Threads Allgemeine Java-Themen 1
M Threads über Kommandozeile Allgemeine Java-Themen 5
mrbig2017 Threads Chat Programm mit Threads? Allgemeine Java-Themen 2
J Threads - java.lang.IllegalThreadStateException Allgemeine Java-Themen 6
J Internet Broswer in Threads öffnen Allgemeine Java-Themen 1
B Threads Multithreading Threads sollen warten Allgemeine Java-Themen 12
N 1000 MQTT Messages die Sekunde - 1000 Threads erstellen ? Allgemeine Java-Themen 10
D Threads Parallel laufende Threads Allgemeine Java-Themen 4
J Unvorhersehbares Verhalten - benutze ich die falsche Bedingungsprüfung oder brauche ich Threads? Allgemeine Java-Themen 12
D Eine Forschleife mit Threads abarbeiten um es zu schneller zu machen. Ist das möglich? Allgemeine Java-Themen 20
S Wie kann ich eine kleine Stelle in meinem Code mit multiplen Threads abarbeiten..? Allgemeine Java-Themen 20
P Threads Parallelisierte DB-Abfragen mit variabler Anzahl an Threads Allgemeine Java-Themen 4
J Threads Threads Allgemeine Java-Themen 9
Viktim Threads Liste In unterschiedlichen Threads bearbeiten Allgemeine Java-Themen 23
E Threads Ausführung in Threads ist langsamer als ohne Threads Allgemeine Java-Themen 13
A Anzahl an Threads Systemweit Allgemeine Java-Themen 2
Tausendsassa Input/Output Problem mit der gleichzeitigen Ausgabe zweier Threads Allgemeine Java-Themen 8
S Alle Methodenaufrufe eines Threads notieren..? Allgemeine Java-Themen 7
M Threads JPanel eingeforen mit Threads Allgemeine Java-Themen 2
F Threads Allgemeine Java-Themen 6
F Threads Allgemeine Java-Themen 2
M Sinn von Threads? Allgemeine Java-Themen 1
J Wie erschaffe ich einen sicheren Datenaustausch zwischen Thread und Nicht-Threads Allgemeine Java-Themen 8
L Abfragen ob Threads fertig Allgemeine Java-Themen 3
P Threads Java Zugreifen Allgemeine Java-Themen 6
K Problem: Java-Klasse mit mehreren Threads als eigenen Prozess starten Allgemeine Java-Themen 3
K KeyEvent in Threads Allgemeine Java-Themen 11
V Threads Weshalb funktionieren meine Threads nicht? Allgemeine Java-Themen 2
Thallius Speicherverhalten von Properties und mehreren Threads Allgemeine Java-Themen 5
L Threads beenden Allgemeine Java-Themen 4
P Threads Threads nicht gleichzeitig starten Allgemeine Java-Themen 3
S Threads Threads werden nicht beendet Allgemeine Java-Themen 2
S Start des zweiten Threads erst nach Beenden des ersten Threads Allgemeine Java-Themen 13
N Threads statische Methoden in Threads Allgemeine Java-Themen 5
P 4 Threads in einer Methode Allgemeine Java-Themen 2
M Eclipse Mehrere Threads, mehrere Konsolen Allgemeine Java-Themen 4
OnDemand Threads und synchronized Allgemeine Java-Themen 9
R LinkedList und Threads: Strukturprobleme bez. löschen von Elementen Allgemeine Java-Themen 3
R LinkedList und Threads - welche Methode ist besser? Allgemeine Java-Themen 2
OnDemand Threads und synvhronized Allgemeine Java-Themen 2
S Problem mit Threads Allgemeine Java-Themen 1
W Threads Threads warten lassen Allgemeine Java-Themen 5
H Optimierung durch Threads Allgemeine Java-Themen 31
B Threads halten sich irgendwie auf... Allgemeine Java-Themen 6
M Threads Allgemeine Java-Themen 8
K JNI: Methoden aus unterschiedlichen Threads aufrufen Allgemeine Java-Themen 3
A Applet Alle Threads beim schließen des Applets beenden Allgemeine Java-Themen 8
A Problem mit der Synchronisierung von Threads Allgemeine Java-Themen 15
R SecurityManager für einzelne Klassen/Threads? Allgemeine Java-Themen 38
O Threads und If Befehle Allgemeine Java-Themen 7
P Threads abwechseln lassen mit wait() und notify() Allgemeine Java-Themen 2
H Sehr viele Threads effizient Verwalten Allgemeine Java-Themen 13
C Threads und Exceptions Allgemeine Java-Themen 7
H java.lang.OutOfMemoryError bei der wiederholten Erzeugng von Threads Allgemeine Java-Themen 8
S Threads Abarbeitungsstatus von Threads in Datei schreiben Allgemeine Java-Themen 2
M Zugriff zweier Threads auf diesselbe Methode Allgemeine Java-Themen 16
E Threads Sudoku Threads Allgemeine Java-Themen 8
M Java Threads - Wait Notify - Verständnisproblem Allgemeine Java-Themen 5
Gossi Threads mit unterschiedlichen Aufgaben in einer Klasse? Allgemeine Java-Themen 9
G Threads Ablauf von Threads im Spezialfall Allgemeine Java-Themen 4
V Threads bei quadcore Allgemeine Java-Themen 10
V 1000 Threads oder Iterativ? Allgemeine Java-Themen 11
4 Simple(?) Frage zu Threads Allgemeine Java-Themen 14
R Threads Exceptions von Threads abfangen im ThreadPool Allgemeine Java-Themen 5
S Threads Ende sämtlicher Threads abwarten Allgemeine Java-Themen 6
S Frage zu Threads (Sichtbarkeit und Verhalten) Allgemeine Java-Themen 11
M Java-Threads und Datentypen-Zugriffe Allgemeine Java-Themen 7
P Threads- Programming Allgemeine Java-Themen 2
G Threads Klasse Sound und Threads bleiben hängen Allgemeine Java-Themen 4
C Threads Zwei Threads greifen auf LinkedList zu. Allgemeine Java-Themen 12
M OutOfMemoryError in nebenläufigen Threads Allgemeine Java-Themen 6
M Threads dauerhafte bewegung mit threads Allgemeine Java-Themen 11

Ähnliche Java Themen

Neue Themen


Oben