From 9110cebd0dc1914f00ef78a8aca1dd6957442a7e Mon Sep 17 00:00:00 2001 From: codeanticode Date: Mon, 20 Jan 2014 16:48:19 -0500 Subject: [PATCH] more refactoring/testing with non-static fields in PGL --- core/src/processing/opengl/FrameBuffer.java | 42 +- core/src/processing/opengl/PGL.java | 395 ++++++++++-------- .../processing/opengl/PGraphicsOpenGL.java | 209 ++++----- core/src/processing/opengl/PJOGL.java | 134 +++--- core/src/processing/opengl/Texture.java | 18 +- 5 files changed, 431 insertions(+), 367 deletions(-) diff --git a/core/src/processing/opengl/FrameBuffer.java b/core/src/processing/opengl/FrameBuffer.java index 1e5ef72a6..e70ac1173 100644 --- a/core/src/processing/opengl/FrameBuffer.java +++ b/core/src/processing/opengl/FrameBuffer.java @@ -174,15 +174,15 @@ public class FrameBuffer implements PConstants { } public void clear() { - PGraphicsOpenGL.pushFramebuffer(); - PGraphicsOpenGL.setFramebuffer(this); + pg.pushFramebuffer(); + pg.setFramebuffer(this); pgl.clearDepth(1); pgl.clearStencil(0); pgl.clearColor(0, 0, 0, 0); pgl.clear(PGL.DEPTH_BUFFER_BIT | PGL.STENCIL_BUFFER_BIT | PGL.COLOR_BUFFER_BIT); - PGraphicsOpenGL.popFramebuffer(); + pg.popFramebuffer(); } public void copy(FrameBuffer dest, FrameBuffer current) { @@ -273,8 +273,8 @@ public class FrameBuffer implements PConstants { colorBufferTex[i] = textures[i]; } - PGraphicsOpenGL.pushFramebuffer(); - PGraphicsOpenGL.setFramebuffer(this); + pg.pushFramebuffer(); + pg.setFramebuffer(this); // Making sure nothing is attached. for (int i = 0; i < numColorBuffers; i++) { @@ -290,7 +290,7 @@ public class FrameBuffer implements PConstants { pgl.validateFramebuffer(); - PGraphicsOpenGL.popFramebuffer(); + pg.popFramebuffer(); } @@ -302,8 +302,8 @@ public class FrameBuffer implements PConstants { colorBufferTex[i1] = tmp; } - PGraphicsOpenGL.pushFramebuffer(); - PGraphicsOpenGL.setFramebuffer(this); + pg.pushFramebuffer(); + pg.setFramebuffer(this); for (int i = 0; i < numColorBuffers; i++) { pgl.framebufferTexture2D(PGL.FRAMEBUFFER, PGL.COLOR_ATTACHMENT0 + i, colorBufferTex[i].glTarget, @@ -311,7 +311,7 @@ public class FrameBuffer implements PConstants { } pgl.validateFramebuffer(); - PGraphicsOpenGL.popFramebuffer(); + pg.popFramebuffer(); } @@ -422,8 +422,8 @@ public class FrameBuffer implements PConstants { protected void createColorBufferMultisample() { if (screenFb) return; - PGraphicsOpenGL.pushFramebuffer(); - PGraphicsOpenGL.setFramebuffer(this); + pg.pushFramebuffer(); + pg.setFramebuffer(this); glMultisample = PGraphicsOpenGL.createRenderBufferObject(context, pgl); pgl.bindRenderbuffer(PGL.RENDERBUFFER, glMultisample); @@ -432,7 +432,7 @@ public class FrameBuffer implements PConstants { pgl.framebufferRenderbuffer(PGL.FRAMEBUFFER, PGL.COLOR_ATTACHMENT0, PGL.RENDERBUFFER, glMultisample); - PGraphicsOpenGL.popFramebuffer(); + pg.popFramebuffer(); } @@ -443,8 +443,8 @@ public class FrameBuffer implements PConstants { throw new RuntimeException("PFramebuffer: size undefined."); } - PGraphicsOpenGL.pushFramebuffer(); - PGraphicsOpenGL.setFramebuffer(this); + pg.pushFramebuffer(); + pg.setFramebuffer(this); glDepthStencil = PGraphicsOpenGL.createRenderBufferObject(context, pgl); pgl.bindRenderbuffer(PGL.RENDERBUFFER, glDepthStencil); @@ -462,7 +462,7 @@ public class FrameBuffer implements PConstants { pgl.framebufferRenderbuffer(PGL.FRAMEBUFFER, PGL.STENCIL_ATTACHMENT, PGL.RENDERBUFFER, glDepthStencil); - PGraphicsOpenGL.popFramebuffer(); + pg.popFramebuffer(); } @@ -473,8 +473,8 @@ public class FrameBuffer implements PConstants { throw new RuntimeException("PFramebuffer: size undefined."); } - PGraphicsOpenGL.pushFramebuffer(); - PGraphicsOpenGL.setFramebuffer(this); + pg.pushFramebuffer(); + pg.setFramebuffer(this); glDepth = PGraphicsOpenGL.createRenderBufferObject(context, pgl); pgl.bindRenderbuffer(PGL.RENDERBUFFER, glDepth); @@ -498,7 +498,7 @@ public class FrameBuffer implements PConstants { pgl.framebufferRenderbuffer(PGL.FRAMEBUFFER, PGL.DEPTH_ATTACHMENT, PGL.RENDERBUFFER, glDepth); - PGraphicsOpenGL.popFramebuffer(); + pg.popFramebuffer(); } @@ -509,8 +509,8 @@ public class FrameBuffer implements PConstants { throw new RuntimeException("PFramebuffer: size undefined."); } - PGraphicsOpenGL.pushFramebuffer(); - PGraphicsOpenGL.setFramebuffer(this); + pg.pushFramebuffer(); + pg.setFramebuffer(this); glStencil = PGraphicsOpenGL.createRenderBufferObject(context, pgl); pgl.bindRenderbuffer(PGL.RENDERBUFFER, glStencil); @@ -533,7 +533,7 @@ public class FrameBuffer implements PConstants { pgl.framebufferRenderbuffer(PGL.FRAMEBUFFER, PGL.STENCIL_ATTACHMENT, PGL.RENDERBUFFER, glStencil); - PGraphicsOpenGL.popFramebuffer(); + pg.popFramebuffer(); } diff --git a/core/src/processing/opengl/PGL.java b/core/src/processing/opengl/PGL.java index bd4066021..629388ed8 100644 --- a/core/src/processing/opengl/PGL.java +++ b/core/src/processing/opengl/PGL.java @@ -57,6 +57,9 @@ public abstract class PGL { /** ID of the GL context associated to the surface **/ protected int glContext; + /** true if this is the GL interface for a primary surface PGraphics */ + protected boolean primaryPGL; + // ........................................................ // Parameters @@ -131,21 +134,21 @@ public abstract class PGL { // FBO layer - protected static boolean fboLayerRequested = false; - protected static boolean fboLayerCreated = false; - protected static boolean fboLayerInUse = false; - protected static boolean firstFrame = true; - protected static int reqNumSamples; - protected static int numSamples; - protected static IntBuffer glColorFbo; - protected static IntBuffer glMultiFbo; - protected static IntBuffer glColorBuf; - protected static IntBuffer glColorTex; - protected static IntBuffer glDepthStencil; - protected static IntBuffer glDepth; - protected static IntBuffer glStencil; - protected static int fboWidth, fboHeight; - protected static int backTex, frontTex; + protected boolean fboLayerRequested = false; + protected boolean fboLayerCreated = false; + protected boolean fboLayerInUse = false; + protected boolean firstFrame = true; + protected int reqNumSamples; + protected int numSamples; + protected IntBuffer glColorFbo; + protected IntBuffer glMultiFbo; + protected IntBuffer glColorBuf; + protected IntBuffer glColorTex; + protected IntBuffer glDepthStencil; + protected IntBuffer glDepth; + protected IntBuffer glStencil; + protected int fboWidth, fboHeight; + protected int backTex, frontTex; /** Flags used to handle the creation of a separate front texture */ protected boolean usingFrontTex = false; @@ -155,33 +158,33 @@ public abstract class PGL { // Texture rendering - protected static boolean loadedTex2DShader = false; - protected static int tex2DShaderProgram; - protected static int tex2DVertShader; - protected static int tex2DFragShader; - protected static int tex2DShaderContext; - protected static int texGeoVBO; - protected static int tex2DVertLoc; - protected static int tex2DTCoordLoc; - protected static int tex2DSamplerLoc; + protected boolean loadedTex2DShader = false; + protected int tex2DShaderProgram; + protected int tex2DVertShader; + protected int tex2DFragShader; + protected int tex2DShaderContext; + protected int texGeoVBO; + protected int tex2DVertLoc; + protected int tex2DTCoordLoc; + protected int tex2DSamplerLoc; - protected static boolean loadedTexRectShader = false; - protected static int texRectShaderProgram; - protected static int texRectVertShader; - protected static int texRectFragShader; - protected static int texRectShaderContext; - protected static int texRectVertLoc; - protected static int texRectTCoordLoc; - protected static int texRectSamplerLoc; + protected boolean loadedTexRectShader = false; + protected int texRectShaderProgram; + protected int texRectVertShader; + protected int texRectFragShader; + protected int texRectShaderContext; + protected int texRectVertLoc; + protected int texRectTCoordLoc; + protected int texRectSamplerLoc; - protected static float[] texCoords = { + protected float[] texCoords = { // X, Y, U, V -1.0f, -1.0f, 0.0f, 0.0f, +1.0f, -1.0f, 1.0f, 0.0f, -1.0f, +1.0f, 0.0f, 1.0f, +1.0f, +1.0f, 1.0f, 1.0f }; - protected static FloatBuffer texData; + protected FloatBuffer texData; protected static final String SHADER_PREPROCESSOR_DIRECTIVE = "#ifdef GL_ES\n" + @@ -218,12 +221,12 @@ public abstract class PGL { }; /** Which texturing targets are enabled */ - protected static boolean[] texturingTargets = { false, false }; + protected boolean[] texturingTargets = { false, false }; /** Used to keep track of which textures are bound to each target */ - protected static int maxTexUnits; - protected static int activeTexUnit = 0; - protected static int[][] boundTextures; + protected int maxTexUnits; + protected int activeTexUnit = 0; + protected int[][] boundTextures; // ........................................................ @@ -270,6 +273,13 @@ public abstract class PGL { protected static final String TEXUNIT_ERROR = "Number of texture units not supported by this hardware (or driver)" + WIKI; + protected static final String NONPRIMARY_ERROR = + "The renderer is trying to call a PGL function that can only be called on a primary PGL. " + + "This is most likely due to a bug in the renderer's code, please report it with an " + + "issue on Processing's github page https://github.com/processing/processing/issues?state=open " + + "if using any of the built-in OpenGL renderers. If you are using a contributed " + + "library, contact the library's developers."; + // ........................................................ // Constants @@ -334,6 +344,17 @@ public abstract class PGL { } + public void setPrimary(boolean primary) { + primaryPGL = primary; + } + + + protected void checkPrimary() { + if (!primaryPGL) { + throw new RuntimeException(NONPRIMARY_ERROR); + } + } + /** * Return the native canvas the OpenGL context associated to this PGL object * is rendering to (if any). @@ -354,6 +375,8 @@ public abstract class PGL { protected void deleteSurface() { + checkPrimary(); + if (threadIsCurrent() && fboLayerCreated) { deleteTextures(2, glColorTex); deleteFramebuffers(1, glColorFbo); @@ -371,11 +394,13 @@ public abstract class PGL { protected int getReadFramebuffer() { + checkPrimary(); return fboLayerInUse ? glColorFbo.get(0) : 0; } protected int getDrawFramebuffer() { + checkPrimary(); if (fboLayerInUse) return 1 < numSamples ? glMultiFbo.get(0) : glColorFbo.get(0); else return 0; @@ -383,26 +408,31 @@ public abstract class PGL { protected int getDefaultDrawBuffer() { + checkPrimary(); return fboLayerInUse ? COLOR_ATTACHMENT0 : FRONT; } protected int getDefaultReadBuffer() { + checkPrimary(); return fboLayerInUse ? COLOR_ATTACHMENT0 : FRONT; } protected boolean isFBOBacked() { + checkPrimary(); return fboLayerInUse; } protected void requestFBOLayer() { + checkPrimary(); fboLayerRequested = true; } protected boolean isMultisampled() { + checkPrimary(); return 1 < numSamples; } @@ -436,6 +466,7 @@ public abstract class PGL { protected Texture wrapBackTexture(Texture texture) { + checkPrimary(); if (texture == null) { texture = new Texture(pg); texture.init(pg.width, pg.height, @@ -453,6 +484,7 @@ public abstract class PGL { protected Texture wrapFrontTexture(Texture texture) { + checkPrimary(); if (texture == null) { texture = new Texture(pg); texture.init(pg.width, pg.height, @@ -469,6 +501,7 @@ public abstract class PGL { protected void bindFrontTexture() { + checkPrimary(); usingFrontTex = true; if (!texturingIsEnabled(TEXTURE_2D)) { enableTexturing(TEXTURE_2D); @@ -478,6 +511,7 @@ public abstract class PGL { protected void unbindFrontTexture() { + checkPrimary(); if (textureIsBound(TEXTURE_2D, glColorTex.get(frontTex))) { // We don't want to unbind another texture // that might be bound instead of this one. @@ -493,6 +527,7 @@ public abstract class PGL { protected void syncBackTexture() { + checkPrimary(); if (usingFrontTex) needSepFrontTex = true; if (1 < numSamples) { bindFramebuffer(READ_FRAMEBUFFER, glMultiFbo.get(0)); @@ -504,18 +539,122 @@ public abstract class PGL { } - protected int qualityToSamples(int quality) { - if (quality <= 1) { - return 1; + /////////////////////////////////////////////////////////// + + // Frame rendering + + + protected void beginDraw(boolean clear0) { + checkPrimary(); + if (needFBOLayer(clear0)) { + if (!fboLayerCreated) createFBOLayer(); + + bindFramebuffer(FRAMEBUFFER, glColorFbo.get(0)); + framebufferTexture2D(FRAMEBUFFER, COLOR_ATTACHMENT0, + TEXTURE_2D, glColorTex.get(backTex), 0); + + if (1 < numSamples) { + bindFramebuffer(FRAMEBUFFER, glMultiFbo.get(0)); + } + + if (firstFrame) { + // No need to draw back color buffer because we are in the first frame. + int argb = pg.backgroundColor; + float a = ((argb >> 24) & 0xff) / 255.0f; + float r = ((argb >> 16) & 0xff) / 255.0f; + float g = ((argb >> 8) & 0xff) / 255.0f; + float b = ((argb) & 0xff) / 255.0f; + clearColor(r, g, b, a); + clear(COLOR_BUFFER_BIT); + } else if (!clear0) { + // Render previous back texture (now is the front) as background, + // because no background() is being used ("incremental drawing") + drawTexture(TEXTURE_2D, glColorTex.get(frontTex), + fboWidth, fboHeight, pg.width, pg.height, + 0, 0, pg.width, pg.height, + 0, 0, pg.width, pg.height); + } + + fboLayerInUse = true; } else { - // Number of samples is always an even number: - int n = 2 * (quality / 2); - return n; + fboLayerInUse = false; + } + + if (firstFrame) { + firstFrame = false; + } + + if (!USE_FBOLAYER_BY_DEFAULT) { + // The result of this assignment is the following: if the user requested + // at some point the use of the FBO layer, but subsequently didn't + // request it again, then the rendering won't render to the FBO layer if + // not needed by the condif, since it is slower than simple onscreen + // rendering. + fboLayerRequested = false; } } - protected void createFBOLayer() { + protected void endDraw(boolean clear0) { + checkPrimary(); + if (fboLayerInUse) { + syncBackTexture(); + + // Draw the contents of the back texture to the screen framebuffer. + bindFramebuffer(FRAMEBUFFER, 0); + + clearDepth(1); + clearColor(0, 0, 0, 0); + clear(COLOR_BUFFER_BIT | DEPTH_BUFFER_BIT); + + // Render current back texture to screen, without blending. + disable(BLEND); + drawTexture(TEXTURE_2D, glColorTex.get(backTex), + fboWidth, fboHeight, pg.width, pg.height, + 0, 0, pg.width, pg.height, + 0, 0, pg.width, pg.height); + + // Swapping front and back textures. + int temp = frontTex; + frontTex = backTex; + backTex = temp; + } + } + + + protected abstract void getGL(PGL pgl); + + + protected abstract boolean canDraw(); + + + protected abstract void requestFocus(); + + + protected abstract void requestDraw(); + + + protected abstract void swapBuffers(); + + + protected boolean threadIsCurrent() { + return Thread.currentThread() == glThread; + } + + + protected void beginGL() { } + + + protected void endGL() { } + + + private boolean needFBOLayer(boolean clear0) { + return !clear0 || fboLayerRequested || 1 < numSamples; + } + + + private void createFBOLayer() { + System.out.println("Creating FBO layer"); String ext = getString(EXTENSIONS); if (-1 < ext.indexOf("texture_non_power_of_two")) { fboWidth = pg.width; @@ -656,118 +795,6 @@ public abstract class PGL { } - /////////////////////////////////////////////////////////// - - // Frame rendering - - - protected void beginDraw(boolean clear0) { - if (needFBOLayer(clear0)) { - if (!fboLayerCreated) createFBOLayer(); - - bindFramebuffer(FRAMEBUFFER, glColorFbo.get(0)); - framebufferTexture2D(FRAMEBUFFER, COLOR_ATTACHMENT0, - TEXTURE_2D, glColorTex.get(backTex), 0); - - if (1 < numSamples) { - bindFramebuffer(FRAMEBUFFER, glMultiFbo.get(0)); - } - - if (firstFrame) { - // No need to draw back color buffer because we are in the first frame. - int argb = pg.backgroundColor; - float a = ((argb >> 24) & 0xff) / 255.0f; - float r = ((argb >> 16) & 0xff) / 255.0f; - float g = ((argb >> 8) & 0xff) / 255.0f; - float b = ((argb) & 0xff) / 255.0f; - clearColor(r, g, b, a); - clear(COLOR_BUFFER_BIT); - } else if (!clear0) { - // Render previous back texture (now is the front) as background, - // because no background() is being used ("incremental drawing") - drawTexture(TEXTURE_2D, glColorTex.get(frontTex), - fboWidth, fboHeight, pg.width, pg.height, - 0, 0, pg.width, pg.height, - 0, 0, pg.width, pg.height); - } - - fboLayerInUse = true; - } else { - fboLayerInUse = false; - } - - if (firstFrame) { - firstFrame = false; - } - - if (!USE_FBOLAYER_BY_DEFAULT) { - // The result of this assignment is the following: if the user requested - // at some point the use of the FBO layer, but subsequently didn't - // request it again, then the rendering won't render to the FBO layer if - // not needed by the condif, since it is slower than simple onscreen - // rendering. - fboLayerRequested = false; - } - } - - - protected void endDraw(boolean clear0) { - if (fboLayerInUse) { - syncBackTexture(); - - // Draw the contents of the back texture to the screen framebuffer. - bindFramebuffer(FRAMEBUFFER, 0); - - clearDepth(1); - clearColor(0, 0, 0, 0); - clear(COLOR_BUFFER_BIT | DEPTH_BUFFER_BIT); - - // Render current back texture to screen, without blending. - disable(BLEND); - drawTexture(TEXTURE_2D, glColorTex.get(backTex), - fboWidth, fboHeight, pg.width, pg.height, - 0, 0, pg.width, pg.height, - 0, 0, pg.width, pg.height); - - // Swapping front and back textures. - int temp = frontTex; - frontTex = backTex; - backTex = temp; - } - } - - - protected abstract void getGL(PGL pgl); - - - protected abstract boolean canDraw(); - - - protected abstract void requestFocus(); - - - protected abstract void requestDraw(); - - - protected abstract void swapBuffers(); - - - protected boolean threadIsCurrent() { - return Thread.currentThread() == glThread; - } - - - protected boolean needFBOLayer(boolean clear0) { - return !clear0 || fboLayerRequested || 1 < numSamples; - } - - - protected void beginGL() { } - - - protected void endGL() { } - - /////////////////////////////////////////////////////////// // Context interface @@ -906,8 +933,8 @@ public abstract class PGL { protected void initTex2DShader() { - if (!loadedTex2DShader/* || tex2DShaderContext != glContext*/) { - System.out.println("initializing texture shader"); + if (!loadedTex2DShader || tex2DShaderContext != glContext) { + System.out.println("Initializing PGL texture shader"); String vertSource = PApplet.join(texVertShaderSource, "\n"); String fragSource = PApplet.join(tex2DFragShaderSource, "\n"); tex2DVertShader = createShader(VERTEX_SHADER, vertSource); @@ -927,6 +954,8 @@ public abstract class PGL { texGeoVBO = intBuffer.get(0); bindBuffer(ARRAY_BUFFER, texGeoVBO); bufferData(ARRAY_BUFFER, 16 * SIZEOF_FLOAT, null, STATIC_DRAW); + + System.out.println("Done!"); } if (texData == null) { @@ -1436,6 +1465,17 @@ public abstract class PGL { } + protected static int qualityToSamples(int quality) { + if (quality <= 1) { + return 1; + } else { + // Number of samples is always an even number: + int n = 2 * (quality / 2); + return n; + } + } + + protected String[] loadVertexShader(String filename) { return pg.parent.loadStrings(filename); } @@ -1486,18 +1526,45 @@ public abstract class PGL { } - protected String[] convertFragmentSource(String[] fragSrc0, - int version0, int version1) { + protected static String[] convertFragmentSource(String[] fragSrc0, + int version0, int version1) { + if (version0 == 120 && version1 == 150) { + String[] fragSrc = new String[fragSrc0.length + 2]; + fragSrc[0] = "#version 150"; + fragSrc[1] = "out vec4 fragColor;"; + for (int i = 0; i < fragSrc0.length; i++) { + String line = fragSrc0[i]; + line = line.replace("varying", "in"); + line = line.replace("attribute", "in"); + line = line.replace("gl_FragColor", "fragColor"); + line = line.replace("texture", "texMap"); + line = line.replace("texMap2D(", "texture("); + line = line.replace("texMap2DRect(", "texture("); + fragSrc[i + 2] = line; + } + return fragSrc; + } return fragSrc0; } - protected String[] convertVertexSource(String[] vertSrc0, - int version0, int version1) { + + protected static String[] convertVertexSource(String[] vertSrc0, + int version0, int version1) { + if (version0 == 120 && version1 == 150) { + String[] vertSrc = new String[vertSrc0.length + 1]; + vertSrc[0] = "#version 150"; + for (int i = 0; i < vertSrc0.length; i++) { + String line = vertSrc0[i]; + line = line.replace("attribute", "in"); + line = line.replace("varying", "out"); + vertSrc[i + 1] = line; + } + return vertSrc; + } return vertSrc0; } - protected int createShader(int shaderType, String source) { int shader = createShader(shaderType); if (shader != 0) { diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 732e2a1f1..b86ece976 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -40,66 +40,7 @@ public class PGraphicsOpenGL extends PGraphics { protected PGraphicsOpenGL currentPG; /** Font cache for texture objects. */ - protected WeakHashMap fontMap = - new WeakHashMap(); - - // ........................................................ - - static final String OPENGL_THREAD_ERROR = - "Cannot run the OpenGL renderer outside the main thread, change your code" + - "\nso the drawing calls are all inside the main thread, " + - "\nor use the default renderer instead."; - static final String BLEND_DRIVER_ERROR = - "blendMode(%1$s) is not supported by this hardware (or driver)"; - static final String BLEND_RENDERER_ERROR = - "blendMode(%1$s) is not supported by this renderer"; - static final String ALREADY_BEGAN_CONTOUR_ERROR = - "Already called beginContour()"; - static final String NO_BEGIN_CONTOUR_ERROR = - "Need to call beginContour() first"; - static final String UNSUPPORTED_SMOOTH_LEVEL_ERROR = - "Smooth level %1$s is not available. Using %2$s instead"; - static final String UNSUPPORTED_SMOOTH_ERROR = - "Smooth is not supported by this hardware (or driver)"; - static final String TOO_MANY_SMOOTH_CALLS_ERROR = - "The smooth/noSmooth functions are being called too often.\n" + - "This results in screen flickering, so they will be disabled\n" + - "for the rest of the sketch's execution"; - static final String UNSUPPORTED_SHAPE_FORMAT_ERROR = - "Unsupported shape format"; - static final String MISSING_UV_TEXCOORDS_ERROR = - "No uv texture coordinates supplied with vertex() call"; - static final String INVALID_FILTER_SHADER_ERROR = - "Your shader cannot be used as a filter because is of type POINT or LINES"; - static final String INCONSISTENT_SHADER_TYPES = - "The vertex and fragment shaders have different types"; - static final String WRONG_SHADER_TYPE_ERROR = - "shader() called with a wrong shader"; - static final String SHADER_NEED_LIGHT_ATTRIBS = - "The provided shader needs light attributes (ambient, diffuse, etc.), but " + - "the current scene is unlit, so the default shader will be used instead"; - static final String MISSING_FRAGMENT_SHADER = - "The fragment shader is missing, cannot create shader object"; - static final String MISSING_VERTEX_SHADER = - "The vertex shader is missing, cannot create shader object"; - static final String UNKNOWN_SHADER_KIND_ERROR = - "Unknown shader kind"; - static final String NO_TEXLIGHT_SHADER_ERROR = - "Your shader needs to be of TEXLIGHT type " + - "to render this geometry properly, using default shader instead."; - static final String NO_LIGHT_SHADER_ERROR = - "Your shader needs to be of LIGHT type " + - "to render this geometry properly, using default shader instead."; - static final String NO_TEXTURE_SHADER_ERROR = - "Your shader needs to be of TEXTURE type " + - "to render this geometry properly, using default shader instead."; - static final String NO_COLOR_SHADER_ERROR = - "Your shader needs to be of COLOR type " + - "to render this geometry properly, using default shader instead."; - static final String TOO_LONG_STROKE_PATH_ERROR = - "Stroke path is too long, some bevel triangles won't be added"; - static final String TESSELLATION_ERROR = - "Tessellation Error: %1$s"; + protected WeakHashMap fontMap; // ........................................................ @@ -153,8 +94,8 @@ public class PGraphicsOpenGL extends PGraphics { protected boolean pointBuffersCreated = false; protected int pointBuffersContext; - protected static final int INIT_VERTEX_BUFFER_SIZE = 256; - protected static final int INIT_INDEX_BUFFER_SIZE = 512; + static protected final int INIT_VERTEX_BUFFER_SIZE = 256; + static protected final int INIT_INDEX_BUFFER_SIZE = 512; // ........................................................ @@ -248,8 +189,8 @@ public class PGraphicsOpenGL extends PGraphics { protected InGeometry inGeo; protected TessGeometry tessGeo; - static protected Tessellator tessellator; protected TexCache texCache; + static protected Tessellator tessellator; // ........................................................ @@ -397,11 +338,11 @@ public class PGraphicsOpenGL extends PGraphics { static protected final int FB_STACK_DEPTH = 16; - static protected int fbStackDepth; - static protected FrameBuffer[] fbStack = new FrameBuffer[FB_STACK_DEPTH]; - static protected FrameBuffer drawFramebuffer; - static protected FrameBuffer readFramebuffer; - static protected FrameBuffer currentFramebuffer; + protected int fbStackDepth; + protected FrameBuffer[] fbStack; + protected FrameBuffer drawFramebuffer; + protected FrameBuffer readFramebuffer; + protected FrameBuffer currentFramebuffer; // ....................................................... @@ -508,6 +449,67 @@ public class PGraphicsOpenGL extends PGraphics { static protected IntBuffer intBuffer; static protected FloatBuffer floatBuffer; + // ........................................................ + + // Error strings: + + static final String OPENGL_THREAD_ERROR = + "Cannot run the OpenGL renderer outside the main thread, change your code" + + "\nso the drawing calls are all inside the main thread, " + + "\nor use the default renderer instead."; + static final String BLEND_DRIVER_ERROR = + "blendMode(%1$s) is not supported by this hardware (or driver)"; + static final String BLEND_RENDERER_ERROR = + "blendMode(%1$s) is not supported by this renderer"; + static final String ALREADY_BEGAN_CONTOUR_ERROR = + "Already called beginContour()"; + static final String NO_BEGIN_CONTOUR_ERROR = + "Need to call beginContour() first"; + static final String UNSUPPORTED_SMOOTH_LEVEL_ERROR = + "Smooth level %1$s is not available. Using %2$s instead"; + static final String UNSUPPORTED_SMOOTH_ERROR = + "Smooth is not supported by this hardware (or driver)"; + static final String TOO_MANY_SMOOTH_CALLS_ERROR = + "The smooth/noSmooth functions are being called too often.\n" + + "This results in screen flickering, so they will be disabled\n" + + "for the rest of the sketch's execution"; + static final String UNSUPPORTED_SHAPE_FORMAT_ERROR = + "Unsupported shape format"; + static final String MISSING_UV_TEXCOORDS_ERROR = + "No uv texture coordinates supplied with vertex() call"; + static final String INVALID_FILTER_SHADER_ERROR = + "Your shader cannot be used as a filter because is of type POINT or LINES"; + static final String INCONSISTENT_SHADER_TYPES = + "The vertex and fragment shaders have different types"; + static final String WRONG_SHADER_TYPE_ERROR = + "shader() called with a wrong shader"; + static final String SHADER_NEED_LIGHT_ATTRIBS = + "The provided shader needs light attributes (ambient, diffuse, etc.), but " + + "the current scene is unlit, so the default shader will be used instead"; + static final String MISSING_FRAGMENT_SHADER = + "The fragment shader is missing, cannot create shader object"; + static final String MISSING_VERTEX_SHADER = + "The vertex shader is missing, cannot create shader object"; + static final String UNKNOWN_SHADER_KIND_ERROR = + "Unknown shader kind"; + static final String NO_TEXLIGHT_SHADER_ERROR = + "Your shader needs to be of TEXLIGHT type " + + "to render this geometry properly, using default shader instead."; + static final String NO_LIGHT_SHADER_ERROR = + "Your shader needs to be of LIGHT type " + + "to render this geometry properly, using default shader instead."; + static final String NO_TEXTURE_SHADER_ERROR = + "Your shader needs to be of TEXTURE type " + + "to render this geometry properly, using default shader instead."; + static final String NO_COLOR_SHADER_ERROR = + "Your shader needs to be of COLOR type " + + "to render this geometry properly, using default shader instead."; + static final String TOO_LONG_STROKE_PATH_ERROR = + "Stroke path is too long, some bevel triangles won't be added"; + static final String TESSELLATION_ERROR = + "Tessellation Error: %1$s"; + + ////////////////////////////////////////////////////////////// // INIT/ALLOCATE/FINISH @@ -538,7 +540,12 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void setPrimary(boolean primary) { super.setPrimary(primary); + pgl.setPrimary(primary); format = ARGB; + if (primary) { + fbStack = new FrameBuffer[FB_STACK_DEPTH]; + fontMap = new WeakHashMap(); + } } @@ -643,12 +650,6 @@ public class PGraphicsOpenGL extends PGraphics { if (primarySurface) { pgl.deleteSurface(); - - // This next line is critical to release many static allocations. - // This is important in the context of, say, a unit test suite, which - // runs more than one OpenGL sketch within the same classloader - // (as in the case of processing.py). Please don't remove it! - //pgl = null; } } @@ -1209,37 +1210,45 @@ public class PGraphicsOpenGL extends PGraphics { // FRAMEBUFFERS - protected static void pushFramebuffer() { - if (fbStackDepth == FB_STACK_DEPTH) { + protected void pushFramebuffer() { + PGraphicsOpenGL ppg = getPrimaryPG(); + if (ppg.fbStackDepth == FB_STACK_DEPTH) { throw new RuntimeException("Too many pushFramebuffer calls"); } - fbStack[fbStackDepth] = currentFramebuffer; - fbStackDepth++; + ppg.fbStack[ppg.fbStackDepth] = ppg.currentFramebuffer; + ppg.fbStackDepth++; } - protected static void setFramebuffer(FrameBuffer fbo) { - if (currentFramebuffer != fbo) { - currentFramebuffer = fbo; - currentFramebuffer.bind(); + protected void setFramebuffer(FrameBuffer fbo) { + PGraphicsOpenGL ppg = getPrimaryPG(); + if (ppg.currentFramebuffer != fbo) { + ppg.currentFramebuffer = fbo; + ppg.currentFramebuffer.bind(); } } - protected static void popFramebuffer() { - if (fbStackDepth == 0) { + protected void popFramebuffer() { + PGraphicsOpenGL ppg = getPrimaryPG(); + if (ppg.fbStackDepth == 0) { throw new RuntimeException("popFramebuffer call is unbalanced."); } - fbStackDepth--; - FrameBuffer fbo = fbStack[fbStackDepth]; - if (currentFramebuffer != fbo) { - currentFramebuffer.finish(); - currentFramebuffer = fbo; - currentFramebuffer.bind(); + ppg.fbStackDepth--; + FrameBuffer fbo = ppg.fbStack[ppg.fbStackDepth]; + if (ppg.currentFramebuffer != fbo) { + ppg.currentFramebuffer.finish(); + ppg.currentFramebuffer = fbo; + ppg.currentFramebuffer.bind(); } } + protected FrameBuffer getCurrentFB() { + return getPrimaryPG().currentFramebuffer; + } + + ////////////////////////////////////////////////////////////// // FRAME RENDERING @@ -1797,8 +1806,8 @@ public class PGraphicsOpenGL extends PGraphics { pgl.depthMask(true); } - currentFramebuffer.bind(); - pgl.drawBuffer(currentFramebuffer.getDefaultDrawBuffer()); + getCurrentFB().bind(); + pgl.drawBuffer(getCurrentFB().getDefaultDrawBuffer()); } public void beginReadPixels() { @@ -1831,7 +1840,7 @@ public class PGraphicsOpenGL extends PGraphics { if (op == OP_READ) { if (offscreenMultisample) { // Making sure the offscreen FBO is up-to-date - multisampleFramebuffer.copy(offscreenFramebuffer, currentFramebuffer); + multisampleFramebuffer.copy(offscreenFramebuffer, getCurrentFB()); } // We always read the screen pixels from the color FBO. pixfb = offscreenFramebuffer; @@ -1844,7 +1853,7 @@ public class PGraphicsOpenGL extends PGraphics { } // Set the framebuffer where the pixel operation shall be carried out. - if (pixfb != currentFramebuffer) { + if (pixfb != getCurrentFB()) { pushFramebuffer(); setFramebuffer(pixfb); pixOpChangedFB = true; @@ -1852,9 +1861,9 @@ public class PGraphicsOpenGL extends PGraphics { // We read from/write to the draw buffer. if (op == OP_READ) { - pgl.readBuffer(currentFramebuffer.getDefaultDrawBuffer()); + pgl.readBuffer(getCurrentFB().getDefaultDrawBuffer()); } else if (op == OP_WRITE) { - pgl.drawBuffer(currentFramebuffer.getDefaultDrawBuffer()); + pgl.drawBuffer(getCurrentFB().getDefaultDrawBuffer()); } pixelsOp = op; @@ -1869,8 +1878,8 @@ public class PGraphicsOpenGL extends PGraphics { } // Restoring default read/draw buffer configuration. - pgl.readBuffer(currentFramebuffer.getDefaultReadBuffer()); - pgl.drawBuffer(currentFramebuffer.getDefaultDrawBuffer()); + pgl.readBuffer(getCurrentFB().getDefaultReadBuffer()); + pgl.drawBuffer(getCurrentFB().getDefaultDrawBuffer()); pixelsOp = OP_NONE; } @@ -5609,7 +5618,7 @@ public class PGraphicsOpenGL extends PGraphics { } else if (offscreenMultisample) { // We need to copy the contents of the multisampled buffer to the color // buffer, so the later is up-to-date with the last drawing. - multisampleFramebuffer.copy(offscreenFramebuffer, currentFramebuffer); + multisampleFramebuffer.copy(offscreenFramebuffer, getCurrentFB()); } if (needEndDraw) { @@ -6353,7 +6362,7 @@ public class PGraphicsOpenGL extends PGraphics { // pgl.colorMask(true, true, true, true); if (offscreenMultisample) { - multisampleFramebuffer.copy(offscreenFramebuffer, currentFramebuffer); + multisampleFramebuffer.copy(offscreenFramebuffer, getCurrentFB()); } popFramebuffer(); diff --git a/core/src/processing/opengl/PJOGL.java b/core/src/processing/opengl/PJOGL.java index 6979d4df4..4fbd88e34 100644 --- a/core/src/processing/opengl/PJOGL.java +++ b/core/src/processing/opengl/PJOGL.java @@ -79,6 +79,41 @@ public class PJOGL extends PGL { /** Selected GL profile */ public static GLProfile profile; + static { + System.out.println("Animation thread: " + Thread.currentThread()); + if (PROFILE == 2) { + try { + profile = GLProfile.getGL2ES1(); + } catch (GLException ex) { + profile = GLProfile.getMaxFixedFunc(true); + } + } else if (PROFILE == 3) { + try { + profile = GLProfile.getGL2GL3(); + } catch (GLException ex) { + profile = GLProfile.getMaxProgrammable(true); + } + if (!profile.isGL3()) { + PGraphics.showWarning("Requested profile GL3 but is not available, got: " + profile); + } + } else if (PROFILE == 4) { + try { + profile = GLProfile.getGL4ES3(); + } catch (GLException ex) { + profile = GLProfile.getMaxProgrammable(true); + } + if (!profile.isGL4()) { + PGraphics.showWarning("Requested profile GL4 but is not available, got: " + profile); + } + } else throw new RuntimeException(UNSUPPORTED_GLPROF_ERROR); + System.out.println("Done, got this profile: " + profile); + + if (2 < PROFILE) { + texVertShaderSource = convertVertexSource(texVertShaderSource, 120, 150); + tex2DFragShaderSource = convertFragmentSource(tex2DFragShaderSource, 120, 150); + texRectFragShaderSource = convertFragmentSource(texRectFragShaderSource, 120, 150); + } + } // ........................................................ @@ -173,13 +208,13 @@ public class PJOGL extends PGL { // JOGL's FBO-layer /** Back (== draw, current frame) buffer */ - protected static FBObject backFBO; + protected FBObject backFBO; /** Sink buffer, used in the multisampled case */ - protected static FBObject sinkFBO; + protected FBObject sinkFBO; /** Front (== read, previous frame) buffer */ - protected static FBObject frontFBO; - protected static FBObject.TextureAttachment backTexAttach; - protected static FBObject.TextureAttachment frontTexAttach; + protected FBObject frontFBO; + protected FBObject.TextureAttachment backTexAttach; + protected FBObject.TextureAttachment frontTexAttach; protected boolean changedFrontTex = false; protected boolean changedBackTex = false; @@ -221,6 +256,7 @@ public class PJOGL extends PGL { @Override protected void setFps(float fps) { + checkPrimary(); if (!setFps || targetFps != fps) { if (60 < fps) { // Disables v-sync @@ -238,39 +274,11 @@ public class PJOGL extends PGL { @Override protected void initSurface(int antialias) { - if (profile == null) { - if (PROFILE == 2) { - try { - profile = GLProfile.getGL2ES1(); - } catch (GLException ex) { - profile = GLProfile.getMaxFixedFunc(true); - } - } else if (PROFILE == 3) { - try { - profile = GLProfile.getGL2GL3(); - } catch (GLException ex) { - profile = GLProfile.getMaxProgrammable(true); - } - if (!profile.isGL3()) { - PGraphics.showWarning("Requested profile GL3 but is not available, got: " + profile); - } - } else if (PROFILE == 4) { - try { - profile = GLProfile.getGL4ES3(); - } catch (GLException ex) { - profile = GLProfile.getMaxProgrammable(true); - } - if (!profile.isGL4()) { - PGraphics.showWarning("Requested profile GL4 but is not available, got: " + profile); - } - } else throw new RuntimeException(UNSUPPORTED_GLPROF_ERROR); + checkPrimary(); - if (2 < PROFILE) { - texVertShaderSource = convertVertexSource(texVertShaderSource, 120, 150); - tex2DFragShaderSource = convertFragmentSource(tex2DFragShaderSource, 120, 150); - texRectFragShaderSource = convertFragmentSource(texRectFragShaderSource, 120, 150); - } - } else { + System.out.println("initializing surface"); + + if (canvasAWT != null && canvasNEWT != null) { // Restarting... if (canvasAWT != null) { canvasAWT.removeGLEventListener(listener); @@ -355,11 +363,14 @@ public class PJOGL extends PGL { fboLayerInUse = false; firstFrame = true; setFps = false; + + System.out.println("done"); } @Override protected void reinitSurface() { + checkPrimary(); sinkFBO = backFBO = frontFBO = null; fboLayerCreated = false; fboLayerInUse = false; @@ -409,11 +420,13 @@ public class PJOGL extends PGL { window.removeGLEventListener(listener); } GLProfile.shutdown(); + System.out.println("bye bye"); } @Override protected int getReadFramebuffer() { + checkPrimary(); if (fboLayerInUse) { return glColorFbo.get(0); } else if (capabilities.isFBO()) { @@ -426,6 +439,7 @@ public class PJOGL extends PGL { @Override protected int getDrawFramebuffer() { + checkPrimary(); if (fboLayerInUse) { if (1 < numSamples) { return glMultiFbo.get(0); @@ -442,6 +456,7 @@ public class PJOGL extends PGL { @Override protected int getDefaultDrawBuffer() { + checkPrimary(); if (fboLayerInUse) { return COLOR_ATTACHMENT0; } else if (capabilities.isFBO()) { @@ -456,6 +471,7 @@ public class PJOGL extends PGL { @Override protected int getDefaultReadBuffer() { + checkPrimary(); if (fboLayerInUse) { return COLOR_ATTACHMENT0; } else if (capabilities.isFBO()) { @@ -470,6 +486,7 @@ public class PJOGL extends PGL { @Override protected boolean isFBOBacked() { + checkPrimary(); return super.isFBOBacked() || capabilities.isFBO(); } @@ -488,6 +505,7 @@ public class PJOGL extends PGL { @Override protected Texture wrapBackTexture(Texture texture) { + checkPrimary(); if (texture == null || changedBackTex) { if (USE_JOGL_FBOLAYER) { texture = new Texture(pg); @@ -515,6 +533,7 @@ public class PJOGL extends PGL { @Override protected Texture wrapFrontTexture(Texture texture) { + checkPrimary(); if (texture == null || changedFrontTex) { if (USE_JOGL_FBOLAYER) { texture = new Texture(pg); @@ -542,6 +561,7 @@ public class PJOGL extends PGL { @Override protected void bindFrontTexture() { if (USE_JOGL_FBOLAYER) { + checkPrimary(); usingFrontTex = true; if (!texturingIsEnabled(TEXTURE_2D)) { enableTexturing(TEXTURE_2D); @@ -554,6 +574,7 @@ public class PJOGL extends PGL { @Override protected void unbindFrontTexture() { if (USE_JOGL_FBOLAYER) { + checkPrimary(); if (textureIsBound(TEXTURE_2D, frontTexAttach.getName())) { // We don't want to unbind another texture // that might be bound instead of this one. @@ -572,6 +593,7 @@ public class PJOGL extends PGL { @Override protected void syncBackTexture() { if (USE_JOGL_FBOLAYER) { + checkPrimary(); if (usingFrontTex) needSepFrontTex = true; if (1 < numSamples) { backFBO.syncSamplingSink(gl); @@ -628,7 +650,6 @@ public class PJOGL extends PGL { } - @Override protected boolean canDraw() { return pg.initialized && pg.parent.isDisplayable(); @@ -641,6 +662,7 @@ public class PJOGL extends PGL { @Override protected void requestDraw() { + checkPrimary(); boolean canDraw = pg.parent.canDraw(); if (pg.initialized && (canDraw || prevCanDraw)) { try { @@ -673,6 +695,7 @@ public class PJOGL extends PGL { @Override protected void swapBuffers() { + checkPrimary(); if (WINDOW_TOOLKIT == AWT) { canvasAWT.swapBuffers(); } else if (WINDOW_TOOLKIT == NEWT) { @@ -1129,41 +1152,6 @@ public class PJOGL extends PGL { } - @Override - protected String[] convertFragmentSource(String[] fragSrc0, - int version0, int version1) { - String[] fragSrc = new String[fragSrc0.length + 2]; - fragSrc[0] = "#version 150"; - fragSrc[1] = "out vec4 fragColor;"; - for (int i = 0; i < fragSrc0.length; i++) { - String line = fragSrc0[i]; - line = line.replace("varying", "in"); - line = line.replace("attribute", "in"); - line = line.replace("gl_FragColor", "fragColor"); - line = line.replace("texture", "texMap"); - line = line.replace("texMap2D(", "texture("); - line = line.replace("texMap2DRect(", "texture("); - fragSrc[i + 2] = line; - } - return fragSrc; - } - - - @Override - protected String[] convertVertexSource(String[] vertSrc0, - int version0, int version1) { - String[] vertSrc = new String[vertSrc0.length + 1]; - vertSrc[0] = "#version 150"; - for (int i = 0; i < vertSrc0.length; i++) { - String line = vertSrc0[i]; - line = line.replace("attribute", "in"); - line = line.replace("varying", "out"); - vertSrc[i + 1] = line; - } - return vertSrc; - } - - /////////////////////////////////////////////////////////// // Tessellator diff --git a/core/src/processing/opengl/Texture.java b/core/src/processing/opengl/Texture.java index cd9ab6052..990d584e3 100644 --- a/core/src/processing/opengl/Texture.java +++ b/core/src/processing/opengl/Texture.java @@ -521,10 +521,10 @@ public class Texture implements PConstants { // reading the pixels from the current draw buffer (which is the color // buffer of the FBO). tempFbo.setColorBuffer(this); - PGraphicsOpenGL.pushFramebuffer(); - PGraphicsOpenGL.setFramebuffer(tempFbo); + pg.pushFramebuffer(); + pg.setFramebuffer(tempFbo); tempFbo.readPixels(); - PGraphicsOpenGL.popFramebuffer(); + pg.popFramebuffer(); tempFbo.getPixels(pixels); convertToARGB(pixels); @@ -1248,8 +1248,8 @@ public class Texture implements PConstants { tempFbo.disableDepthTest(); // FBO copy: - PGraphicsOpenGL.pushFramebuffer(); - PGraphicsOpenGL.setFramebuffer(tempFbo); + pg.pushFramebuffer(); + pg.setFramebuffer(tempFbo); // Clear the color buffer to make sure that the alpha channel is set to // full transparency pgl.clearColor(0, 0, 0, 0); @@ -1269,7 +1269,7 @@ public class Texture implements PConstants { tex.glWidth, tex.glHeight, tempFbo.width, tempFbo.height, x, y, w, h, x, y, w, h); } - PGraphicsOpenGL.popFramebuffer(); + pg.popFramebuffer(); updateTexels(x, y, w, h); } @@ -1288,8 +1288,8 @@ public class Texture implements PConstants { tempFbo.disableDepthTest(); // FBO copy: - PGraphicsOpenGL.pushFramebuffer(); - PGraphicsOpenGL.setFramebuffer(tempFbo); + pg.pushFramebuffer(); + pg.setFramebuffer(tempFbo); if (scale) { // Rendering tex into "this", and scaling the source rectangle // to cover the entire destination region. @@ -1305,7 +1305,7 @@ public class Texture implements PConstants { texWidth, texHeight, tempFbo.width, tempFbo.height, x, y, w, h, x, y, w, h); } - PGraphicsOpenGL.popFramebuffer(); + pg.popFramebuffer(); updateTexels(x, y, w, h); }