From 22ee0cfa7dc3f3a7ac5e30322537196dcab8b310 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Wed, 4 Dec 2019 04:35:06 +0100 Subject: Bug 1405: Provide stand alone demo launcher reducing complexity The launcher script also allows inflating classes and native libs to test impact on Raspberry Pi 3 Model B+. --- src/demos/com/jogamp/opengl/demos/Launcher0.java | 484 +++++++++++++++++++++++ src/demos/com/jogamp/opengl/demos/MiscUtils.java | 259 ++++++++++++ 2 files changed, 743 insertions(+) create mode 100644 src/demos/com/jogamp/opengl/demos/Launcher0.java create mode 100644 src/demos/com/jogamp/opengl/demos/MiscUtils.java (limited to 'src/demos/com') diff --git a/src/demos/com/jogamp/opengl/demos/Launcher0.java b/src/demos/com/jogamp/opengl/demos/Launcher0.java new file mode 100644 index 000000000..c5e736733 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/Launcher0.java @@ -0,0 +1,484 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.demos; + +import java.io.IOException; + +import com.jogamp.newt.Display; +import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.Screen; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.event.TraceMouseAdapter; +import com.jogamp.newt.event.WindowAdapter; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.newt.opengl.util.NEWTDemoListener; +import com.jogamp.newt.util.EDTUtil; +import com.jogamp.opengl.util.Animator; +import com.jogamp.opengl.util.AnimatorBase; +import com.jogamp.nativewindow.ScalableSurface; +import com.jogamp.nativewindow.util.Dimension; +import com.jogamp.nativewindow.util.Point; +import com.jogamp.nativewindow.util.PointImmutable; +import com.jogamp.nativewindow.util.DimensionImmutable; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GLAnimatorControl; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLPipelineFactory; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.demos.es2.GearsES2; + +import jogamp.newt.DefaultEDTUtil; + +/** + *

+ * The demo code uses {@link NEWTDemoListener} functionality. + *

+ *

+ * Manual invocation via main allows setting each tests's duration in milliseconds, e.g.{@code -duration 10000} and many more, see {@link #main(String[])} + *

+ */ +public class Launcher0 { + static int screenIdx = 0; + static PointImmutable wpos; + static DimensionImmutable wsize = new Dimension(640, 480), rwsize=null; + static float[] reqSurfacePixelScale = new float[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE }; + + static long duration = 500; // ms + static boolean opaque = true; + static int forceAlpha = -1; + static boolean undecorated = false; + static boolean alwaysOnTop = false; + static boolean alwaysOnBottom = false; + static boolean resizable = true; + static boolean sticky = false; + static boolean max_vert= false; + static boolean max_horz= false; + static boolean fullscreen = false; + static int swapInterval = 1; + static boolean waitForKey = false; + static boolean mouseVisible = true; + static boolean mouseConfined = false; + static boolean setPointerIcon = false; + static boolean showFPS = false; + static boolean forceES2 = false; + static boolean forceES3 = false; + static boolean forceGL3 = false; + static boolean forceGL2 = false; + static boolean forceDebug = false; + static boolean forceTrace = false; + static boolean traceMouse = false; + static boolean exclusiveContext = false; + static boolean useAnimator = true; + static boolean useMappedBuffers = false; + static enum SysExit { none, testExit, testError, testEDTError, displayExit, displayError, displayEDTError }; + static SysExit sysExit = SysExit.none; + + public void runTest() throws InterruptedException { + final GLProfile glp; + if(forceGL3) { + glp = GLProfile.get(GLProfile.GL3); + } else if(forceES3) { + glp = GLProfile.get(GLProfile.GLES3); + } else if(forceES2) { + glp = GLProfile.get(GLProfile.GLES2); + } else if(forceGL2) { + glp = GLProfile.get(GLProfile.GL2); + } else { + glp = GLProfile.getGL2ES2(); + } + final GLCapabilities caps = new GLCapabilities( glp ); + caps.setBackgroundOpaque(opaque); + if(-1 < forceAlpha) { + caps.setAlphaBits(forceAlpha); + } + + System.err.println("requested: vsync "+swapInterval+", "+caps); + final Display dpy = NewtFactory.createDisplay(null); + final Screen screen = NewtFactory.createScreen(dpy, screenIdx); + final GLWindow glWindow = GLWindow.create(screen, caps); + + glWindow.setSurfaceScale(reqSurfacePixelScale); + final float[] valReqSurfacePixelScale = glWindow.getRequestedSurfaceScale(new float[2]); + glWindow.setSize(wsize.getWidth(), wsize.getHeight()); + if(null != wpos) { + glWindow.setPosition(wpos.getX(), wpos.getY()); + } + glWindow.setUndecorated(undecorated); + glWindow.setAlwaysOnTop(alwaysOnTop); + glWindow.setAlwaysOnBottom(alwaysOnBottom); + glWindow.setResizable(resizable); + glWindow.setSticky(sticky); + glWindow.setMaximized(max_horz, max_vert); + glWindow.setFullscreen(fullscreen); + glWindow.setPointerVisible(mouseVisible); + glWindow.confinePointer(mouseConfined); + + final GLEventListener demo; + { + final GearsES2 gearsES2 = new GearsES2(swapInterval); + gearsES2.setUseMappedBuffers(useMappedBuffers); + gearsES2.setValidateBuffers(true); + demo = gearsES2; + } + if( forceDebug || forceTrace ) { + glWindow.addGLEventListener(new GLEventListener() { + @Override + public void init(final GLAutoDrawable drawable) { + GL _gl = drawable.getGL(); + if(forceDebug) { + try { + _gl = _gl.getContext().setGL( GLPipelineFactory.create("com.jogamp.opengl.Debug", null, _gl, null) ); + } catch (final Exception e) {e.printStackTrace();} + } + + if(forceTrace) { + try { + // Trace .. + _gl = _gl.getContext().setGL( GLPipelineFactory.create("com.jogamp.opengl.Trace", null, _gl, new Object[] { System.err } ) ); + } catch (final Exception e) {e.printStackTrace();} + } + } + @Override + public void dispose(final GLAutoDrawable drawable) {} + @Override + public void display(final GLAutoDrawable drawable) {} + @Override + public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) {} + }); + } + + if( null != demo ) { + glWindow.addGLEventListener(demo); + } + + if(waitForKey) { + glWindow.addGLEventListener(new GLEventListener() { + public void init(final GLAutoDrawable drawable) { } + public void dispose(final GLAutoDrawable drawable) { } + public void display(final GLAutoDrawable drawable) { + final GLAnimatorControl actrl = drawable.getAnimator(); + if(waitForKey && actrl.getTotalFPSFrames() == 60*3) { + MiscUtils.waitForKey("3s mark"); + actrl.resetFPSCounter(); + waitForKey = false; + } + } + public void reshape(final GLAutoDrawable drawable, final int x, final int y, + final int width, final int height) { } + }); + } + + final Animator animator = useAnimator ? new Animator() : null; + if( useAnimator ) { + animator.setModeBits(false, AnimatorBase.MODE_EXPECT_AWT_RENDERING_THREAD); + animator.setExclusiveContext(exclusiveContext); + } + + glWindow.addWindowListener(new WindowAdapter() { + public void windowResized(final WindowEvent e) { + System.err.println("window resized: "+glWindow.getBounds()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()); + NEWTDemoListener.setTitle(glWindow); + } + public void windowMoved(final WindowEvent e) { + System.err.println("window moved: "+glWindow.getBounds()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()); + NEWTDemoListener.setTitle(glWindow); + } + }); + + final NEWTDemoListener newtDemoListener = new NEWTDemoListener(glWindow); + newtDemoListener.quitAdapterEnable(true); + glWindow.addKeyListener(newtDemoListener); + if( traceMouse ) { + glWindow.addMouseListener(new TraceMouseAdapter()); + } + glWindow.addMouseListener(newtDemoListener); + glWindow.addWindowListener(newtDemoListener); + + if( useAnimator ) { + animator.add(glWindow); + animator.start(); + } + + if( SysExit.displayError == sysExit || SysExit.displayExit == sysExit || SysExit.displayEDTError == sysExit ) { + glWindow.addGLEventListener(new GLEventListener() { + @Override + public void init(final GLAutoDrawable drawable) {} + @Override + public void dispose(final GLAutoDrawable drawable) { } + @Override + public void display(final GLAutoDrawable drawable) { + final GLAnimatorControl anim = drawable.getAnimator(); + if( null != anim && anim.isAnimating() ) { + final long ms = anim.getTotalFPSDuration(); + if( ms >= duration/2 || ms >= 3000 ) { // max 3s wait until provoking error + if( SysExit.displayError == sysExit ) { + throw new Error("test error send from GLEventListener.display - "+Thread.currentThread()); + } else if ( SysExit.displayExit == sysExit ) { + System.err.println("exit(0) send from GLEventListener"); + System.exit(0); + } else if ( SysExit.displayEDTError == sysExit ) { + final Object upstream = drawable.getUpstreamWidget(); + System.err.println("EDT invokeAndWaitError: upstream type "+upstream.getClass().getName()); + if( upstream instanceof Window ) { + final EDTUtil edt = ((Window)upstream).getScreen().getDisplay().getEDTUtil(); + System.err.println("EDT invokeAndWaitError: edt type "+edt.getClass().getName()); + if( edt instanceof DefaultEDTUtil ) { + newtDemoListener.doQuit(); + ((DefaultEDTUtil)edt).invokeAndWaitError(new Runnable() { + public void run() { + throw new RuntimeException("XXX Should never ever be seen! - "+Thread.currentThread()); + } + }); + } + } + } + } + } else { + System.exit(0); + } + } + @Override + public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { } + }); + } + + glWindow.setVisible(true); + if( useAnimator ) { + animator.setUpdateFPSFrames(60, showFPS ? System.err : null); + } + + System.err.println("Window Current State : "+glWindow.getStateMaskString()); + System.err.println("Window Supported States: "+glWindow.getSupportedStateMaskString()); + System.err.println("NW chosen: "+glWindow.getDelegatedWindow().getChosenCapabilities()); + System.err.println("GL chosen: "+glWindow.getChosenCapabilities()); + System.err.println("window pos/siz: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()+", "+glWindow.getInsets()); + + final float[] hasSurfacePixelScale1 = glWindow.getCurrentSurfaceScale(new float[2]); + System.err.println("HiDPI PixelScale: "+reqSurfacePixelScale[0]+"x"+reqSurfacePixelScale[1]+" (req) -> "+ + valReqSurfacePixelScale[0]+"x"+valReqSurfacePixelScale[1]+" (val) -> "+ + hasSurfacePixelScale1[0]+"x"+hasSurfacePixelScale1[1]+" (has)"); + NEWTDemoListener.setTitle(glWindow); + + if( null != rwsize ) { + Thread.sleep(500); // 500ms delay + glWindow.setSize(rwsize.getWidth(), rwsize.getHeight()); + System.err.println("window resize pos/siz: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()+", "+glWindow.getInsets()); + } + + final long t0 = System.currentTimeMillis(); + long t1 = t0; + while(!newtDemoListener.shouldQuit() && t1-t0= duration/2 || ms >= 3000 ) { // max 3s wait until provoking error + if( SysExit.testError == sysExit ) { + throw new Error("test error send from test thread"); + } else if ( SysExit.testExit == sysExit ) { + System.err.println("exit(0) send from test thread"); + System.exit(0); + } else if ( SysExit.testEDTError == sysExit ) { + final EDTUtil edt = glWindow.getScreen().getDisplay().getEDTUtil(); + System.err.println("EDT invokeAndWaitError: edt type "+edt.getClass().getName()); + if( edt instanceof DefaultEDTUtil ) { + newtDemoListener.doQuit(); + ((DefaultEDTUtil)edt).invokeAndWaitError(new Runnable() { + public void run() { + throw new RuntimeException("XXX Should never ever be seen!"); + } + }); + } + } + } + } + } + + if( useAnimator ) { + animator.stop(); + } + glWindow.destroy(); + } + + public static void main(final String args[]) throws IOException { + int x=0, y=0, w=640, h=480, rw=-1, rh=-1; + boolean usePos = false; + + for(int i=0; i delta ) { + throw new AssertionError(msg+"; Expected @ ["+a0+"+"+i+"] has "+ai+", but actual @ ["+b0+"+"+i+"] has "+bi+", it's delta "+daibi+" > "+delta); + } + } + } + + public static void assertFloatBufferNotEqual(final String errmsg, final FloatBuffer expected, final FloatBuffer actual, final float delta) { + if(null == expected || null == actual) { + return; + } + if(expected.remaining() != actual.remaining()) { + return; + } + final String msg = null != errmsg ? errmsg + " " : ""; + final int a0 = expected.position(); + final int b0 = actual.position(); + for(int i=0; i delta ) { + return; + } + } + throw new AssertionError(msg+"; Expected and actual are equal."); + } + + public static boolean setFieldIfExists(final Object instance, final String fieldName, final Object value) { + try { + final Field f = instance.getClass().getField(fieldName); + if(value instanceof Boolean || f.getType().isInstance(value)) { + f.set(instance, value); + return true; + } else { + System.out.println(instance.getClass()+" '"+fieldName+"' field not assignable with "+value.getClass()+", it's a: "+f.getType()); + } + } catch (final IllegalAccessException ex) { + throw new RuntimeException(ex); + } catch (final NoSuchFieldException nsfe) { + // OK - throw new RuntimeException(instance.getClass()+" has no '"+fieldName+"' field", nsfe); + } + return false; + } + + public static void waitForKey(final String preMessage) { + final BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); + System.err.println(preMessage+"> Press enter to continue"); + try { + System.err.println(stdin.readLine()); + } catch (final IOException e) { e.printStackTrace(); } + } + + + public static class StreamDump extends InterruptSource.Thread { + final InputStream is; + final StringBuilder outString; + final OutputStream outStream; + final String prefix; + final Object sync; + volatile boolean eos = false; + + public StreamDump(final OutputStream out, final String prefix, final InputStream is, final Object sync) { + this.is = is; + this.outString = null; + this.outStream = out; + this.prefix = prefix; + this.sync = sync; + } + public StreamDump(final StringBuilder sb, final String prefix, final InputStream is, final Object sync) { + this.is = is; + this.outString = sb; + this.outStream = null; + this.prefix = prefix; + this.sync = sync; + } + public StreamDump(final StringBuilder sb, final InputStream is, final Object sync) { + this.is = is; + this.outString = sb; + this.outStream = null; + this.prefix = null; + this.sync = sync; + } + + public final boolean eos() { return eos; } + + @Override + public void run() { + synchronized ( sync ) { + try { + final BufferedReader in = new BufferedReader( new InputStreamReader(is) ); + String line = null; + while ((line = in.readLine()) != null) { + if( null != outString ) { + outString.append(line).append(Platform.getNewline()); + } else if( null != outStream ) { + if( null != prefix ) { + outStream.write(prefix.getBytes()); + } + outStream.write(line.getBytes()); + outStream.write(Platform.getNewline().getBytes()); + outStream.flush(); + } + } + } catch (final IOException ioe) { + System.err.println("Caught "+ioe.getClass().getName()+": "+ioe.getMessage()); + ioe.printStackTrace(); + } finally { + eos = true; + sync.notifyAll(); + } + } + } + } + + public static void dumpSharedGLContext(final String prefix, final GLContext self) { + int i = 0, j = 0; + final GLContext master = self.getSharedMaster(); + final int masterHash = null != master ? master.hashCode() : 0; + System.err.println(prefix+": hash 0x"+Integer.toHexString(self.hashCode())+", \t(isShared "+self.isShared()+", created "+self.isCreated()+", master 0x"+Integer.toHexString(masterHash)+")"); + { + final List set = self.getCreatedShares(); + for (final Iterator iter = set.iterator(); iter.hasNext(); ) { + final GLContext c = iter.next(); + System.err.println(" Created Ctx #"+(i++)+": hash 0x"+Integer.toHexString(c.hashCode())+", \t(created "+c.isCreated()+")"); + } + } + { + final List set = self.getDestroyedShares(); + for (final Iterator iter = set.iterator(); iter.hasNext(); ) { + final GLContext c = iter.next(); + System.err.println(" Destroyed Ctx #"+(j++)+": hash 0x"+Integer.toHexString(c.hashCode())+", \t(created "+c.isCreated()+")"); + } + } + System.err.println("\t Total created "+i+" + destroyed "+j+" = "+(i+j)); + System.err.println(); + } +} + + + -- cgit v1.2.3