JOGL v2.6.0-rc-20250706
JOGL, High-Performance Graphics Binding for Java™ (public API).
TestSWTBug643AsyncExec.java
Go to the documentation of this file.
1/**
2 * Copyright 2012 JogAmp Community. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification, are
5 * permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * The views and conclusions contained in the software and documentation are those of the
25 * authors and should not be interpreted as representing official policies, either expressed
26 * or implied, of JogAmp Community.
27 */
28
29package com.jogamp.opengl.test.junit.jogl.swt;
30
31import java.lang.reflect.InvocationTargetException;
32
33import org.eclipse.swt.SWT ;
34
35import org.eclipse.swt.layout.FillLayout ;
36
37import org.eclipse.swt.widgets.Composite ;
38import org.eclipse.swt.widgets.Display ;
39import org.eclipse.swt.widgets.Shell ;
40
41import org.junit.Assert;
42import org.junit.Assume;
43import org.junit.Test;
44import org.junit.FixMethodOrder;
45import org.junit.runners.MethodSorters;
46
47import com.jogamp.opengl.GLAutoDrawable;
49import com.jogamp.opengl.GLProfile;
50
51import jogamp.newt.swt.SWTEDTUtil;
52import jogamp.newt.swt.event.SWTNewtEventFactory;
53
54import com.jogamp.common.util.InterruptSource;
55import com.jogamp.nativewindow.swt.SWTAccessor;
56import com.jogamp.newt.NewtFactory;
59import com.jogamp.opengl.swt.GLCanvas;
60import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
61import com.jogamp.opengl.test.junit.util.MiscUtils;
62import com.jogamp.opengl.test.junit.util.NewtTestUtil;
63import com.jogamp.opengl.test.junit.util.SWTTestUtil;
64import com.jogamp.opengl.test.junit.util.TestUtil;
65import com.jogamp.opengl.test.junit.util.UITestCase;
66import com.jogamp.opengl.util.Animator;
67
68////////////////////////////////////////////////////////////////////////////////
69
70
71@FixMethodOrder(MethodSorters.NAME_ASCENDING)
72public class TestSWTBug643AsyncExec extends UITestCase {
73
74 static int duration = 500;
75 static boolean useAnimator = false;
76
77 ////////////////////////////////////////////////////////////////////////////////
78
79 static void resetSWTAndNEWTEDTCounter() {
80 synchronized(swtCountSync) {
81 swtCount=0;
82 }
83 synchronized(edtCountSync) {
84 edtCount=0;
85 }
86 }
87 static int incrSWTCount() {
88 synchronized(swtCountSync) {
89 swtCount++;
90 return swtCount;
91 }
92 }
93 static int getSWTCount() {
94 synchronized(swtCountSync) {
95 return swtCount;
96 }
97 }
98 static int incrNEWTCount() {
99 synchronized(edtCountSync) {
100 edtCount++;
101 return edtCount;
102 }
103 }
104 static int getNEWTCount() {
105 synchronized(edtCountSync) {
106 return edtCount;
107 }
108 }
109 static Object swtCountSync = new Object();
110 static int swtCount = 0;
111 static Object edtCountSync = new Object();
112 static int edtCount = 0;
113
114 ////////////////////////////////////////////////////////////////////////////////
115
116 static class AsyncExecEDTFeederThread extends InterruptSource.Thread {
117 volatile boolean shallStop = false;
118 private final Display swtDisplay ;
119 private final jogamp.newt.DisplayImpl newtDisplay;
120 private int swtN, newtN ;
121
122 public AsyncExecEDTFeederThread( final Display swtDisplay, final com.jogamp.newt.Display newtDisplay )
123 {
124 this.swtDisplay = swtDisplay ;
125 this.newtDisplay = (jogamp.newt.DisplayImpl)newtDisplay;
126 }
127
128 final Runnable swtAsyncAction = new Runnable() {
129 public void run()
130 {
131 ++swtN ; incrSWTCount();
132 System.err.println("[SWT A-i shallStop "+shallStop+"]: Counter[loc "+swtN+", glob: "+getSWTCount()+"]");
133 } };
134
135 final Runnable newtAsyncAction = new Runnable() {
136 public void run()
137 {
138 ++newtN ; incrNEWTCount();
139 System.err.println("[NEWT A-i shallStop "+shallStop+"]: Counter[loc "+newtN+", glob: "+getNEWTCount()+"]");
140 } };
141
142 public void run()
143 {
144 System.err.println("[A-0 shallStop "+shallStop+"]");
145
146 while( !shallStop && !swtDisplay.isDisposed() )
147 {
148 try
149 {
150 if( !swtDisplay.isDisposed() ) {
151 swtDisplay.asyncExec( swtAsyncAction );
152 }
153 if(null != newtDisplay && newtDisplay.isNativeValid() && newtDisplay.getEDTUtil().isRunning()) {
154 // only perform async exec on valid and already running NEWT EDT!
155 newtDisplay.runOnEDTIfAvail(false, newtAsyncAction);
156 }
157 java.lang.Thread.sleep( 50L ) ;
158 } catch( final InterruptedException e ) {
159 break ;
160 }
161 }
162 System.err.println("*R-Exit* shallStop "+shallStop);
163 }
164 }
165
166 ////////////////////////////////////////////////////////////////////////////////
167
168 private volatile boolean shallStop = false;
169
170 static class SWT_DSC {
171 Display display;
172 Shell shell;
173 Composite composite;
174
175 public void init() {
176 SWTAccessor.invokeOnOSTKThread(true, new Runnable() {
177 public void run() {
178 display = new Display();
179 Assert.assertNotNull( display );
180 }});
181
182 display.syncExec(new Runnable() {
183 public void run() {
184 shell = new Shell( display );
185 Assert.assertNotNull( shell );
186 shell.setLayout( new FillLayout() );
187 composite = new Composite( shell, SWT.NO_BACKGROUND );
188 composite.setLayout( new FillLayout() );
189 Assert.assertNotNull( composite );
190 }});
191 }
192
193 public void dispose() {
194 Assert.assertNotNull( display );
195 Assert.assertNotNull( shell );
196 Assert.assertNotNull( composite );
197 try {
198 display.syncExec(new Runnable() {
199 public void run() {
200 composite.dispose();
201 shell.dispose();
202 }});
203 SWTAccessor.invokeOnOSTKThread(true, new Runnable() {
204 public void run() {
205 display.dispose();
206 }});
207 }
208 catch( final Throwable throwable ) {
209 throwable.printStackTrace();
210 Assume.assumeNoException( throwable );
211 }
212 display = null;
213 shell = null;
214 composite = null;
215 }
216 }
217
218 private void testImpl(final boolean useJOGLGLCanvas, final boolean useNewtCanvasSWT, final boolean glWindowPreVisible) throws InterruptedException, InvocationTargetException {
219 resetSWTAndNEWTEDTCounter();
220
221 final SWT_DSC dsc = new SWT_DSC();
222 dsc.init();
223
224 final com.jogamp.newt.Display newtDisplay;
225 {
226 final GLProfile gl2Profile = GLProfile.get( GLProfile.GL2 ) ;
227 final GLCapabilities caps = new GLCapabilities( gl2Profile ) ;
228
229 final GLAutoDrawable glad;
230 if( useJOGLGLCanvas ) {
231 final GearsES2 demo = new GearsES2();
232 final GLCanvas glc = GLCanvas.create(dsc.composite, 0, caps, null);
233 final SWTNewtEventFactory swtNewtEventFactory = new SWTNewtEventFactory();
234 dsc.display.syncExec(new Runnable() {
235 @Override
236 public void run() {
237 swtNewtEventFactory.attachDispatchListener(glc, glc, demo.gearsMouse, demo.gearsKeys);
238 } } );
239 glc.addGLEventListener( demo ) ;
240 glad = glc;
241 newtDisplay = null;
242 } else if( useNewtCanvasSWT ) {
243 newtDisplay = NewtFactory.createDisplay(null, false); // no-reuse
244 final com.jogamp.newt.Screen screen = NewtFactory.createScreen(newtDisplay, 0);
245 final GLWindow glWindow = GLWindow.create( screen, caps ) ;
246 glWindow.addGLEventListener( new GearsES2() ) ;
247 if( glWindowPreVisible ) {
248 newtDisplay.setEDTUtil(new SWTEDTUtil(newtDisplay, dsc.display)); // Especially Windows requires creation access via same thread!
249 glWindow.setVisible(true);
250 NewtTestUtil.waitForRealized(glWindow, true, null);
251 Thread.sleep(120); // let it render a bit, before consumed by SWT
252 }
253 glad = glWindow;
254 NewtCanvasSWT.create( dsc.composite, 0, glWindow ) ;
255 } else {
256 throw new InternalError("XXX");
257 }
258 if(useAnimator) {
259 final Animator animator = new Animator(glad);
260 animator.start();
261 }
262 }
263
264 System.err.println("**** Pre Shell Open");
265 dsc.display.syncExec( new Runnable() {
266 public void run() {
267 dsc.shell.setText( "NewtCanvasSWT Resize Bug Demo" ) ;
268 dsc.shell.setSize( 400, 450 ) ;
269 dsc.shell.open() ;
270 } } );
271 System.err.println("**** Post Shell Open");
272
273 shallStop = false;
274
275 final int[] counterBeforeExit = new int[] { 0 /* SWT */, 0 /* NEWT */ };
276
277 final AsyncExecEDTFeederThread asyncExecFeeder;
278 {
279 asyncExecFeeder = new AsyncExecEDTFeederThread(dsc.display, newtDisplay) ;
280 asyncExecFeeder.start() ;
281 }
282
283 {
284 final Thread t = new InterruptSource.Thread(null, new Runnable() {
285 @Override
286 public void run() {
287 try {
288 Thread.sleep(duration);
289 } catch (final InterruptedException e) {}
290
291 counterBeforeExit[0] = getSWTCount();
292 counterBeforeExit[1] = getNEWTCount();
293 asyncExecFeeder.shallStop = true;
294 try
295 {
296 asyncExecFeeder.join();
297 } catch( final InterruptedException e ) { }
298 shallStop = true;
299 dsc.display.wake();
300 } } );
301 t.setDaemon(true);
302 t.start();
303 }
304
305 final SWTTestUtil.WaitAction generalWaitAction = new SWTTestUtil.WaitAction(dsc.display, true, 10);
306
307 try {
308 final Display d = dsc.display;
309 while( !shallStop && !d.isDisposed() ) {
310 generalWaitAction.run();
311 }
312 } catch (final Exception e0) {
313 e0.printStackTrace();
314 Assert.assertTrue("Deadlock @ dispatch: "+e0, false);
315 }
316
317 // canvas is disposed implicit, due to it's disposed listener !
318
319 dsc.dispose();
320
321 System.err.println("EDT Counter before exit: SWT " + counterBeforeExit[0] + ", NEWT "+counterBeforeExit[1]);
322 Assert.assertTrue("SWT EDT Counter not greater zero before dispose!", 0 < counterBeforeExit[0]);
323 if( null != newtDisplay ) {
324 Assert.assertTrue("NEWT EDT Counter not greater zero before dispose!", 0 < counterBeforeExit[1]);
325 }
326 }
327
328 @Test
329 public void test01JOGLGLCanvas() throws InterruptedException, InvocationTargetException {
330 testImpl(true /* useJOGLGLCanvas */, false /* useNewtCanvasSWT */, false /* glWindowPreVisible */);
331 }
332
333 @Test
334 public void test02NewtCanvasSWTSimple() throws InterruptedException, InvocationTargetException {
335 testImpl(false /* useJOGLGLCanvas */, true /* useNewtCanvasSWT */, false /* glWindowPreVisible */);
336 }
337
338 @Test
339 public void test02NewtCanvasSWTPreVisible() throws InterruptedException, InvocationTargetException {
340 testImpl(false /* useJOGLGLCanvas */, true /* useNewtCanvasSWT */, true /* glWindowPreVisible */);
341 }
342
343 public static void main( final String[] args ) {
344 for(int i=0; i<args.length; i++) {
345 if(args[i].equals("-time")) {
346 duration = MiscUtils.atoi(args[++i], duration);
347 } else if(args[i].equals("-anim")) {
348 useAnimator = true;
349 }
350 }
351 System.out.println("durationPerTest: "+duration);
352 org.junit.runner.JUnitCore.main(TestSWTBug643AsyncExec.class.getName());
353 }
354
355}
static void invokeOnOSTKThread(final boolean blocking, final Runnable runnable)
Runs the specified action in an SWT compatible OS toolkit thread, which is:
abstract EDTUtil setEDTUtil(EDTUtil usrEDTUtil)
Sets a new EDTUtil and returns the previous one.
static Display createDisplay(final String name)
Create a Display entity.
static Screen createScreen(final Display display, final int index)
Create a Screen entity.
A screen may span multiple MonitorDevices representing their combined virtual size.
Definition: Screen.java:58
An implementation of GLAutoDrawable and Window interface, using a delegated Window instance,...
Definition: GLWindow.java:121
final void setVisible(final boolean visible)
Calls setVisible(true, visible), i.e.
Definition: GLWindow.java:615
static GLWindow create(final GLCapabilitiesImmutable caps)
Creates a new GLWindow attaching a new Window referencing a new default Screen and default Display wi...
Definition: GLWindow.java:169
SWT Canvas containing a NEWT Window using native parenting.
static NewtCanvasSWT create(final Composite parent, final int style, final Window child)
Creates an instance using NewtCanvasSWT(Composite, int, Window) on the SWT thread.
Specifies a set of OpenGL capabilities.
Specifies the the OpenGL profile.
Definition: GLProfile.java:77
static GLProfile get(final AbstractGraphicsDevice device, String profile)
Returns a GLProfile object.
static final String GL2
The desktop OpenGL profile 1.x up to 3.0.
Definition: GLProfile.java:579
A heavyweight AWT component which provides OpenGL rendering support.
Definition: GLCanvas.java:170
void addGLEventListener(final GLEventListener listener)
Adds the given listener to the end of this drawable queue.
Definition: GLCanvas.java:1065
static int atoi(final String str, final int def)
Definition: MiscUtils.java:57
static boolean waitForRealized(final Screen screen, final boolean realized, final Runnable waitAction)
final synchronized boolean start()
Starts this animator, if not running.
Definition: Animator.java:344
A higher-level abstraction than GLDrawable which supplies an event based mechanism (GLEventListener) ...
void addGLEventListener(GLEventListener listener)
Adds the given listener to the end of this drawable queue.