From 036446a2b07ea4514b43062ea56cec31a46e8c1a Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 21 Jun 2015 21:23:05 -0400 Subject: [PATCH] deal with some threading issues, remove init() --- core/src/processing/core/PApplet.java | 120 ++++++++++--------- core/src/processing/core/PSurfaceAWT.java | 120 +++++-------------- core/src/processing/opengl/PSurfaceJOGL.java | 31 ++--- core/todo.txt | 15 ++- 4 files changed, 121 insertions(+), 165 deletions(-) diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index 2dc2ac29f..07133d212 100644 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -40,6 +40,7 @@ import java.awt.color.ColorSpace; import java.awt.image.BufferedImage; + // used by loadImage() functions import javax.imageio.ImageIO; // allows us to remove our own MediaTracker code @@ -256,7 +257,7 @@ public class PApplet implements PConstants { * true if no size() command has been executed. This is used to wait until * a size has been set before placing in the window and showing it. */ - public boolean defaultSize; +// public boolean defaultSize; // /** Storage for the current renderer size to avoid re-allocation. */ // Dimension currentSize = new Dimension(); @@ -507,7 +508,7 @@ public class PApplet implements PConstants { * across platforms and input methods. */ @Deprecated - public boolean firstMouse; + public boolean firstMouse = true; /** * ( begin auto-generated from mouseButton.xml ) @@ -706,10 +707,10 @@ public class PApplet implements PConstants { */ public float frameRate = 10; - protected boolean looping; + protected boolean looping = true; /** flag set to true when a redraw is asked for by the user */ - protected boolean redraw; + protected boolean redraw = true; /** * ( begin auto-generated from frameCount.xml ) @@ -828,55 +829,55 @@ public class PApplet implements PConstants { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - /** - * Applet initialization. This can do GUI work because the components have - * not been 'realized' yet: things aren't visible, displayed, etc. - */ - public void init() { -// println("init() called " + Integer.toHexString(hashCode())); - // using a local version here since the class variable is deprecated -// Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); -// screenWidth = screen.width; -// screenHeight = screen.height; - - defaultSize = true; - finished = false; // just for clarity - - // this will be cleared by draw() if it is not overridden - looping = true; - redraw = true; // draw this guy at least once - firstMouse = true; - - // calculated dynamically on first call -// // Removed in 2.1.2, brought back for 2.1.3. Usually sketchPath is set -// // inside runSketch(), but if this sketch takes care of calls to init() -// // when PApplet.main() is not used (i.e. it's in a Java application). -// // THe path needs to be set here so that loadXxxx() functions work. -// if (sketchPath == null) { -// sketchPath = calcSketchPath(); -// } - - // set during Surface.initFrame() -// // Figure out the available display width and height. -// // No major problem if this fails, we have to try again anyway in -// // handleDraw() on the first (== 0) frame. -// checkDisplaySize(); - -// // Set the default size, until the user specifies otherwise -// int w = sketchWidth(); -// int h = sketchHeight(); -// defaultSize = (w == DEFAULT_WIDTH) && (h == DEFAULT_HEIGHT); +// /** +// * Applet initialization. This can do GUI work because the components have +// * not been 'realized' yet: things aren't visible, displayed, etc. +// */ +// public void init() { +//// println("init() called " + Integer.toHexString(hashCode())); +// // using a local version here since the class variable is deprecated +//// Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); +//// screenWidth = screen.width; +//// screenHeight = screen.height; // -// g = makeGraphics(w, h, sketchRenderer(), null, true); -// // Fire component resize event -// setSize(w, h); -// setPreferredSize(new Dimension(w, h)); +// defaultSize = true; +// finished = false; // just for clarity // -// width = g.width; -// height = g.height; - - surface.startThread(); - } +// // this will be cleared by draw() if it is not overridden +// looping = true; +// redraw = true; // draw this guy at least once +// firstMouse = true; +// +// // calculated dynamically on first call +//// // Removed in 2.1.2, brought back for 2.1.3. Usually sketchPath is set +//// // inside runSketch(), but if this sketch takes care of calls to init() +//// // when PApplet.main() is not used (i.e. it's in a Java application). +//// // THe path needs to be set here so that loadXxxx() functions work. +//// if (sketchPath == null) { +//// sketchPath = calcSketchPath(); +//// } +// +// // set during Surface.initFrame() +//// // Figure out the available display width and height. +//// // No major problem if this fails, we have to try again anyway in +//// // handleDraw() on the first (== 0) frame. +//// checkDisplaySize(); +// +//// // Set the default size, until the user specifies otherwise +//// int w = sketchWidth(); +//// int h = sketchHeight(); +//// defaultSize = (w == DEFAULT_WIDTH) && (h == DEFAULT_HEIGHT); +//// +//// g = makeGraphics(w, h, sketchRenderer(), null, true); +//// // Fire component resize event +//// setSize(w, h); +//// setPreferredSize(new Dimension(w, h)); +//// +//// width = g.width; +//// height = g.height; +// +// surface.startThread(); +// } // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . @@ -2368,7 +2369,7 @@ public class PApplet implements PConstants { // // Give up, instead set the new renderer and re-attempt setup() // return; // } - defaultSize = false; +// defaultSize = false; } else { // frameCount > 0, meaning an actual draw() // update the current frameRate @@ -10119,7 +10120,7 @@ public class PApplet implements PConstants { sketch.windowColor = windowColor; } - PSurface surface = sketch.initSurface(); + final PSurface surface = sketch.initSurface(); // sketch.initSurface(windowColor, displayIndex, fullScreen, spanDisplays); /* @@ -10146,6 +10147,9 @@ public class PApplet implements PConstants { surface.placeWindow(location, editorLocation); } +// EventQueue.invokeLater(new Runnable() { +// public void run() { + // Helps avoid this code being duplicated 2x per surface class. // Andres is testing to make sure this doesn't cause trouble. if (sketch.getGraphics().displayable()) { @@ -10153,9 +10157,15 @@ public class PApplet implements PConstants { } // not always running externally when in present mode - if (external) { + if (sketch.external) { surface.setupExternalMessages(); } + + //sketch.init(); + surface.startThread(); + +// } +// }); } @@ -10220,7 +10230,7 @@ public class PApplet implements PConstants { surface.initOffscreen(this); // for PDF/PSurfaceNone and friends } - init(); +// init(); return surface; } diff --git a/core/src/processing/core/PSurfaceAWT.java b/core/src/processing/core/PSurfaceAWT.java index ff3b5e06c..6dcd8a5a1 100644 --- a/core/src/processing/core/PSurfaceAWT.java +++ b/core/src/processing/core/PSurfaceAWT.java @@ -160,6 +160,7 @@ public class PSurfaceAWT extends PSurfaceNone { private Dimension newSize = new Dimension(0, 0); + // Turns out getParent() returns a JPanel on a JFrame. Yech. public Frame getFrame() { return frame; } @@ -197,7 +198,11 @@ public class PSurfaceAWT extends PSurfaceNone { // System.out.println("validate() render old=" + oldSize + " -> new=" + newSize); oldSize = newSize; sketch.setSize(newSize.width, newSize.height); +// try { render(); +// } catch (IllegalStateException ise) { +// System.out.println(ise.getMessage()); +// } } } @@ -248,103 +253,35 @@ public class PSurfaceAWT extends PSurfaceNone { synchronized protected void render() { -// System.out.println("render() top"); - - /* - if (!EventQueue.isDispatchThread()) { - //throw new IllegalStateException("render() called outside the EDT"); - //System.err.println("render() called outside the EDT"); - new Exception("render() called outside the EDT").printStackTrace(); + if (canvas.isDisplayable() && + graphics.image != null) { + if (canvas.getBufferStrategy() == null) { + canvas.createBufferStrategy(2); } - */ -// if (canvas == null) { -// removeListeners(this); -// canvas = new Canvas(); -// add(canvas); -// setIgnoreRepaint(true); -// canvas.setIgnoreRepaint(true); -// addListeners(canvas); -//// add(canvas, BorderLayout.CENTER); -//// doLayout(); -// } + BufferStrategy strategy = canvas.getBufferStrategy(); + if (strategy != null) { + // Render single frame +// try { + do { + // The following loop ensures that the contents of the drawing buffer + // are consistent in case the underlying surface was recreated + do { + Graphics2D draw = (Graphics2D) strategy.getDrawGraphics(); + // draw to width/height, since this may be a 2x image + draw.drawImage(graphics.image, 0, 0, sketchWidth, sketchHeight, null); + draw.dispose(); + } while (strategy.contentsRestored()); - // not sure why this was here, can't be good - //canvas.setBounds(0, 0, sketch.width, sketch.height); + // Display the buffer + strategy.show(); - if (!canvas.isDisplayable()) { -// System.out.println("no peer.. holding"); - return; - } - - if (graphics.image == null) { - if (PApplet.DEBUG) { - new Exception("image is null, returning").printStackTrace(System.out); + // Repeat the rendering if the drawing buffer was lost + } while (strategy.contentsLost()); } - return; } - - Canvas c = canvas; -// Frame c = frame; -// System.out.println("render(), canvas bounds are " + canvas.getBounds()); - if (c.getBufferStrategy() == null) { // whole block [121222] -// System.out.println("creating a strategy"); - c.createBufferStrategy(2); - } - BufferStrategy strategy = c.getBufferStrategy(); -// System.out.println(strategy); - if (strategy == null) { - return; - } - // Render single frame - do { - // The following loop ensures that the contents of the drawing buffer - // are consistent in case the underlying surface was recreated - do { - Graphics2D draw = (Graphics2D) strategy.getDrawGraphics(); - //draw.drawImage(pg.image, 0, 0, sketch.width, sketch.height, null); - //System.out.println("render() drawing image"); - /* - while (sketch.insideDraw) { - System.out.println("render() yielding because inside draw"); - //Thread.yield(); - try { - Thread.sleep(1); - } catch (InterruptedException e) { } - } - */ - - // this wasn't any faster than setting the image size while drawing -// if (graphics.pixelFactor == 2) { -// draw.scale(0.5, 0.5); -// } - - // draw to width/height, since this may be a 2x image - draw.drawImage(graphics.image, 0, 0, sketchWidth, sketchHeight, null); -// draw.drawImage(graphics.image, 0, 0, null); - draw.dispose(); - - // Repeat the rendering if the drawing buffer contents - // were restored -// System.out.println("restored " + strategy.contentsRestored()); - } while (strategy.contentsRestored()); - - // Display the buffer -// System.out.println("showing"); - strategy.show(); - - // Repeat the rendering if the drawing buffer was lost -// System.out.println("lost " + strategy.contentsLost()); -// System.out.println(); - } while (strategy.contentsLost()); -// System.out.println("render() bottom"); } -// Object offscreenLock = new Object(); -// BufferedImage offscreen; -// BufferedImage onscreen; - - /* protected void blit() { // Other folks that call render() (i.e. paint()) are already on the EDT. @@ -762,8 +699,10 @@ public class PSurfaceAWT extends PSurfaceNone { //frame.setExtendedState(Frame.MAXIMIZED_BOTH); // https://github.com/processing/processing/pull/3162 - frame.dispose(); // release native resources, allows setUndecorated() + //frame.dispose(); // release native resources, allows setUndecorated() + frame.removeNotify(); frame.setUndecorated(true); + frame.addNotify(); // this may be the bounds of all screens frame.setBounds(screenRect); @@ -1479,7 +1418,6 @@ public class PSurfaceAWT extends PSurfaceNone { @Override public void callDraw() { sketch.handleDraw(); - //blit(); render(); } }; diff --git a/core/src/processing/opengl/PSurfaceJOGL.java b/core/src/processing/opengl/PSurfaceJOGL.java index c54927a23..4d7acef28 100644 --- a/core/src/processing/opengl/PSurfaceJOGL.java +++ b/core/src/processing/opengl/PSurfaceJOGL.java @@ -493,21 +493,22 @@ public class PSurfaceJOGL implements PSurface { public void startThread() { - if (animator == null) return; - if (placedWindow) { - window.setVisible(true); - animator.start(); - requestedStart = false; - } else { - // The GL window is not visible until it has been placed, so we cannot - // start the animator because it requires the window to be visible. - requestedStart = true; - // Need this assignment to bypass the while loop in runSketch, otherwise - // the programs hangs waiting for defaultSize to be false, but it never - // happens because the animation thread is not yet running to avoid showing - // the window in the wrong place: - // https://github.com/processing/processing/issues/3308 - sketch.defaultSize = false; + if (animator != null) { + if (placedWindow) { + window.setVisible(true); + animator.start(); + requestedStart = false; + } else { + // The GL window is not visible until it has been placed, so we cannot + // start the animator because it requires the window to be visible. + requestedStart = true; + // Need this assignment to bypass the while loop in runSketch, otherwise + // the programs hangs waiting for defaultSize to be false, but it never + // happens because the animation thread is not yet running to avoid showing + // the window in the wrong place: + // https://github.com/processing/processing/issues/3308 +// sketch.defaultSize = false; + } } } diff --git a/core/todo.txt b/core/todo.txt index cc31b8917..14496e08b 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -54,6 +54,12 @@ X https://github.com/processing/processing/issues/3316 X Window never shows with exported application on 64-bit Linux X https://github.com/processing/processing/issues/3303 X present mode is now broken +o still some spinning when sketches break +X fixed because we're back off the EDT +o settings() is probably not showing exceptions since we're back to the EDT +o can't call handleSettings() on the anim thread since it sets the surface +o so maybe the first part is on the EDT, but other threads run this stuff +X remove the init() method cleaning o possible addition for 'implementation' variable @@ -109,10 +115,9 @@ _ update wiki/docs to say "don't override sketchXxxx() methods" beta -_ still some spinning when sketches break -_ settings() is probably not showing exceptions since we're back to the EDT -_ can't call handleSettings() on the anim thread since it sets the surface -_ so maybe the first part is on the EDT, but other threads run this stuff +_ run only the necessary pieces on the EDT +_ in part because FX doesn't even use the EDT +_ re-check the Linux frame visibility stuff _ try using Frame instead of JFrame _ default sketch location using insets incorrectly _ use the BufferStrategy directly from the Frame object? @@ -149,6 +154,8 @@ _ or pass createImage() through to renderer? _ implement frameRate() _ implement external messages (moving the window) _ implement PSurfaceFX.setIcon() +_ javafx not supported with ARM (so we're screwed on raspberry pi) +_ https://www.linkedin.com/pulse/oracle-just-removed-javafx-support-arm-jan-snelders opengl