diff options
author | Sven Gothel <[email protected]> | 2012-07-22 04:16:55 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2012-07-22 04:16:55 +0200 |
commit | 4b5a0f6557d7152ec770bc13ad3c494449de0529 (patch) | |
tree | 12fc93f9e7f34b61c1d5748f0e6a1cd85fc6125b /src/test/com/jogamp/opengl | |
parent | adc9522ccaff74eb779d4d33905d76d52acb36bb (diff) |
Fix Bug 606 - New AWT threading implementation breaks .. ; Fix GLAutoDrawable multi-threading w/ proper pattern (hope so)
Considering code changes and remarks:
3ed491213f8f7f05d7b9866b50d764370d8ff5f6
1a91ec5c8b6fd9d9db7bc115569c369fe7b38e9b
3334a924309a9361a448d69bc707d4cce416b430
4f27bcecf7484dc041551f52a5c49e2884cb3867
It seems necessary to have
- recursive locking employed for all semantic actions which changes drawable & context (and the Window resource)
- to avoid deadlock, we have to ensure the locked code segment will not spawn
off to another thread, or a thread holds the lock, spawns of an action requiring the lock. .. sure
- other read-only methods (flags, ..) shall at least utilize a safe local copy of a volatile field
if further use to produce the result is necessary.
- flags like sendReshape require to be volatile to guarantee it's being processed
Patch impacts: AWT/SWT GLCanvas, GLAutoDrawableBase [and it's specializations]
and hopefully closes any loopholes of missing a cache hit, etc.
If you review this and find optimizations, i.e. removing a lock due to semantics etc,
don't hold back and discuss it, please.
Diffstat (limited to 'src/test/com/jogamp/opengl')
3 files changed, 78 insertions, 34 deletions
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateNEWT.java index eb716677d..426b7734f 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateNEWT.java @@ -87,8 +87,8 @@ public class TestGLAutoDrawableDelegateNEWT extends UITestCase { final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(drawable, context, window) { @Override - public void destroy() { - super.destroy(); // destroys drawable/context + protected void destroyImplInLock() { + super.destroyImplInLock(); // destroys drawable/context window.destroy(); // destroys the actual window } }; @@ -97,15 +97,15 @@ public class TestGLAutoDrawableDelegateNEWT extends UITestCase { window.addWindowListener(new WindowAdapter() { @Override public void windowRepaint(WindowUpdateEvent e) { - glad.defaultWindowRepaintOp(); + glad.windowRepaintOp(); } @Override public void windowResized(WindowEvent e) { - glad.defaultWindowResizedOp(); + glad.windowResizedOp(); } @Override public void windowDestroyNotify(WindowEvent e) { - glad.defaultWindowDestroyNotifyOp(); + glad.windowDestroyNotifyOp(); } }); window.addWindowListener(wl); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java index 06aa29b4f..92b4c5238 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java @@ -90,8 +90,8 @@ public class TestGLContextDrawableSwitchNEWT extends UITestCase { final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(drawable, null, window) { @Override - public void destroy() { - super.destroy(); // destroys drawable/context + protected void destroyImplInLock() { + super.destroyImplInLock(); window.destroy(); // destroys the actual window } }; @@ -100,15 +100,15 @@ public class TestGLContextDrawableSwitchNEWT extends UITestCase { window.addWindowListener(new WindowAdapter() { @Override public void windowRepaint(WindowUpdateEvent e) { - glad.defaultWindowRepaintOp(); + glad.windowRepaintOp(); } @Override public void windowResized(WindowEvent e) { - glad.defaultWindowResizedOp(); + glad.windowResizedOp(); } @Override public void windowDestroyNotify(WindowEvent e) { - glad.defaultWindowDestroyNotifyOp(); + glad.windowDestroyNotifyOp(); } }); window.addWindowListener(wl); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextSurfaceLockNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextSurfaceLockNEWT.java index 78988c0e5..b3516d6b4 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextSurfaceLockNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextSurfaceLockNEWT.java @@ -33,9 +33,9 @@ import java.io.IOException; import javax.media.nativewindow.NativeSurface; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLEventListener; import javax.media.opengl.GLProfile; -import org.junit.Assert; import org.junit.Test; import com.jogamp.newt.opengl.GLWindow; @@ -69,7 +69,7 @@ public class TestGLContextSurfaceLockNEWT extends UITestCase { } public void run() { - System.err.println("Animatr "+id+": PRE: "+Thread.currentThread().getName()); + System.err.println("Animatr "+id+", count "+frameCount+": PRE: "+Thread.currentThread().getName()); for(int c=0; c<frameCount; c++) { glad.display(); @@ -99,10 +99,10 @@ public class TestGLContextSurfaceLockNEWT extends UITestCase { } public void run() { - System.err.println("Resizer "+id+": PRE: "+Thread.currentThread().getName()); + System.err.println("Resizer "+id+", count "+actionCount+": PRE: "+Thread.currentThread().getName()); for(int c=0; c<actionCount; c++) { - win.runOnEDTIfAvail(false, new Runnable() { + win.runOnEDTIfAvail(true, new Runnable() { public void run() { // Normal resize, may trigger immediate display within lock win.setSize(win.getWidth()+1, win.getHeight()+1); @@ -148,41 +148,80 @@ public class TestGLContextSurfaceLockNEWT extends UITestCase { return true; } + protected class MyEventCounter implements GLEventListener { + volatile int reshapeCount = 0; + volatile int displayCount = 0; + + @Override + public void init(GLAutoDrawable drawable) { + } + + @Override + public void dispose(GLAutoDrawable drawable) { + System.err.println("*** reshapes: "+reshapeCount+", displays "+displayCount); + } + + @Override + public void display(GLAutoDrawable drawable) { + displayCount++; + } + + @Override + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { + reshapeCount++; + } + + public void reset() { + reshapeCount = 0; + displayCount = 0; + } + } + protected void runJOGLTasks(int animThreadCount, int frameCount, int reszThreadCount, int resizeCount) throws InterruptedException { - GLWindow glWindow = GLWindow.create(new GLCapabilities(GLProfile.getDefault())); - Assert.assertNotNull(glWindow); + final GLWindow glWindow = GLWindow.create(new GLCapabilities(GLProfile.getDefault())); + final MyEventCounter myEventCounter = new MyEventCounter(); glWindow.addGLEventListener(new GearsES2(0)); + glWindow.addGLEventListener(myEventCounter); glWindow.setSize(demoSize, demoSize); glWindow.setVisible(true); final String currentThreadName = Thread.currentThread().getName(); final Object sync = new Object(); - final MyRunnable[] tasks = new MyRunnable[animThreadCount+reszThreadCount]; - final Thread[] threads = new Thread[animThreadCount+reszThreadCount]; - int i=0; + final MyRunnable[] animTasks = new MyRunnable[animThreadCount]; + final MyRunnable[] resizeTasks = new MyRunnable[animThreadCount]; + final Thread[] animThreads = new Thread[reszThreadCount]; + final Thread[] resizeThreads = new Thread[reszThreadCount]; System.err.println("animThreadCount "+animThreadCount+", frameCount "+frameCount); System.err.println("reszThreadCount "+reszThreadCount+", resizeCount "+resizeCount); - System.err.println("tasks "+tasks.length+", threads "+threads.length); + System.err.println("tasks "+(animTasks.length+resizeTasks.length)+", threads "+(animThreads.length+resizeThreads.length)); - for(; i<animThreadCount; i++) { + for(int i=0; i<animThreadCount; i++) { System.err.println("create anim task/thread "+i); - tasks[i] = new RudeAnimator(glWindow, frameCount, sync, i); - threads[i] = new Thread(tasks[i], currentThreadName+"-anim"+i); + animTasks[i] = new RudeAnimator(glWindow, frameCount, sync, i); + animThreads[i] = new Thread(animTasks[i], currentThreadName+"-anim"+i); } - for(; i<animThreadCount+reszThreadCount; i++) { + for(int i=0; i<reszThreadCount; i++) { System.err.println("create resz task/thread "+i); - tasks[i] = new RudeResizer(glWindow, resizeCount, sync, i); - threads[i] = new Thread(tasks[i], currentThreadName+"-resz"+i); + resizeTasks[i] = new RudeResizer(glWindow, resizeCount, sync, i); + resizeThreads[i] = new Thread(resizeTasks[i], currentThreadName+"-resz"+i); } - for(i=0; i<animThreadCount+reszThreadCount; i++) { - System.err.println("start thread "+i); - threads[i].start(); + myEventCounter.reset(); + + int j=0, k=0; + for(int i=0; i<reszThreadCount+animThreadCount; i++) { + if(0==i%2) { + System.err.println("start resize thread "+j); + resizeThreads[j++].start(); + } else { + System.err.println("start anim thread "+k); + animThreads[k++].start(); + } } synchronized (sync) { - while(!done(tasks)) { + while(!done(resizeTasks) || !done(animTasks)) { try { sync.wait(); } catch (InterruptedException e) { @@ -190,8 +229,8 @@ public class TestGLContextSurfaceLockNEWT extends UITestCase { } } } - i=0; - while(i<30 && !isDead(threads)) { + int i=0; + while(i<30 && !isDead(animThreads) && !isDead(resizeThreads)) { Thread.sleep(100); i++; } @@ -200,8 +239,13 @@ public class TestGLContextSurfaceLockNEWT extends UITestCase { } @Test - public void test01_1AThreads_600Frames() throws InterruptedException { - runJOGLTasks(1, 600, 1, 600); + public void test01_1A1RThreads_100Resizes() throws InterruptedException { + runJOGLTasks(1, 200, 1, 100); + } + + @Test + public void test01_3A3RThreads_50Resizes() throws InterruptedException { + runJOGLTasks(3, 100, 3, 50); } public static void main(String args[]) throws IOException { |