/** * Disposes all memory and resources allocated for the given OGLContext, * which was previously stored in thread-local storage and is about to be * destroyed. */ static void WGLGC_DestroyOGLContext(JNIEnv *env, OGLContext *oglc) { J2dTraceLn(J2D_TRACE_INFO, "in WGLGC_DestroyOGLContext"); if (oglc != NULL) { WGLCtxInfo *ctxinfo = (WGLCtxInfo *)oglc->ctxInfo; // invalidate the current context OGLContext_InvalidateCurrentContext(env); j2d_wglMakeCurrent(NULL, NULL); if (ctxinfo != NULL) { j2d_wglDeleteContext(ctxinfo->context); free(ctxinfo); } if (oglc->xformMatrix != NULL) { free(oglc->xformMatrix); } if (oglc->maskTextureID != 0) { j2d_glDeleteTextures(1, &oglc->maskTextureID); } if (oglc->blitTextureID != 0) { j2d_glDeleteTextures(1, &oglc->blitTextureID); } free(oglc); } }
/** * Disposes all memory and resources allocated for the given OGLContext. */ static void WGLGC_DestroyOGLContext(OGLContext *oglc) { WGLCtxInfo *ctxinfo; J2dTraceLn(J2D_TRACE_INFO, "WGLGC_DestroyOGLContext"); if (oglc == NULL) { J2dRlsTraceLn(J2D_TRACE_ERROR, "WGLGC_DestroyOGLContext: context is null"); return; } // at this point, this context will be current to its scratch surface, // so the following operations should be safe... OGLContext_DestroyContextResources(oglc); ctxinfo = (WGLCtxInfo *)oglc->ctxInfo; if (ctxinfo != NULL) { // release the current context before we continue j2d_wglMakeCurrent(NULL, NULL); if (ctxinfo->context != 0) { j2d_wglDeleteContext(ctxinfo->context); } if (ctxinfo->scratchSurface != 0) { if (ctxinfo->scratchSurfaceDC != 0) { j2d_wglReleasePbufferDCARB(ctxinfo->scratchSurface, ctxinfo->scratchSurfaceDC); } j2d_wglDestroyPbufferARB(ctxinfo->scratchSurface); } free(ctxinfo); } free(oglc); }
/** * Makes the given context current to its associated "scratch" surface. If * the operation is successful, this method will return JNI_TRUE; otherwise, * returns JNI_FALSE. */ static jboolean WGLSD_MakeCurrentToScratch(JNIEnv *env, OGLContext *oglc) { WGLCtxInfo *ctxInfo; J2dTraceLn(J2D_TRACE_INFO, "WGLSD_MakeCurrentToScratch"); if (oglc == NULL) { J2dRlsTraceLn(J2D_TRACE_ERROR, "WGLSD_MakeCurrentToScratch: context is null"); return JNI_FALSE; } ctxInfo = (WGLCtxInfo *)oglc->ctxInfo; if (!j2d_wglMakeCurrent(ctxInfo->scratchSurfaceDC, ctxInfo->context)) { J2dRlsTraceLn(J2D_TRACE_ERROR, "WGLSD_MakeCurrentToScratch: could not make current"); return JNI_FALSE; } return JNI_TRUE; }
JNIEXPORT jlong JNICALL Java_sun_java2d_opengl_WGLGraphicsConfig_makeNativeSharedContextCurrent (JNIEnv *env, jobject wglsd, jlong pCtx) { OGLContext *oglc = (OGLContext *)jlong_to_ptr(pCtx); WGLCtxInfo *ctxinfo; J2dTraceLn(J2D_TRACE_INFO, "in WGLGraphicsConfig_makeNativeSharedContextCurrent"); if (oglc == NULL) { J2dTraceLn(J2D_TRACE_ERROR, "shared context is null"); return 0L; } ctxinfo = (WGLCtxInfo *)oglc->ctxInfo; if (!j2d_wglMakeCurrent(sharedSurfaceDC, ctxinfo->context)) { J2dTraceLn(J2D_TRACE_ERROR, "could not make shared WGL context current"); return 0L; } return pCtx; }
/** * Determines whether the WGL pipeline can be used for a given GraphicsConfig * provided its screen number and visual ID. If the minimum requirements are * met, the native WGLGraphicsConfigInfo structure is initialized for this * GraphicsConfig with the necessary information (pixel format, etc.) * and a pointer to this structure is returned as a jlong. If * initialization fails at any point, zero is returned, indicating that WGL * cannot be used for this GraphicsConfig (we should fallback on the existing * DX pipeline). */ JNIEXPORT jlong JNICALL Java_sun_java2d_opengl_WGLGraphicsConfig_getWGLConfigInfo(JNIEnv *env, jclass wglgc, jint screennum, jint pixfmt) { OGLContext *oglc; PIXELFORMATDESCRIPTOR pfd; HWND hwnd; HDC hdc; HGLRC context; HPBUFFERARB scratch; HDC scratchDC; WGLGraphicsConfigInfo *wglinfo; const unsigned char *versionstr; const char *extstr; jint caps = CAPS_EMPTY; int attrKeys[] = { WGL_DOUBLE_BUFFER_ARB, WGL_ALPHA_BITS_ARB }; int attrVals[2]; J2dRlsTraceLn(J2D_TRACE_INFO, "WGLGraphicsConfig_getWGLConfigInfo"); // initialize GL/WGL extension functions if (!WGLGC_InitExtFuncs(screennum)) { J2dRlsTraceLn(J2D_TRACE_ERROR, "WGLGraphicsConfig_getWGLConfigInfo: could not init ext funcs"); return 0L; } // create a scratch window hwnd = WGLGC_CreateScratchWindow(screennum); if (hwnd == 0) { return 0L; } // get the HDC for the scratch window hdc = GetDC(hwnd); if (hdc == 0) { J2dRlsTraceLn(J2D_TRACE_ERROR, "WGLGraphicsConfig_getWGLConfigInfo: could not get dc for scratch window"); DestroyWindow(hwnd); return 0L; } if (pixfmt == 0) { // find an appropriate pixel format pixfmt = WGLGC_GetPixelFormatForDC(hdc); if (pixfmt == 0) { J2dRlsTraceLn(J2D_TRACE_ERROR, "WGLGraphicsConfig_getWGLConfigInfo: could not find appropriate pixfmt"); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); return 0L; } } if (sharedContext == 0) { // create the one shared context sharedContext = WGLGC_CreateContext(screennum, pixfmt); if (sharedContext == 0) { J2dRlsTraceLn(J2D_TRACE_ERROR, "WGLGraphicsConfig_getWGLConfigInfo: could not create shared context"); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); return 0L; } } // set the pixel format for the scratch window if (!SetPixelFormat(hdc, pixfmt, &pfd)) { J2dRlsTraceLn(J2D_TRACE_ERROR, "WGLGraphicsconfig_getWGLConfigInfo: error setting pixel format"); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); return 0L; } // create the HGLRC (context) for this WGLGraphicsConfig context = j2d_wglCreateContext(hdc); if (context == 0) { J2dRlsTraceLn(J2D_TRACE_ERROR, "WGLGraphicsConfig_getWGLConfigInfo: could not create WGL context"); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); return 0L; } // REMIND: when using wglShareLists, the two contexts must use an // identical pixel format... if (!j2d_wglShareLists(sharedContext, context)) { J2dRlsTraceLn(J2D_TRACE_WARNING, "WGLGraphicsConfig_getWGLConfigInfo: unable to share lists"); } // make the context current so that we can query the OpenGL version // and extension strings if (!j2d_wglMakeCurrent(hdc, context)) { J2dRlsTraceLn(J2D_TRACE_ERROR, "WGLGraphicsConfig_getWGLConfigInfo: could not make temp context current"); j2d_wglDeleteContext(context); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); return 0L; } // get version and extension strings versionstr = j2d_glGetString(GL_VERSION); extstr = j2d_wglGetExtensionsStringARB(hdc); OGLContext_GetExtensionInfo(env, &caps); J2dRlsTraceLn1(J2D_TRACE_INFO, "WGLGraphicsConfig_getWGLConfigInfo: OpenGL version=%s", (versionstr == NULL) ? "null" : (char *)versionstr); if (!OGLContext_IsVersionSupported(versionstr)) { J2dRlsTraceLn(J2D_TRACE_ERROR, "WGLGraphicsConfig_getWGLConfigInfo: OpenGL 1.2 is required"); j2d_wglMakeCurrent(NULL, NULL); j2d_wglDeleteContext(context); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); return 0L; } // check for required WGL extensions if (!OGLContext_IsExtensionAvailable(extstr, "WGL_ARB_pbuffer") || !OGLContext_IsExtensionAvailable(extstr, "WGL_ARB_make_current_read")|| !OGLContext_IsExtensionAvailable(extstr, "WGL_ARB_pixel_format")) { J2dRlsTraceLn(J2D_TRACE_ERROR, "WGLGraphicsConfig_getWGLConfigInfo: required ext(s) unavailable"); j2d_wglMakeCurrent(NULL, NULL); j2d_wglDeleteContext(context); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); return 0L; } // get config-specific capabilities j2d_wglGetPixelFormatAttribivARB(hdc, pixfmt, 0, 2, attrKeys, attrVals); if (attrVals[0]) { caps |= CAPS_DOUBLEBUFFERED; } if (attrVals[1] > 0) { caps |= CAPS_STORED_ALPHA; } // create the scratch pbuffer scratch = j2d_wglCreatePbufferARB(hdc, pixfmt, 1, 1, NULL); // destroy the temporary resources j2d_wglMakeCurrent(NULL, NULL); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); if (scratch == 0) { J2dRlsTraceLn(J2D_TRACE_ERROR, "WGLGraphicsConfig_getWGLConfigInfo: could not create scratch surface"); j2d_wglDeleteContext(context); return 0L; } // get the HDC for the scratch pbuffer scratchDC = j2d_wglGetPbufferDCARB(scratch); if (scratchDC == 0) { J2dRlsTraceLn(J2D_TRACE_ERROR, "WGLGraphicsConfig_getWGLConfigInfo: could not get hdc for scratch surface"); j2d_wglDeleteContext(context); j2d_wglDestroyPbufferARB(scratch); return 0L; } // initialize the OGLContext, which wraps the pixfmt and HGLRC (context) oglc = WGLGC_InitOGLContext(pixfmt, context, scratch, scratchDC, caps); if (oglc == NULL) { J2dRlsTraceLn(J2D_TRACE_ERROR, "WGLGraphicsConfig_getWGLConfigInfo: could not create oglc"); j2d_wglDeleteContext(context); j2d_wglReleasePbufferDCARB(scratch, scratchDC); j2d_wglDestroyPbufferARB(scratch); return 0L; } J2dTraceLn(J2D_TRACE_VERBOSE, "WGLGraphicsConfig_getWGLConfigInfo: finished checking dependencies"); // create the WGLGraphicsConfigInfo record for this config wglinfo = (WGLGraphicsConfigInfo *)malloc(sizeof(WGLGraphicsConfigInfo)); if (wglinfo == NULL) { J2dRlsTraceLn(J2D_TRACE_ERROR, "WGLGraphicsConfig_getWGLConfigInfo: could not allocate memory for wglinfo"); WGLGC_DestroyOGLContext(oglc); return 0L; } wglinfo->screen = screennum; wglinfo->pixfmt = pixfmt; wglinfo->context = oglc; return ptr_to_jlong(wglinfo); }
/** * Initializes the extension function pointers for the given device. Note * that under WGL, extension functions have different entrypoints depending * on the device, so we must first make a context current for the given * device before attempting to load the function pointers via * wglGetProcAddress. * * REMIND: ideally the extension function pointers would not be global, but * rather would be stored in a structure associated with the * WGLGraphicsConfig, so that we use the correct function entrypoint * depending on the destination device... */ static jboolean WGLGC_InitExtFuncs(jint screennum) { HWND hwnd; HDC hdc; HGLRC context; J2dTraceLn(J2D_TRACE_INFO, "WGLGC_InitExtFuncs"); // create a scratch window hwnd = WGLGC_CreateScratchWindow(screennum); if (hwnd == 0) { return JNI_FALSE; } // get the HDC for the scratch window hdc = GetDC(hwnd); if (hdc == 0) { DestroyWindow(hwnd); return JNI_FALSE; } // find and set a basic pixel format for the scratch window if (!WGLGC_SetBasicPixelFormatForDC(hdc)) { J2dRlsTraceLn(J2D_TRACE_ERROR, "WGLGC_InitExtFuncs: could not find appropriate pixfmt"); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); return JNI_FALSE; } // create a temporary context context = j2d_wglCreateContext(hdc); if (context == 0) { J2dRlsTraceLn(J2D_TRACE_ERROR, "WGLGC_InitExtFuncs: could not create temp WGL context"); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); return JNI_FALSE; } // make the context current so that we can load the function pointers // using wglGetProcAddress if (!j2d_wglMakeCurrent(hdc, context)) { J2dRlsTraceLn(J2D_TRACE_ERROR, "WGLGC_InitExtFuncs: could not make temp context current"); j2d_wglDeleteContext(context); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); return JNI_FALSE; } if (!OGLFuncs_InitExtFuncs()) { J2dRlsTraceLn(J2D_TRACE_ERROR, "WGLGC_InitExtFuncs: could not initialize extension funcs"); j2d_wglMakeCurrent(NULL, NULL); j2d_wglDeleteContext(context); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); return JNI_FALSE; } // destroy the temporary resources j2d_wglMakeCurrent(NULL, NULL); j2d_wglDeleteContext(context); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); return JNI_TRUE; }
/** * Determines whether the WGL pipeline can be used for a given GraphicsConfig * provided its screen number and visual ID. If the minimum requirements are * met, the native WGLGraphicsConfigInfo structure is initialized for this * GraphicsConfig with the necessary information (pixel format, etc.) * and a pointer to this structure is returned as a jlong. If * initialization fails at any point, zero is returned, indicating that WGL * cannot be used for this GraphicsConfig (we should fallback on the existing * DX pipeline). */ static jlong WGLGC_GetWGLConfigInfo(JNIEnv *env, jint screennum, jint pixfmt) { PIXELFORMATDESCRIPTOR pfd; HWND hwnd; HDC hdc; HGLRC context; WGLGraphicsConfigInfo *wglinfo; const unsigned char *versionstr; const char *extstr; int attr[] = { WGL_DOUBLE_BUFFER_ARB, 0 }; int db; J2dTraceLn(J2D_TRACE_INFO, "in WGLGC_GetWGLConfigInfo"); // initialize GL/WGL extension functions if (!WGLGC_InitExtFuncs(screennum)) { J2dTraceLn(J2D_TRACE_ERROR, "could not initialize extension funcs"); return 0L; } // create the WGLGraphicsConfigInfo record for this config wglinfo = (WGLGraphicsConfigInfo *)malloc(sizeof(WGLGraphicsConfigInfo)); if (wglinfo == NULL) { J2dTraceLn(J2D_TRACE_ERROR, "could not allocate memory for wglinfo"); return 0L; } // create a scratch window hwnd = WGLGC_CreateScratchWindow(screennum); if (hwnd == 0) { free(wglinfo); return 0L; } // get the HDC for the scratch window hdc = GetDC(hwnd); if (hdc == 0) { J2dTraceLn(J2D_TRACE_ERROR, "could not get dc for scratch window"); DestroyWindow(hwnd); free(wglinfo); return 0L; } if (pixfmt == 0) { // find an appropriate pixel format pixfmt = WGLGC_GetPixelFormatForDC(hdc); if (pixfmt == 0) { J2dTraceLn(J2D_TRACE_ERROR, "could not find appropriate pixfmt"); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); free(wglinfo); return 0L; } } // set the pixel format for the scratch window if (!SetPixelFormat(hdc, pixfmt, &pfd)) { J2dTraceLn(J2D_TRACE_ERROR, "error setting pixel format"); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); free(wglinfo); return 0L; } // create a temporary context context = j2d_wglCreateContext(hdc); if (context == 0) { J2dTraceLn(J2D_TRACE_ERROR, "could not create temp WGL context"); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); free(wglinfo); return 0L; } // make the context current so that we can query the OpenGL version // and extension strings if (!j2d_wglMakeCurrent(hdc, context)) { J2dTraceLn(J2D_TRACE_ERROR, "could not make temp context current"); j2d_wglDeleteContext(context); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); free(wglinfo); return 0L; } // invalidate the current context OGLContext_InvalidateCurrentContext(env); // get version and extension strings versionstr = j2d_glGetString(GL_VERSION); extstr = j2d_wglGetExtensionsStringARB(hdc); OGLContext_GetExtensionInfo(&wglinfo->extInfo); J2dTraceLn1(J2D_TRACE_INFO, "OpenGL version: %s", versionstr); if (!OGLContext_IsVersionSupported(versionstr)) { J2dTraceLn(J2D_TRACE_ERROR, "invalid OpenGL version; 1.2 is required"); j2d_wglMakeCurrent(NULL, NULL); j2d_wglDeleteContext(context); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); free(wglinfo); return 0L; } // check for required WGL extensions if (!OGLContext_IsExtensionAvailable(extstr, "WGL_ARB_pbuffer") || !OGLContext_IsExtensionAvailable(extstr, "WGL_ARB_render_texture") || !OGLContext_IsExtensionAvailable(extstr, "WGL_ARB_pixel_format")) { J2dTraceLn(J2D_TRACE_ERROR, "required extension(s) not available"); j2d_wglMakeCurrent(NULL, NULL); j2d_wglDeleteContext(context); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); free(wglinfo); return 0L; } // check whether pixel format is double buffered j2d_wglGetPixelFormatAttribivARB(hdc, pixfmt, 0, 1, attr, &db); // destroy the temporary resources j2d_wglMakeCurrent(NULL, NULL); j2d_wglDeleteContext(context); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); J2dTraceLn(J2D_TRACE_VERBOSE, "successfully finished checking dependencies"); wglinfo->screen = screennum; wglinfo->pixfmt = pixfmt; wglinfo->isDoubleBuffered = db; // create the single shared context (if it hasn't been created already) if (sharedContext == NULL) { if (WGLGC_InitSharedContext(env, wglinfo) == SD_FAILURE) { J2dTraceLn(J2D_TRACE_ERROR, "could not init shared context"); free(wglinfo); return 0L; } } return ptr_to_jlong(wglinfo); }
/** * Makes a context current to the given source and destination * surfaces. If there is a problem making the context current, this method * will return NULL; otherwise, returns a pointer to the OGLContext that is * associated with the destination surface. */ OGLContext * OGLSD_MakeOGLContextCurrent(JNIEnv *env, OGLSDOps *srcOps, OGLSDOps *dstOps) { WGLSDOps *srcWGLOps = (WGLSDOps *)srcOps->privOps; WGLSDOps *dstWGLOps = (WGLSDOps *)dstOps->privOps; OGLContext *oglc; WGLCtxInfo *ctxinfo; HDC srcHDC, dstHDC; BOOL success; J2dTraceLn(J2D_TRACE_INFO, "OGLSD_MakeOGLContextCurrent"); J2dTraceLn4(J2D_TRACE_VERBOSE, " src: %d %p dst: %d %p", srcOps->drawableType, srcOps, dstOps->drawableType, dstOps); oglc = dstWGLOps->configInfo->context; if (oglc == NULL) { J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_MakeOGLContextCurrent: context is null"); return NULL; } if (dstOps->drawableType == OGLSD_FBOBJECT) { OGLContext *currentContext = OGLRenderQueue_GetCurrentContext(); // first make sure we have a current context (if the context isn't // already current to some drawable, we will make it current to // its scratch surface) if (oglc != currentContext) { if (!WGLSD_MakeCurrentToScratch(env, oglc)) { return NULL; } } // now bind to the fbobject associated with the destination surface; // this means that all rendering will go into the fbobject destination // (note that we unbind the currently bound texture first; this is // recommended procedure when binding an fbobject) j2d_glBindTexture(dstOps->textureTarget, 0); j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dstOps->fbobjectID); return oglc; } ctxinfo = (WGLCtxInfo *)oglc->ctxInfo; // get the hdc for the destination surface if (dstOps->drawableType == OGLSD_PBUFFER) { dstHDC = dstWGLOps->pbufferDC; } else { dstHDC = GetDC(dstWGLOps->window); } // get the hdc for the source surface if (srcOps->drawableType == OGLSD_PBUFFER) { srcHDC = srcWGLOps->pbufferDC; } else { // the source will always be equal to the destination in this case srcHDC = dstHDC; } // REMIND: in theory we should be able to use wglMakeContextCurrentARB() // even when the src/dst surfaces are the same, but this causes problems // on ATI's drivers (see 6525997); for now we will only use it when the // surfaces are different, otherwise we will use the old // wglMakeCurrent() approach... if (srcHDC != dstHDC) { // use WGL_ARB_make_current_read extension to make context current success = j2d_wglMakeContextCurrentARB(dstHDC, srcHDC, ctxinfo->context); } else { // use the old approach for making current to the destination success = j2d_wglMakeCurrent(dstHDC, ctxinfo->context); } if (!success) { J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_MakeOGLContextCurrent: could not make current"); if (dstOps->drawableType != OGLSD_PBUFFER) { ReleaseDC(dstWGLOps->window, dstHDC); } return NULL; } if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) { // the GL_EXT_framebuffer_object extension is present, so we // must bind to the default (windowing system provided) // framebuffer j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } if (dstOps->drawableType != OGLSD_PBUFFER) { ReleaseDC(dstWGLOps->window, dstHDC); } return oglc; }