/** * 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 a new OGLContext, which includes the native WGL context handle * and some other important information such as the associated pixel format. * If sharedctx is non-null, its texture objects will be shared with the newly * created HGLRC. If useDisposer is JNI_TRUE, a new DisposerTarget * (with the current Java-level thread object as the referent) will be * created and enqueued in the Disposer, so that this OGLContext will be * disposed of properly when its associated thread exits. Contexts that are * intended to remain for the lifetime of the app (such as the sharedContext) * should specify JNI_FALSE for useDisposer. */ OGLContext * WGLGC_InitOGLContext(JNIEnv *env, WGLGraphicsConfigInfo *wglinfo, jboolean useDisposer) { OGLContext *oglc; WGLCtxInfo *ctxinfo; HGLRC context; static jboolean firstTime = JNI_TRUE; J2dTraceLn(J2D_TRACE_INFO, "in WGLGC_InitOGLContext"); oglc = (OGLContext *)malloc(sizeof(OGLContext)); if (oglc == NULL) { J2dTraceLn(J2D_TRACE_ERROR, "could not allocate memory for oglc"); return NULL; } memset(oglc, 0, sizeof(OGLContext)); ctxinfo = (WGLCtxInfo *)malloc(sizeof(WGLCtxInfo)); if (ctxinfo == NULL) { J2dTraceLn(J2D_TRACE_ERROR, "could not allocate memory for ctxinfo"); free(oglc); return NULL; } context = WGLGC_CreateContext(wglinfo->screen, wglinfo->pixfmt); if (context == 0) { J2dTraceLn(J2D_TRACE_ERROR, "could not create new WGL context"); free(oglc); free(ctxinfo); return NULL; } // REMIND: when using wglShareLists, the two contexts must use an // identical pixel format... if (sharedContext != NULL) { WGLCtxInfo *sharedCtxInfo = (WGLCtxInfo *)sharedContext->ctxInfo; if (!j2d_wglShareLists(sharedCtxInfo->context, context)) { J2dTraceLn(J2D_TRACE_WARNING, "unable to share lists"); } } ctxinfo->context = context; ctxinfo->configInfo = wglinfo; oglc->ctxInfo = ctxinfo; oglc->extInfo = &wglinfo->extInfo; // initialize this value to 1.0f as it is sometimes used when uploading // textures (see OGLBlitLoops_Blit()), and in the case of the shared // context, we skip the InitComposite() step that would otherwise // initialize the oglc->extraAlpha value... oglc->extraAlpha = 1.0f; /** * REMIND: The following is a total hack. The first time we enter * this method, we must be on the main thread attempting to initialize * the default GraphicsConfig. Each time we enter this method, we would * like to upcall to the static EventQueue.isDispatchThread() method. * But the first time we call that static method, we may end up implicitly * loading WToolkit, which will also attempt to call getDefaultConfig(). * But since we still haven't fully initialized the default config, we * re-enter the getDefaultConfig() method (in the same thread), and then * come down through this same method. JNI doesn't seem to like this * situation, and we end up with a seg fault. This may be a JNI bug, * but for now we'll work around it, by avoiding the upcall the first * time around. After that, we should be able to make this upcall without * the nasty side effects. */ if (firstTime) { oglc->onJED = JNI_FALSE; firstTime = JNI_FALSE; } else { oglc->onJED = JNU_CallStaticMethodByName(env, NULL, "java/awt/EventQueue", "isDispatchThread", "()Z").z; } if (useDisposer) { // initialize a new Disposer target (when the Java-level thread object // is about to go away, Disposer will invoke our native dispose // method, which destroys this OGLContext and its associated entries) jobject thread = JNU_CallStaticMethodByName(env, NULL, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;").l; if (thread == NULL) { J2dTraceLn(J2D_TRACE_ERROR, "could not fetch current thread"); j2d_wglDeleteContext(context); free(oglc); free(ctxinfo); return NULL; } Disposer_AddRecord(env, thread, WGLGC_DisposeOGLContext, ptr_to_jlong(oglc)); } return oglc; }