From 772c977e15e9b8078b2bc3382da26c2f08ba4da4 Mon Sep 17 00:00:00 2001 From: "jul..om" Date: Wed, 24 Oct 2012 19:19:55 +0000 Subject: [PATCH] Adds a few missing features into the shader-based renderer relying on JOGL 2.0 git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9887 75d07b2b-3a1a-0410-a2c5-0572b91ccdca --- .../com/jme3/renderer/jogl/JoglRenderer.java | 826 +++++++++++++----- 1 file changed, 588 insertions(+), 238 deletions(-) diff --git a/engine/src/jogl/com/jme3/renderer/jogl/JoglRenderer.java b/engine/src/jogl/com/jme3/renderer/jogl/JoglRenderer.java index 291a8acc1..af919ddc3 100644 --- a/engine/src/jogl/com/jme3/renderer/jogl/JoglRenderer.java +++ b/engine/src/jogl/com/jme3/renderer/jogl/JoglRenderer.java @@ -77,19 +77,18 @@ import javax.media.opengl.GL2; import javax.media.opengl.GL2ES1; import javax.media.opengl.GL2ES2; import javax.media.opengl.GL2GL3; -import javax.media.opengl.GL3; import javax.media.opengl.GLContext; import javax.media.opengl.fixedfunc.GLLightingFunc; -import javax.media.opengl.fixedfunc.GLMatrixFunc; import javax.media.opengl.fixedfunc.GLPointerFunc; import jme3tools.converters.MipMapGenerator; +import jme3tools.shader.ShaderDebug; public class JoglRenderer implements Renderer { private static final Logger logger = Logger.getLogger(JoglRenderer.class.getName()); private static final boolean VALIDATE_SHADER = false; - //private final ByteBuffer nameBuf = BufferUtils.createByteBuffer(250); - //private final StringBuilder stringBuf = new StringBuilder(250); + private final ByteBuffer nameBuf = BufferUtils.createByteBuffer(250); + private final StringBuilder stringBuf = new StringBuilder(250); private final IntBuffer intBuf1 = BufferUtils.createIntBuffer(1); private final IntBuffer intBuf16 = BufferUtils.createIntBuffer(16); private RenderContext context = new RenderContext(); @@ -128,7 +127,7 @@ public class JoglRenderer implements Renderer { public JoglRenderer() { } - /*protected void updateNameBuffer() { + protected void updateNameBuffer() { int len = stringBuf.length(); nameBuf.position(0); @@ -138,7 +137,7 @@ public class JoglRenderer implements Renderer { } nameBuf.rewind(); - }*/ + } public Statistics getStatistics() { return statistics; @@ -860,20 +859,569 @@ public class JoglRenderer implements Renderer { throw new UnsupportedOperationException("Unrecognized shader type."); } } + + public void updateShaderSourceData(ShaderSource source) { + int id = source.getId(); + GL gl = GLContext.getCurrentGL(); + if (id == -1) { + // Create id + id = gl.getGL2().glCreateShader(convertShaderType(source.getType())); + if (id <= 0) { + throw new RendererException("Invalid ID received when trying to create shader."); + } + + source.setId(id); + } else { + throw new RendererException("Cannot recompile shader source"); + } + + // Upload shader source. + // Merge the defines and source code. + String language = source.getLanguage(); + stringBuf.setLength(0); + if (language.startsWith("GLSL")) { + int version = Integer.parseInt(language.substring(4)); + if (version > 100) { + stringBuf.append("#version "); + stringBuf.append(language.substring(4)); + if (version >= 150) { + stringBuf.append(" core"); + } + stringBuf.append("\n"); + } + } + updateNameBuffer(); + + byte[] definesCodeData = source.getDefines().getBytes(); + byte[] sourceCodeData = source.getSource().getBytes(); + ByteBuffer codeBuf = BufferUtils.createByteBuffer(nameBuf.limit() + + definesCodeData.length + + sourceCodeData.length); + codeBuf.put(nameBuf); + codeBuf.put(definesCodeData); + codeBuf.put(sourceCodeData); + codeBuf.flip(); + + byte[] array = new byte[codeBuf.limit()]; + codeBuf.rewind(); + codeBuf.get(array); + codeBuf.rewind(); + + gl.getGL2ES2().glShaderSource(id, 1, new String[]{new String(array)}, new int[]{array.length}, 0); + gl.getGL2().glCompileShader(id); + + gl.getGL2().glGetShaderiv(id, GL2.GL_COMPILE_STATUS, intBuf1); + + boolean compiledOK = intBuf1.get(0) == GL.GL_TRUE; + String infoLog = null; + + if (VALIDATE_SHADER || !compiledOK) { + // even if compile succeeded, check + // log for warnings + gl.getGL2().glGetShaderiv(id, GL2.GL_INFO_LOG_LENGTH, intBuf1); + int length = intBuf1.get(0); + if (length > 3) { + // get infos + ByteBuffer logBuf = BufferUtils.createByteBuffer(length); + gl.getGL2().glGetShaderInfoLog(id, length, null, logBuf); + byte[] logBytes = new byte[length]; + logBuf.get(logBytes, 0, length); + // convert to string, etc + infoLog = new String(logBytes); + } + } + + if (compiledOK) { + if (infoLog != null) { + logger.log(Level.INFO, "{0} compile success\n{1}", + new Object[]{source.getName(), infoLog}); + } else { + logger.log(Level.FINE, "{0} compile success", source.getName()); + } + source.clearUpdateNeeded(); + } else { + logger.log(Level.WARNING, "Bad compile of:\n{0}", + new Object[]{ShaderDebug.formatShaderSource(source.getDefines(), source.getSource(), stringBuf.toString())}); + if (infoLog != null) { + throw new RendererException("compile error in:" + source + " error:" + infoLog); + } else { + throw new RendererException("compile error in:" + source + " error: "); + } + } + } + + public void updateShaderData(Shader shader) { + GL gl = GLContext.getCurrentGL(); + int id = shader.getId(); + boolean needRegister = false; + if (id == -1) { + // create program + id = gl.getGL2().glCreateProgram(); + if (id == 0) { + throw new RendererException("Invalid ID (" + id + ") received when trying to create shader program."); + } + + shader.setId(id); + needRegister = true; + } + + for (ShaderSource source : shader.getSources()) { + if (source.isUpdateNeeded()) { + updateShaderSourceData(source); + } + gl.getGL2().glAttachShader(id, source.getId()); + } + + if (caps.contains(Caps.OpenGL30)) { + // Check if GLSL version is 1.5 for shader + gl.getGL2().glBindFragDataLocation(id, 0, "outFragColor"); + // For MRT + for (int i = 0; i < maxMRTFBOAttachs; i++) { + gl.getGL2().glBindFragDataLocation(id, i, "outFragData[" + i + "]"); + } + } + + // Link shaders to program + gl.getGL2().glLinkProgram(id); + + // Check link status + gl.getGL2().glGetProgramiv(id, GL2.GL_LINK_STATUS, intBuf1); + boolean linkOK = intBuf1.get(0) == GL.GL_TRUE; + String infoLog = null; + + if (VALIDATE_SHADER || !linkOK) { + gl.getGL2().glGetProgramiv(id, GL2.GL_INFO_LOG_LENGTH, intBuf1); + int length = intBuf1.get(0); + if (length > 3) { + // get infos + ByteBuffer logBuf = BufferUtils.createByteBuffer(length); + gl.getGL2().glGetProgramInfoLog(id, length, null, logBuf); + + // convert to string, etc + byte[] logBytes = new byte[length]; + logBuf.get(logBytes, 0, length); + infoLog = new String(logBytes); + } + } + + if (linkOK) { + if (infoLog != null) { + logger.log(Level.INFO, "shader link success. \n{0}", infoLog); + } else { + logger.fine("shader link success"); + } + shader.clearUpdateNeeded(); + if (needRegister) { + // Register shader for clean up if it was created in this method. + objManager.registerForCleanup(shader); + statistics.onNewShader(); + } else { + // OpenGL spec: uniform locations may change after re-link + resetUniformLocations(shader); + } + } else { + if (infoLog != null) { + throw new RendererException("Shader link failure, shader:" + shader + " info:" + infoLog); + } else { + throw new RendererException("Shader link failure, shader:" + shader + " info: "); + } + } + } + + public void setShader(Shader shader) { + if (shader == null) { + throw new IllegalArgumentException("Shader cannot be null"); + } else { + if (shader.isUpdateNeeded()) { + updateShaderData(shader); + } + + // NOTE: might want to check if any of the + // sources need an update? + + assert shader.getId() > 0; + + updateShaderUniforms(shader); + bindProgram(shader); + } + } public void deleteShaderSource(ShaderSource source) { + if (source.getId() < 0) { + logger.warning("Shader source is not uploaded to GPU, cannot delete."); + return; + } + source.clearUpdateNeeded(); + GL gl = GLContext.getCurrentGL(); + gl.getGL2().glDeleteShader(source.getId()); + source.resetObject(); + } + + public void deleteShader(Shader shader) { + if (shader.getId() == -1) { + logger.warning("Shader is not uploaded to GPU, cannot delete."); + return; + } + + GL gl = GLContext.getCurrentGL(); + for (ShaderSource source : shader.getSources()) { + if (source.getId() != -1) { + gl.getGL2().glDetachShader(shader.getId(), source.getId()); + deleteShaderSource(source); + } + } + + gl.getGL2().glDeleteProgram(shader.getId()); + statistics.onDeleteShader(); + shader.resetObject(); } - public void setShader(Shader shader) { + /*********************************************************************\ + |* Framebuffers *| + \*********************************************************************/ + public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst) { + copyFrameBuffer(src, dst, true); + } + + public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst, boolean copyDepth) { + GL gl = GLContext.getCurrentGL(); + if (gl.isExtensionAvailable("GL_EXT_framebuffer_blit")) { + int srcX0 = 0; + int srcY0 = 0; + int srcX1 = 0; + int srcY1 = 0; + + int dstX0 = 0; + int dstY0 = 0; + int dstX1 = 0; + int dstY1 = 0; + + int prevFBO = context.boundFBO; + + if (mainFbOverride != null) { + if (src == null) { + src = mainFbOverride; + } + if (dst == null) { + dst = mainFbOverride; + } + } + + if (src != null && src.isUpdateNeeded()) { + updateFrameBuffer(src); + } + + if (dst != null && dst.isUpdateNeeded()) { + updateFrameBuffer(dst); + } + + if (src == null) { + gl.glBindFramebuffer(GL2.GL_READ_FRAMEBUFFER, 0); + srcX0 = vpX; + srcY0 = vpY; + srcX1 = vpX + vpW; + srcY1 = vpY + vpH; + } else { + gl.glBindFramebuffer(GL2.GL_READ_FRAMEBUFFER, src.getId()); + srcX1 = src.getWidth(); + srcY1 = src.getHeight(); + } + if (dst == null) { + gl.glBindFramebuffer(GL2.GL_DRAW_FRAMEBUFFER, 0); + dstX0 = vpX; + dstY0 = vpY; + dstX1 = vpX + vpW; + dstY1 = vpY + vpH; + } else { + gl.glBindFramebuffer(GL2.GL_DRAW_FRAMEBUFFER, dst.getId()); + dstX1 = dst.getWidth(); + dstY1 = dst.getHeight(); + } + int mask = GL.GL_COLOR_BUFFER_BIT; + if (copyDepth) { + mask |= GL.GL_DEPTH_BUFFER_BIT; + } + gl.getGL2().glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, mask, + GL.GL_NEAREST); + + + gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, prevFBO); + try { + checkFrameBufferError(); + } catch (IllegalStateException ex) { + logger.log(Level.SEVERE, "Source FBO:\n{0}", src); + logger.log(Level.SEVERE, "Dest FBO:\n{0}", dst); + throw ex; + } + } else { + throw new RendererException("EXT_framebuffer_blit required."); + // TODO: support non-blit copies? + } + } + + private String getTargetBufferName(int buffer) { + switch (buffer) { + case GL.GL_NONE: + return "NONE"; + case GL.GL_FRONT: + return "GL_FRONT"; + case GL.GL_BACK: + return "GL_BACK"; + default: + if (buffer >= GL.GL_COLOR_ATTACHMENT0 + && buffer <= GL2.GL_COLOR_ATTACHMENT15) { + return "GL_COLOR_ATTACHMENT" + + (buffer - GL.GL_COLOR_ATTACHMENT0); + } else { + return "UNKNOWN? " + buffer; + } + } + } + + private void printRealRenderBufferInfo(FrameBuffer fb, RenderBuffer rb, String name) { + GL gl = GLContext.getCurrentGL(); + System.out.println("== Renderbuffer " + name + " =="); + System.out.println("RB ID: " + rb.getId()); + System.out.println("Is proper? " + gl.glIsRenderbuffer(rb.getId())); + + int attachment = convertAttachmentSlot(rb.getSlot()); + + gl.glGetFramebufferAttachmentParameteriv(GL2.GL_DRAW_FRAMEBUFFER, + attachment, + GL.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, intBuf16); + int type = intBuf16.get(0); + gl.glGetFramebufferAttachmentParameteriv(GL2.GL_DRAW_FRAMEBUFFER, + attachment, + GL.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, intBuf16); + int rbName = intBuf16.get(0); + + switch (type) { + case GL.GL_NONE: + System.out.println("Type: None"); + break; + case GL.GL_TEXTURE: + System.out.println("Type: Texture"); + break; + case GL2.GL_RENDERBUFFER: + System.out.println("Type: Buffer"); + System.out.println("RB ID: " + rbName); + break; + } + + + + } + + private void printRealFrameBufferInfo(FrameBuffer fb) { + GL gl = GLContext.getCurrentGL(); + final byte[] param = new byte[1]; + gl.glGetBooleanv(GL2.GL_DOUBLEBUFFER, param, 0); + boolean doubleBuffer = param[0] != (byte) 0x00; + gl.glGetIntegerv(GL2.GL_DRAW_BUFFER, intBuf16); + String drawBuf = getTargetBufferName(intBuf16.get(0)); + gl.glGetIntegerv(GL2.GL_READ_BUFFER, intBuf16); + String readBuf = getTargetBufferName(intBuf16.get(0)); + + int fbId = fb.getId(); + gl.glGetIntegerv(GL2.GL_DRAW_FRAMEBUFFER_BINDING, intBuf16); + int curDrawBinding = intBuf16.get(0); + gl.glGetIntegerv(GL2.GL_READ_FRAMEBUFFER_BINDING, intBuf16); + int curReadBinding = intBuf16.get(0); + + System.out.println("=== OpenGL FBO State ==="); + System.out.println("Context doublebuffered? " + doubleBuffer); + System.out.println("FBO ID: " + fbId); + System.out.println("Is proper? " + gl.glIsFramebuffer(fbId)); + System.out.println("Is bound to draw? " + (fbId == curDrawBinding)); + System.out.println("Is bound to read? " + (fbId == curReadBinding)); + System.out.println("Draw buffer: " + drawBuf); + System.out.println("Read buffer: " + readBuf); + + if (context.boundFBO != fbId) { + gl.glBindFramebuffer(GL2.GL_DRAW_FRAMEBUFFER, fbId); + context.boundFBO = fbId; + } + + if (fb.getDepthBuffer() != null) { + printRealRenderBufferInfo(fb, fb.getDepthBuffer(), "Depth"); + } + for (int i = 0; i < fb.getNumColorBuffers(); i++) { + printRealRenderBufferInfo(fb, fb.getColorBuffer(i), "Color" + i); + } + } + + private void checkFrameBufferError() { + GL gl = GLContext.getCurrentGL(); + int status = gl.glCheckFramebufferStatus(GL.GL_FRAMEBUFFER); + switch (status) { + case GL.GL_FRAMEBUFFER_COMPLETE: + break; + case GL.GL_FRAMEBUFFER_UNSUPPORTED: + // Choose different formats + throw new IllegalStateException("Framebuffer object format is " + + "unsupported by the video hardware."); + case GL.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + throw new IllegalStateException("Framebuffer has erronous attachment."); + case GL.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + throw new IllegalStateException("Framebuffer is missing required attachment."); + case GL.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: + throw new IllegalStateException( + "Framebuffer attachments must have same dimensions."); + case GL.GL_FRAMEBUFFER_INCOMPLETE_FORMATS: + throw new IllegalStateException("Framebuffer attachments must have same formats."); + case GL2GL3.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: + throw new IllegalStateException("Incomplete draw buffer."); + case GL2GL3.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: + throw new IllegalStateException("Incomplete read buffer."); + case GL2GL3.GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: + throw new IllegalStateException("Incomplete multisample buffer."); + default: + // Programming error; will fail on all hardware + throw new IllegalStateException("Some video driver error " + + "or programming error occured. " + + "Framebuffer object status is invalid. "); + } + } + + private void updateRenderBuffer(FrameBuffer fb, RenderBuffer rb) { + GL gl = GLContext.getCurrentGL(); + int id = rb.getId(); + if (id == -1) { + gl.glGenRenderbuffers(1, intBuf1); + id = intBuf1.get(0); + rb.setId(id); + } + + if (context.boundRB != id) { + gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, id); + context.boundRB = id; + } + + if (fb.getWidth() > maxRBSize || fb.getHeight() > maxRBSize) { + throw new UnsupportedOperationException("Resolution " + fb.getWidth() + ":" + + fb.getHeight() + " is not supported."); + } + + if (fb.getSamples() > 0 && gl.isExtensionAvailable("GL_EXT_framebuffer_multisample") + && gl.isFunctionAvailable("glRenderbufferStorageMultisample")) { + int samples = fb.getSamples(); + if (maxFBOSamples < samples) { + samples = maxFBOSamples; + } + gl.getGL2() + .glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, samples, + TextureUtil.convertTextureFormat(rb.getFormat()), fb.getWidth(), + fb.getHeight()); + } else { + gl.glRenderbufferStorage(GL.GL_RENDERBUFFER, + TextureUtil.convertTextureFormat(rb.getFormat()), fb.getWidth(), fb.getHeight()); + } + } + + private int convertAttachmentSlot(int attachmentSlot) { + // can also add support for stencil here + if (attachmentSlot == -100) { + return GL.GL_DEPTH_ATTACHMENT; + } else if (attachmentSlot < 0 || attachmentSlot >= 16) { + throw new UnsupportedOperationException("Invalid FBO attachment slot: " + + attachmentSlot); + } + + return GL.GL_COLOR_ATTACHMENT0 + attachmentSlot; + } + + public void updateRenderTexture(FrameBuffer fb, RenderBuffer rb) { + GL gl = GLContext.getCurrentGL(); + Texture tex = rb.getTexture(); + Image image = tex.getImage(); + if (image.isUpdateNeeded()) { + updateTexImageData(image, tex.getType(), 0); + + // NOTE: For depth textures, sets nearest/no-mips mode + // Required to fix "framebuffer unsupported" + // for old NVIDIA drivers! + setupTextureParams(tex); + } + + gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, convertAttachmentSlot(rb.getSlot()), + convertTextureType(tex.getType(), image.getMultiSamples(), rb.getFace()), + image.getId(), 0); + } + + public void updateFrameBufferAttachment(FrameBuffer fb, RenderBuffer rb) { + boolean needAttach; + if (rb.getTexture() == null) { + // if it hasn't been created yet, then attach is required. + needAttach = rb.getId() == -1; + updateRenderBuffer(fb, rb); + } else { + needAttach = false; + updateRenderTexture(fb, rb); + } + if (needAttach) { + GL gl = GLContext.getCurrentGL(); + gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, convertAttachmentSlot(rb.getSlot()), + GL.GL_RENDERBUFFER, rb.getId()); + } + } + + public void updateFrameBuffer(FrameBuffer fb) { + GL gl = GLContext.getCurrentGL(); + int id = fb.getId(); + if (id == -1) { + // create FBO + gl.glGenFramebuffers(1, intBuf1); + id = intBuf1.get(0); + fb.setId(id); + objManager.registerForCleanup(fb); + + statistics.onNewFrameBuffer(); + } + + if (context.boundFBO != id) { + gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, id); + // binding an FBO automatically sets draw buf to GL_COLOR_ATTACHMENT0 + context.boundDrawBuf = 0; + context.boundFBO = id; + } + + FrameBuffer.RenderBuffer depthBuf = fb.getDepthBuffer(); + if (depthBuf != null) { + updateFrameBufferAttachment(fb, depthBuf); + } + + for (int i = 0; i < fb.getNumColorBuffers(); i++) { + FrameBuffer.RenderBuffer colorBuf = fb.getColorBuffer(i); + updateFrameBufferAttachment(fb, colorBuf); + } + + fb.clearUpdateNeeded(); } + + public Vector2f[] getFrameBufferSamplePositions(FrameBuffer fb) { + if (fb.getSamples() <= 1) { + throw new IllegalArgumentException("Framebuffer must be multisampled"); + } - public void deleteShader(Shader shader) { - } + setFrameBuffer(fb); - public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst) { - copyFrameBuffer(src, dst, true); + Vector2f[] samplePositions = new Vector2f[fb.getSamples()]; + FloatBuffer samplePos = BufferUtils.createFloatBuffer(2); + GL gl = GLContext.getCurrentGL(); + for (int i = 0; i < samplePositions.length; i++) { + gl.getGL2().glGetMultisamplefv(GL2.GL_SAMPLE_POSITION, i, samplePos); + samplePos.clear(); + samplePositions[i] = new Vector2f(samplePos.get(0) - 0.5f, + samplePos.get(1) - 0.5f); + } + return samplePositions; } + public void setMainFrameBufferOverride(FrameBuffer fb) { + mainFbOverride = fb; + } + public void setFrameBuffer(FrameBuffer fb) { if (lastFb == fb) { return; @@ -966,165 +1514,46 @@ public class JoglRenderer implements Renderer { } } - public void updateFrameBuffer(FrameBuffer fb) { - GL gl = GLContext.getCurrentGL(); - int id = fb.getId(); - if (id == -1) { - // create FBO - gl.glGenFramebuffers(1, intBuf1); - id = intBuf1.get(0); - fb.setId(id); - objManager.registerForCleanup(fb); - - statistics.onNewFrameBuffer(); - } - - if (context.boundFBO != id) { - gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, id); - // binding an FBO automatically sets draw buf to GL_COLOR_ATTACHMENT0 - context.boundDrawBuf = 0; - context.boundFBO = id; - } - - FrameBuffer.RenderBuffer depthBuf = fb.getDepthBuffer(); - if (depthBuf != null) { - updateFrameBufferAttachment(fb, depthBuf); - } - - for (int i = 0; i < fb.getNumColorBuffers(); i++) { - FrameBuffer.RenderBuffer colorBuf = fb.getColorBuffer(i); - updateFrameBufferAttachment(fb, colorBuf); - } - - fb.clearUpdateNeeded(); - } - - private int convertAttachmentSlot(int attachmentSlot) { - // can also add support for stencil here - if (attachmentSlot == -100) { - return GL.GL_DEPTH_ATTACHMENT; - } else if (attachmentSlot < 0 || attachmentSlot >= 16) { - throw new UnsupportedOperationException("Invalid FBO attachment slot: " - + attachmentSlot); + public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf) { + if (fb != null) { + return; } - - return GL.GL_COLOR_ATTACHMENT0 + attachmentSlot; - } - - public void updateRenderTexture(FrameBuffer fb, RenderBuffer rb) { GL gl = GLContext.getCurrentGL(); - Texture tex = rb.getTexture(); - Image image = tex.getImage(); - if (image.isUpdateNeeded()) { - updateTexImageData(image, tex.getType(), 0); - - // NOTE: For depth textures, sets nearest/no-mips mode - // Required to fix "framebuffer unsupported" - // for old NVIDIA drivers! - setupTextureParams(tex); - } - - gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, convertAttachmentSlot(rb.getSlot()), - convertTextureType(tex.getType(), image.getMultiSamples(), rb.getFace()), - image.getId(), 0); - } - - public void updateFrameBufferAttachment(FrameBuffer fb, RenderBuffer rb) { - boolean needAttach; - if (rb.getTexture() == null) { - // if it hasn't been created yet, then attach is required. - needAttach = rb.getId() == -1; - updateRenderBuffer(fb, rb); - } else { - needAttach = false; - updateRenderTexture(fb, rb); - } - if (needAttach) { - GL gl = GLContext.getCurrentGL(); - gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, convertAttachmentSlot(rb.getSlot()), - GL.GL_RENDERBUFFER, rb.getId()); - } + gl.glReadPixels(vpX, vpY, vpW, vpH, GL2GL3.GL_BGRA, GL.GL_UNSIGNED_BYTE, byteBuf); } - - private void checkFrameBufferError() { + + private void deleteRenderBuffer(FrameBuffer fb, RenderBuffer rb) { + intBuf1.put(0, rb.getId()); GL gl = GLContext.getCurrentGL(); - int status = gl.glCheckFramebufferStatus(GL.GL_FRAMEBUFFER); - switch (status) { - case GL.GL_FRAMEBUFFER_COMPLETE: - break; - case GL.GL_FRAMEBUFFER_UNSUPPORTED: - // Choose different formats - throw new IllegalStateException("Framebuffer object format is " - + "unsupported by the video hardware."); - case GL.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - throw new IllegalStateException("Framebuffer has erronous attachment."); - case GL.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: - throw new IllegalStateException("Framebuffer is missing required attachment."); - case GL.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: - throw new IllegalStateException( - "Framebuffer attachments must have same dimensions."); - case GL.GL_FRAMEBUFFER_INCOMPLETE_FORMATS: - throw new IllegalStateException("Framebuffer attachments must have same formats."); - case GL2GL3.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: - throw new IllegalStateException("Incomplete draw buffer."); - case GL2GL3.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: - throw new IllegalStateException("Incomplete read buffer."); - case GL2GL3.GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: - throw new IllegalStateException("Incomplete multisample buffer."); - default: - // Programming error; will fail on all hardware - throw new IllegalStateException("Some video driver error " - + "or programming error occured. " - + "Framebuffer object status is invalid. "); - } + gl.glDeleteRenderbuffers(1, intBuf1); } + + public void deleteFrameBuffer(FrameBuffer fb) { + if (fb.getId() != -1) { + GL gl = GLContext.getCurrentGL(); + if (context.boundFBO == fb.getId()) { + gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0); + context.boundFBO = 0; + } - private void updateRenderBuffer(FrameBuffer fb, RenderBuffer rb) { - GL gl = GLContext.getCurrentGL(); - int id = rb.getId(); - if (id == -1) { - gl.glGenRenderbuffers(1, intBuf1); - id = intBuf1.get(0); - rb.setId(id); - } - - if (context.boundRB != id) { - gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, id); - context.boundRB = id; - } - - if (fb.getWidth() > maxRBSize || fb.getHeight() > maxRBSize) { - throw new UnsupportedOperationException("Resolution " + fb.getWidth() + ":" - + fb.getHeight() + " is not supported."); - } - - if (fb.getSamples() > 0 && gl.isExtensionAvailable("GL_EXT_framebuffer_multisample") - && gl.isFunctionAvailable("glRenderbufferStorageMultisample")) { - int samples = fb.getSamples(); - if (maxFBOSamples < samples) { - samples = maxFBOSamples; + if (fb.getDepthBuffer() != null) { + deleteRenderBuffer(fb, fb.getDepthBuffer()); + } + if (fb.getColorBuffer() != null) { + deleteRenderBuffer(fb, fb.getColorBuffer()); } - gl.getGL2() - .glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, samples, - TextureUtil.convertTextureFormat(rb.getFormat()), fb.getWidth(), - fb.getHeight()); - } else { - gl.glRenderbufferStorage(GL.GL_RENDERBUFFER, - TextureUtil.convertTextureFormat(rb.getFormat()), fb.getWidth(), fb.getHeight()); - } - } - public void deleteFrameBuffer(FrameBuffer fb) { - } + intBuf1.put(0, fb.getId()); + gl.glDeleteFramebuffers(1, intBuf1); + fb.resetObject(); - public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf) { - if (fb != null) { - return; + statistics.onDeleteFrameBuffer(); } - GL gl = GLContext.getCurrentGL(); - gl.glReadPixels(vpX, vpY, vpW, vpH, GL2GL3.GL_BGRA, GL.GL_UNSIGNED_BYTE, byteBuf); } + /*********************************************************************\ + |* Textures *| + \*********************************************************************/ private int convertTextureType(Texture.Type type, int samples, int face) { switch (type) { case TwoDimensional: @@ -1908,84 +2337,5 @@ public class JoglRenderer implements Renderer { }*/ } - public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst, boolean copyDepth) { - GL gl = GLContext.getCurrentGL(); - if (gl.isExtensionAvailable("GL_EXT_framebuffer_blit")) { - int srcX0 = 0; - int srcY0 = 0; - int srcX1 = 0; - int srcY1 = 0; - - int dstX0 = 0; - int dstY0 = 0; - int dstX1 = 0; - int dstY1 = 0; - - int prevFBO = context.boundFBO; - - if (mainFbOverride != null) { - if (src == null) { - src = mainFbOverride; - } - if (dst == null) { - dst = mainFbOverride; - } - } - - if (src != null && src.isUpdateNeeded()) { - updateFrameBuffer(src); - } - - if (dst != null && dst.isUpdateNeeded()) { - updateFrameBuffer(dst); - } - - if (src == null) { - gl.glBindFramebuffer(GL2.GL_READ_FRAMEBUFFER, 0); - srcX0 = vpX; - srcY0 = vpY; - srcX1 = vpX + vpW; - srcY1 = vpY + vpH; - } else { - gl.glBindFramebuffer(GL2.GL_READ_FRAMEBUFFER, src.getId()); - srcX1 = src.getWidth(); - srcY1 = src.getHeight(); - } - if (dst == null) { - gl.glBindFramebuffer(GL2.GL_DRAW_FRAMEBUFFER, 0); - dstX0 = vpX; - dstY0 = vpY; - dstX1 = vpX + vpW; - dstY1 = vpY + vpH; - } else { - gl.glBindFramebuffer(GL2.GL_DRAW_FRAMEBUFFER, dst.getId()); - dstX1 = dst.getWidth(); - dstY1 = dst.getHeight(); - } - int mask = GL.GL_COLOR_BUFFER_BIT; - if (copyDepth) { - mask |= GL.GL_DEPTH_BUFFER_BIT; - } - gl.getGL2().glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, - dstX0, dstY0, dstX1, dstY1, mask, - GL.GL_NEAREST); - - - gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, prevFBO); - try { - checkFrameBufferError(); - } catch (IllegalStateException ex) { - logger.log(Level.SEVERE, "Source FBO:\n{0}", src); - logger.log(Level.SEVERE, "Dest FBO:\n{0}", dst); - throw ex; - } - } else { - throw new RendererException("EXT_framebuffer_blit required."); - // TODO: support non-blit copies? - } - } - - public void setMainFrameBufferOverride(FrameBuffer fb) { - mainFbOverride = fb; - } + }