/** * Disposes of all native resources associated with this surface. */ void OGLSD_Flush(JNIEnv *env, OGLSDOps *oglsdo) { J2dTraceLn1(J2D_TRACE_INFO, "OGLSD_Flush: type=%d", oglsdo->drawableType); if (oglsdo->drawableType == OGLSD_TEXTURE) { if (oglsdo->textureID != 0) { j2d_glDeleteTextures(1, &oglsdo->textureID); oglsdo->textureID = 0; } } else if (oglsdo->drawableType == OGLSD_FBOBJECT) { if (oglsdo->textureID != 0) { j2d_glDeleteTextures(1, &oglsdo->textureID); oglsdo->textureID = 0; } if (oglsdo->depthID != 0) { j2d_glDeleteRenderbuffersEXT(1, &oglsdo->depthID); oglsdo->depthID = 0; } if (oglsdo->fbobjectID != 0) { j2d_glDeleteFramebuffersEXT(1, &oglsdo->fbobjectID); oglsdo->fbobjectID = 0; } } else { // dispose windowing system resources (pbuffer, pixmap, etc) OGLSD_DestroyOGLSurface(env, oglsdo); } }
/** * Returns JNI_TRUE only if all of the following conditions are met: * - the GL_EXT_framebuffer_object extension is available * - FBO support has been enabled via the system property * - we can successfully create an FBO with depth capabilities */ static jboolean OGLContext_IsFBObjectExtensionAvailable(JNIEnv *env, const char *extString) { jboolean isFBObjectEnabled = JNI_FALSE; GLuint fbobjectID, textureID, depthID; jint width = 1, height = 1; J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsFBObjectExtensionAvailable"); // first see if the fbobject extension is available if (!OGLContext_IsExtensionAvailable(extString, "GL_EXT_framebuffer_object")) { return JNI_FALSE; } // next see if the depth texture extension is available if (!OGLContext_IsExtensionAvailable(extString, "GL_ARB_depth_texture")) { return JNI_FALSE; } // next see if the fbobject system property has been enabled isFBObjectEnabled = JNU_GetStaticFieldByName(env, NULL, "sun/java2d/opengl/OGLSurfaceData", "isFBObjectEnabled", "Z").z; if (!isFBObjectEnabled) { J2dRlsTraceLn(J2D_TRACE_INFO, "OGLContext_IsFBObjectExtensionAvailable: disabled via flag"); return JNI_FALSE; } // finally, create a dummy fbobject with depth capabilities to see // if this configuration is supported by the drivers/hardware // (first we initialize a color texture object that will be used to // construct the dummy fbobject) j2d_glGenTextures(1, &textureID); j2d_glBindTexture(GL_TEXTURE_2D, textureID); j2d_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // initialize framebuffer object using color texture created above if (!OGLSD_InitFBObject(&fbobjectID, &depthID, textureID, GL_TEXTURE_2D, width, height)) { J2dRlsTraceLn(J2D_TRACE_INFO, "OGLContext_IsFBObjectExtensionAvailable: fbobject unsupported"); j2d_glDeleteTextures(1, &textureID); return JNI_FALSE; } // delete the temporary resources j2d_glDeleteTextures(1, &textureID); j2d_glDeleteRenderbuffersEXT(1, &depthID); j2d_glDeleteFramebuffersEXT(1, &fbobjectID); J2dRlsTraceLn(J2D_TRACE_INFO, "OGLContext_IsFBObjectExtensionAvailable: fbobject supported"); return JNI_TRUE; }
/** * Initializes a framebuffer object based on the given textureID and its * width/height. This method will iterate through all possible depth formats * to find one that is supported by the drivers/hardware. (Since our use of * the depth buffer is fairly simplistic, we hope to find a depth format that * uses as little VRAM as possible.) If an appropriate depth buffer is found * and all attachments are successful (i.e. the framebuffer object is * "complete"), then this method will return JNI_TRUE and will initialize * the values of fbobjectID and depthID using the IDs created by this method. * Otherwise, this method returns JNI_FALSE. Note that the caller is only * responsible for deleting the allocated fbobject and depth renderbuffer * resources if this method returned JNI_TRUE. */ jboolean OGLSD_InitFBObject(GLuint *fbobjectID, GLuint *depthID, GLuint textureID, GLenum textureTarget, jint textureWidth, jint textureHeight) { GLenum depthFormats[] = { GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT32 }; GLuint fboTmpID, depthTmpID; jboolean foundDepth = JNI_FALSE; int i; J2dTraceLn3(J2D_TRACE_INFO, "OGLSD_InitFBObject: w=%d h=%d texid=%d", textureWidth, textureHeight, textureID); // initialize framebuffer object j2d_glGenFramebuffersEXT(1, &fboTmpID); j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboTmpID); // attach color texture to framebuffer object j2d_glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, textureTarget, textureID, 0); // attempt to create a depth renderbuffer of a particular format; we // will start with the smallest size and then work our way up for (i = 0; i < 3; i++) { GLenum error, status; GLenum depthFormat = depthFormats[i]; int depthSize = 16 + (i * 8); // initialize depth renderbuffer j2d_glGenRenderbuffersEXT(1, &depthTmpID); j2d_glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthTmpID); j2d_glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, depthFormat, textureWidth, textureHeight); // creation of depth buffer could potentially fail, so check for error error = j2d_glGetError(); if (error != GL_NO_ERROR) { J2dTraceLn2(J2D_TRACE_VERBOSE, "OGLSD_InitFBObject: could not create depth buffer: depth=%d error=%x", depthSize, error); j2d_glDeleteRenderbuffersEXT(1, &depthTmpID); continue; } // attach depth renderbuffer to framebuffer object j2d_glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthTmpID); // now check for framebuffer "completeness" status = j2d_glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); if (status == GL_FRAMEBUFFER_COMPLETE_EXT) { // we found a valid format, so break out of the loop J2dTraceLn1(J2D_TRACE_VERBOSE, " framebuffer is complete: depth=%d", depthSize); foundDepth = JNI_TRUE; break; } else { // this depth format didn't work, so delete and try another format J2dTraceLn2(J2D_TRACE_VERBOSE, " framebuffer is incomplete: depth=%d status=%x", depthSize, status); j2d_glDeleteRenderbuffersEXT(1, &depthTmpID); } } // unbind the texture and framebuffer objects (they will be bound again // later as needed) j2d_glBindTexture(textureTarget, 0); j2d_glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); if (!foundDepth) { J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_InitFBObject: could not find valid depth format"); j2d_glDeleteFramebuffersEXT(1, &fboTmpID); return JNI_FALSE; } *fbobjectID = fboTmpID; *depthID = depthTmpID; return JNI_TRUE; }