JOGL v2.6.0-rc-20250706
JOGL, High-Performance Graphics Binding for Java™ (public API).
TestGLException01NEWT.java
Go to the documentation of this file.
1/**
2 * Copyright 2011 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.acore;
30
31import java.util.ArrayList;
32import java.util.List;
33import java.util.concurrent.atomic.AtomicInteger;
34
35import com.jogamp.newt.opengl.GLWindow;
36import com.jogamp.opengl.test.junit.util.MiscUtils;
37import com.jogamp.opengl.test.junit.util.UITestCase;
38import com.jogamp.opengl.util.Animator;
39import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
40
41import com.jogamp.opengl.GLAnimatorControl;
42import com.jogamp.opengl.GLAutoDrawable;
43import com.jogamp.opengl.GLCapabilities;
44import com.jogamp.opengl.GLEventListener;
45import com.jogamp.opengl.GLProfile;
46import com.jogamp.opengl.GLRunnable;
47
48import org.junit.Assert;
49import org.junit.BeforeClass;
50import org.junit.Test;
51import org.junit.FixMethodOrder;
52import org.junit.runners.MethodSorters;
53
54@FixMethodOrder(MethodSorters.NAME_ASCENDING)
55public class TestGLException01NEWT extends UITestCase {
56 static GLProfile glp;
57 static int width, height;
58
59 @SuppressWarnings("serial")
60 static class AnimException extends RuntimeException {
61 final Thread thread;
62 final GLAnimatorControl animator;
63 final GLAutoDrawable drawable;
64 public AnimException(final Thread thread, final GLAnimatorControl animator, final GLAutoDrawable drawable, final Throwable cause) {
65 super(cause);
66 this.thread = thread;
67 this.animator = animator;
68 this.drawable = drawable;
69 }
70 }
71
72 @BeforeClass
73 public static void initClass() {
74 glp = GLProfile.getGL2ES2();
75 Assert.assertNotNull(glp);
76 width = 512;
77 height = 512;
78 }
79
80 public static void dumpThrowable(final Throwable t) {
81 System.err.println("User caught exception "+t.getClass().getSimpleName()+": "+t.getMessage()+" on thread "+Thread.currentThread().getName());
82 t.printStackTrace();
83 }
84
85 protected void runTestGL(final GLCapabilities caps, final boolean onThread,
86 final boolean throwInInit, final boolean throwInDisplay,
87 final boolean throwInReshape, final boolean throwInInvoke,
88 final boolean throwInDispose) throws InterruptedException {
89 final GLWindow glWindow = GLWindow.create(caps);
90 Assert.assertNotNull(glWindow);
91 glWindow.setTitle(getTestMethodName());
92 final GearsES2 demo1 = new GearsES2();
93 demo1.setVerbose(false);
94 glWindow.addGLEventListener(demo1);
95 final AtomicInteger cleanInitCount = new AtomicInteger();
96 final AtomicInteger cleanDisposeCount = new AtomicInteger();
97 final AtomicInteger cleanDisplayCount = new AtomicInteger();
98 final AtomicInteger cleanReshapeCount = new AtomicInteger();
99 final AtomicInteger cleanInvokeCount = new AtomicInteger();
100 final AtomicInteger allInitCount = new AtomicInteger();
101 final AtomicInteger allDisposeCount = new AtomicInteger();
102 final AtomicInteger allDisplayCount = new AtomicInteger();
103 final AtomicInteger allReshapeCount = new AtomicInteger();
104 final AtomicInteger allInvokeCount = new AtomicInteger();
105 final AtomicInteger exceptionSent = new AtomicInteger();
106
107 glWindow.addGLEventListener(new GLEventListener() {
108 @Override
109 public void init(final GLAutoDrawable drawable) {
110 if( throwInInit ) {
111 exceptionSent.incrementAndGet();
112 throw new RuntimeException("<Injected GLEventListener exception in init: #"+exceptionSent.get()+" on thread "+Thread.currentThread().getName()+">");
113 }
114 }
115 @Override
116 public void dispose(final GLAutoDrawable drawable) {
117 if( throwInDispose ) {
118 exceptionSent.incrementAndGet();
119 throw new RuntimeException("<Injected GLEventListener exception in dispose: #"+exceptionSent.get()+" on thread "+Thread.currentThread().getName()+">");
120 }
121 }
122 @Override
123 public void display(final GLAutoDrawable drawable) {
124 if( throwInDisplay ) {
125 exceptionSent.incrementAndGet();
126 throw new RuntimeException("<Injected GLEventListener exception in display: #"+exceptionSent.get()+" on thread "+Thread.currentThread().getName()+">");
127 }
128 }
129 @Override
130 public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) {
131 if( throwInReshape ) {
132 exceptionSent.incrementAndGet();
133 throw new RuntimeException("<Injected GLEventListener exception in reshape: #"+exceptionSent.get()+" on thread "+Thread.currentThread().getName()+">");
134 }
135 }
136 });
137 final GLRunnable glRunnableInject = new GLRunnable() {
138 @Override
139 public boolean run(final GLAutoDrawable drawable) {
140 if( throwInInvoke ) {
141 exceptionSent.incrementAndGet();
142 throw new RuntimeException("<Injected GLEventListener exception in invoke: #"+exceptionSent.get()+" on thread "+Thread.currentThread().getName()+">");
143 }
144 return true;
145 }
146 };
147 final GLRunnable glRunnableCount = new GLRunnable() {
148 @Override
149 public boolean run(final GLAutoDrawable drawable) {
150 if( 0 == exceptionSent.get() ) {
151 cleanInvokeCount.incrementAndGet();
152 }
153 allInvokeCount.incrementAndGet();
154 return true;
155 }
156 };
157
158 glWindow.addGLEventListener(new GLEventListener() {
159 @Override
160 public void init(final GLAutoDrawable drawable) {
161 if( 0 == exceptionSent.get() ) {
162 cleanInitCount.incrementAndGet();
163 }
164 allInitCount.incrementAndGet();
165 }
166 @Override
167 public void dispose(final GLAutoDrawable drawable) {
168 if( 0 == exceptionSent.get() ) {
169 cleanDisposeCount.incrementAndGet();
170 }
171 allDisposeCount.incrementAndGet();
172 }
173 @Override
174 public void display(final GLAutoDrawable drawable) {
175 if( 0 == exceptionSent.get() ) {
176 cleanDisplayCount.incrementAndGet();
177 }
178 allDisplayCount.incrementAndGet();
179 }
180 @Override
181 public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) {
182 if( 0 == exceptionSent.get() ) {
183 cleanReshapeCount.incrementAndGet();
184 }
185 allReshapeCount.incrementAndGet();
186 }
187 });
188
189 RuntimeException exceptionAtInitReshapeDisplay = null;
190 RuntimeException exceptionAtInvoke = null;
191 RuntimeException exceptionAtDispose = null;
192 final List<AnimException> exceptionsAtGLAnimatorControl = new ArrayList<AnimException>();
193 final GLAnimatorControl.UncaughtExceptionHandler uncaughtExceptionHandler;
194
195 final Animator animator;
196 if( onThread ) {
197 animator = null;
198 uncaughtExceptionHandler = null;
199 } else {
200 animator = new Animator(glWindow);
201 uncaughtExceptionHandler = new GLAnimatorControl.UncaughtExceptionHandler() {
202 @Override
203 public void uncaughtException(final GLAnimatorControl animator, final GLAutoDrawable drawable, final Throwable cause) {
204 final AnimException ae = new AnimException(animator.getThread(), animator, drawable, cause);
205 exceptionsAtGLAnimatorControl.add(ae);
206 dumpThrowable(ae);
207 } };
208 animator.setUncaughtExceptionHandler(uncaughtExceptionHandler);
209 }
210
211 glWindow.setSize(width, height);
212
213 if( !onThread ) {
214 animator.setUpdateFPSFrames(1, null);
215 animator.start();
216 }
217 try {
218 glWindow.setVisible(true);
219 } catch (final RuntimeException re) {
220 exceptionAtInitReshapeDisplay = re;
221 dumpThrowable(re);
222 }
223
224 try {
225 glWindow.invoke(true, glRunnableInject);
226 glWindow.invoke(true, glRunnableCount);
227 } catch (final RuntimeException re) {
228 exceptionAtInvoke = re;
229 dumpThrowable(re);
230 }
231
232 final long t0 = System.currentTimeMillis();
233 long t1 = t0;
234 while(0 == exceptionSent.get() && ( onThread || animator.isAnimating() ) && t1-t0<duration ) {
235 if( onThread ) {
236 try {
237 glWindow.display();
238 } catch (final RuntimeException re) {
239 exceptionAtInitReshapeDisplay = re;
240 dumpThrowable(re);
241 }
242 }
243 Thread.sleep(100);
244 t1 = System.currentTimeMillis();
245 }
246
247 if( !onThread ) {
248 animator.stop();
249 }
250 try {
251 glWindow.destroy();
252 } catch (final RuntimeException re) {
253 exceptionAtDispose = re;
254 dumpThrowable(re);
255 }
256
257 final boolean onAnimThread = !onThread && !throwInDispose; /** dispose happens on [AWT|NEWT] EDT, not on animator thread! */
258
259 System.err.println("This-Thread : "+onThread);
260 System.err.println("Anim-Thread : "+onAnimThread);
261 System.err.println("ExceptionSent : "+exceptionSent.get());
262 System.err.println("Exception @ Init/Reshape/Display: "+(null != exceptionAtInitReshapeDisplay));
263 System.err.println("Exception @ Invoke : "+(null != exceptionAtInvoke));
264 System.err.println("Exception @ Dispose : "+(null != exceptionAtDispose));
265 System.err.println("Exception @ GLAnimatorControl : "+exceptionsAtGLAnimatorControl.size());
266 System.err.println("Init Count : "+cleanInitCount.get()+" / "+allInitCount.get());
267 System.err.println("Reshape Count : "+cleanReshapeCount.get()+" / "+allReshapeCount.get());
268 System.err.println("Display Count : "+cleanDisplayCount.get()+" / "+allDisplayCount.get());
269 System.err.println("Invoke Count : "+cleanInvokeCount.get()+" / "+allInvokeCount.get());
270 System.err.println("Dispose Count : "+cleanDisposeCount.get()+" / "+allDisposeCount.get());
271
272 if( throwInInit || throwInReshape || throwInDisplay || throwInDispose || throwInInvoke ) {
273 Assert.assertTrue("Not one exception sent, but "+exceptionSent.get(), 0 < exceptionSent.get());
274 if( onAnimThread ) {
275 Assert.assertEquals("No exception forwarded from init to animator-handler", 1, exceptionsAtGLAnimatorControl.size());
276 Assert.assertNull("Exception forwarded from init, on-thread", exceptionAtInitReshapeDisplay);
277 }
278 if( throwInInit ) {
279 if( !onAnimThread ) {
280 Assert.assertNotNull("No exception forwarded from init, on-thread", exceptionAtInitReshapeDisplay);
281 Assert.assertEquals("Exception forwarded from init to animator-handler", 0, exceptionsAtGLAnimatorControl.size());
282 }
283 Assert.assertEquals("Init Count", 0, cleanInitCount.get());
284 Assert.assertEquals("Reshape Count", 0, cleanReshapeCount.get());
285 Assert.assertEquals("Display Count", 0, cleanDisplayCount.get());
286 Assert.assertEquals("Invoke Count", 0, cleanInvokeCount.get());
287 Assert.assertEquals("Dispose Count", 0, cleanDisposeCount.get());
288 } else if( throwInReshape ) {
289 if( !onAnimThread ) {
290 Assert.assertNotNull("No exception forwarded from reshape, on-thread", exceptionAtInitReshapeDisplay);
291 Assert.assertEquals("Exception forwarded from init to animator-handler", 0, exceptionsAtGLAnimatorControl.size());
292 }
293 Assert.assertEquals("Init Count", 1, cleanInitCount.get());
294 Assert.assertEquals("Reshape Count", 0, cleanReshapeCount.get());
295 Assert.assertEquals("Display Count", 0, cleanDisplayCount.get());
296 Assert.assertEquals("Invoke Count", 0, cleanInvokeCount.get());
297 Assert.assertEquals("Dispose Count", 0, cleanDisposeCount.get());
298 } else if( throwInDisplay ) {
299 if( !onAnimThread ) {
300 Assert.assertNotNull("No exception forwarded from display, on-thread", exceptionAtInitReshapeDisplay);
301 Assert.assertEquals("Exception forwarded from init to animator-handler", 0, exceptionsAtGLAnimatorControl.size());
302 }
303 Assert.assertEquals("Init Count", 1, cleanInitCount.get());
304 Assert.assertEquals("Reshape Count", 1, cleanReshapeCount.get());
305 Assert.assertEquals("Display Count", 0, cleanDisplayCount.get());
306 Assert.assertEquals("Invoke Count", 0, cleanInvokeCount.get());
307 Assert.assertEquals("Dispose Count", 0, cleanDisposeCount.get());
308 } else if( throwInInvoke ) {
309 if( !onAnimThread ) {
310 Assert.assertNotNull("No exception forwarded from invoke, on-thread", exceptionAtInvoke);
311 Assert.assertEquals("Exception forwarded from init to animator-handler", 0, exceptionsAtGLAnimatorControl.size());
312 }
313 Assert.assertEquals("Init Count", 1, cleanInitCount.get());
314 Assert.assertEquals("Reshape Count", 1, cleanReshapeCount.get());
315 Assert.assertTrue ("Display count not greater-equal 1, but "+cleanDisplayCount.get(), 1 <= cleanDisplayCount.get());
316 Assert.assertEquals("Invoke Count", 0, cleanInvokeCount.get());
317 Assert.assertEquals("Dispose Count", 0, cleanDisposeCount.get());
318 } else if( throwInDispose ) {
319 if( !onAnimThread ) {
320 Assert.assertNotNull("No exception forwarded from dispose, on-thread", exceptionAtDispose);
321 Assert.assertEquals("Exception forwarded from init to animator-handler", 0, exceptionsAtGLAnimatorControl.size());
322 }
323 Assert.assertEquals("Init Count", 1, cleanInitCount.get());
324 Assert.assertEquals("Reshape Count", 1, cleanReshapeCount.get());
325 Assert.assertTrue ("Display count not greater-equal 1, but "+cleanDisplayCount.get(), 1 <= cleanDisplayCount.get());
326 Assert.assertEquals("Invoke Count", 1, cleanInvokeCount.get());
327 Assert.assertEquals("Dispose Count", 0, cleanDisposeCount.get());
328 }
329 }
330 }
331
332 @Test
333 public void test01OnThreadAtInit() throws InterruptedException {
334 final GLCapabilities caps = new GLCapabilities(glp);
335 caps.setBackgroundOpaque(true); // default
336 runTestGL(caps, true /* onThread */, true /* init */, false /* display */, false /* reshape */, false /* invoke */, false /* dispose */);
337 }
338 @Test
339 public void test02OnThreadAtReshape() throws InterruptedException {
340 final GLCapabilities caps = new GLCapabilities(glp);
341 caps.setBackgroundOpaque(true); // default
342 runTestGL(caps, true /* onThread */, false /* init */, false /* display */, true /* reshape */, false /* invoke */, false /* dispose */);
343 }
344 @Test
345 public void test03OnThreadAtDisplay() throws InterruptedException {
346 final GLCapabilities caps = new GLCapabilities(glp);
347 caps.setBackgroundOpaque(true); // default
348 runTestGL(caps, true /* onThread */, false /* init */, true /* display */, false /* reshape */, false /* invoke */, false /* dispose */);
349 }
350 @Test
351 public void test04OnThreadAtInvoke() throws InterruptedException {
352 final GLCapabilities caps = new GLCapabilities(glp);
353 caps.setBackgroundOpaque(true); // default
354 runTestGL(caps, true /* onThread */, false /* init */, true /* display */, false /* reshape */, true /* invoke */, false /* dispose */);
355 }
356 @Test
357 public void test05OnThreadAtDispose() throws InterruptedException {
358 final GLCapabilities caps = new GLCapabilities(glp);
359 caps.setBackgroundOpaque(true); // default
360 runTestGL(caps, true /* onThread */, false /* init */, false /* display */, false /* reshape */, false /* invoke */, true /* dispose */);
361 }
362
363 @Test
364 public void test11OffThreadAtInit() throws InterruptedException {
365 final GLCapabilities caps = new GLCapabilities(glp);
366 caps.setBackgroundOpaque(true); // default
367 runTestGL(caps, false /* onThread */, true /* init */, false /* display */, false /* reshape */, false /* invoke */, false /* dispose */);
368 }
369 @Test
370 public void test12OffThreadAtReshape() throws InterruptedException {
371 final GLCapabilities caps = new GLCapabilities(glp);
372 caps.setBackgroundOpaque(true); // default
373 runTestGL(caps, false /* onThread */, false /* init */, false /* display */, true /* reshape */, false /* invoke */, false /* dispose */);
374 }
375 @Test
376 public void test13OffThreadAtDisplay() throws InterruptedException {
377 final GLCapabilities caps = new GLCapabilities(glp);
378 caps.setBackgroundOpaque(true); // default
379 runTestGL(caps, false /* onThread */, false /* init */, true /* display */, false /* reshape */, false /* invoke */, false /* dispose */);
380 }
381 @Test
382 public void test14OffThreadAtInvoke() throws InterruptedException {
383 final GLCapabilities caps = new GLCapabilities(glp);
384 caps.setBackgroundOpaque(true); // default
385 runTestGL(caps, false /* onThread */, false /* init */, true /* display */, false /* reshape */, true /* invoke */, false /* dispose */);
386 }
387 @Test
388 public void test15OffThreadAtDispose() throws InterruptedException {
389 final GLCapabilities caps = new GLCapabilities(glp);
390 caps.setBackgroundOpaque(true); // default
391 runTestGL(caps, false /* onThread */, false /* init */, false /* display */, false /* reshape */, false /* invoke */, true /* dispose */);
392 }
393
394 static long duration = 500; // ms
395
396 public static void main(final String args[]) {
397 boolean waitForKey = false;
398
399 for(int i=0; i<args.length; i++) {
400 if(args[i].equals("-time")) {
401 i++;
402 duration = MiscUtils.atol(args[i], duration);
403 } else if(args[i].equals("-wait")) {
404 waitForKey = true;
405 }
406 }
407 if( waitForKey ) {
408 UITestCase.waitForKey("main");
409 }
410 org.junit.runner.JUnitCore.main(TestGLException01NEWT.class.getName());
411 }
412}
void setBackgroundOpaque(final boolean opaque)
Sets whether the surface shall be opaque or translucent.
An implementation of GLAutoDrawable and Window interface, using a delegated Window instance,...
Definition: GLWindow.java:121
final void setTitle(final String title)
Definition: GLWindow.java:297
final void setSize(final int width, final int height)
Sets the size of the window's client area in window units, excluding decorations.
Definition: GLWindow.java:625
final void setVisible(final boolean visible)
Calls setVisible(true, visible), i.e.
Definition: GLWindow.java:615
final void destroy()
Destroys all resources associated with this GLAutoDrawable, inclusive the GLContext.
Definition: GLWindow.java:605
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
Specifies a set of OpenGL capabilities.
Specifies the the OpenGL profile.
Definition: GLProfile.java:77
static GLProfile getGL2ES2(final AbstractGraphicsDevice device)
Returns the GL2ES2 profile implementation, hence compatible w/ GL2ES2.
Definition: GLProfile.java:913
void runTestGL(final GLCapabilities caps, final boolean onThread, final boolean throwInInit, final boolean throwInDisplay, final boolean throwInReshape, final boolean throwInInvoke, final boolean throwInDispose)
static long atol(final String str, final long def)
Definition: MiscUtils.java:66
final void setUncaughtExceptionHandler(final UncaughtExceptionHandler handler)
Set the handler invoked when this animator abruptly stops due to an uncaught exception from one of it...
final void setUpdateFPSFrames(final int frames, final PrintStream out)
final synchronized boolean start()
Starts this animator, if not running.
Definition: Animator.java:344
final synchronized boolean stop()
Stops this animator.
Definition: Animator.java:368
A registered UncaughtExceptionHandler instance is invoked when an animator abruptly stops due to an u...
An animator control interface, which implementation may drive a com.jogamp.opengl....
A higher-level abstraction than GLDrawable which supplies an event based mechanism (GLEventListener) ...
boolean invoke(boolean wait, GLRunnable glRunnable)
Enqueues a one-shot GLRunnable, which will be executed within the next display() call after all regis...
void addGLEventListener(GLEventListener listener)
Adds the given listener to the end of this drawable queue.
Declares events which client code can use to manage OpenGL rendering into a GLAutoDrawable.