1 /*
   2  * Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include <stdlib.h>
  27 #include <string.h>
  28 
  29 #include "sun_java2d_opengl_WGLGraphicsConfig.h"
  30 
  31 #include "jni.h"
  32 #include "jni_util.h"
  33 #include "jlong.h"
  34 #include "WGLGraphicsConfig.h"
  35 #include "WGLSurfaceData.h"
  36 
  37 /**
  38  * This is a globally shared context used when creating textures.  When any
  39  * new contexts are created, they specify this context as the "share list"
  40  * context, which means any texture objects created when this shared context
  41  * is current will be available to any other context in any other thread.
  42  */
  43 HGLRC sharedContext = 0;
  44 
  45 /**
  46  * Attempts to initialize WGL and the core OpenGL library.  For this method
  47  * to return JNI_TRUE, the following must be true:
  48  *     - opengl32.dll must be loaded successfully (via LoadLibrary)
  49  *     - all core WGL/OGL function symbols from opengl32.dll must be
  50  *       available and loaded properly
  51  * If any of these requirements are not met, this method will return
  52  * JNI_FALSE, indicating there is no hope of using WGL/OpenGL for any
  53  * GraphicsConfig in the environment.
  54  */
  55 JNIEXPORT jboolean JNICALL
  56 Java_sun_java2d_opengl_WGLGraphicsConfig_initWGL(JNIEnv *env, jclass wglgc)
  57 {
  58     J2dRlsTraceLn(J2D_TRACE_INFO, "WGLGraphicsConfig_initWGL");
  59 
  60     if (!OGLFuncs_OpenLibrary()) {
  61         return JNI_FALSE;
  62     }
  63 
  64     if (!OGLFuncs_InitPlatformFuncs() ||
  65         !OGLFuncs_InitBaseFuncs())
  66     {
  67         OGLFuncs_CloseLibrary();
  68         return JNI_FALSE;
  69     }
  70 
  71     return JNI_TRUE;
  72 }
  73 
  74 /**
  75  * Disposes all memory and resources allocated for the given OGLContext.
  76  */
  77 static void
  78 WGLGC_DestroyOGLContext(OGLContext *oglc)
  79 {
  80     WGLCtxInfo *ctxinfo;
  81 
  82     J2dTraceLn(J2D_TRACE_INFO, "WGLGC_DestroyOGLContext");
  83 
  84     if (oglc == NULL) {
  85         J2dRlsTraceLn(J2D_TRACE_ERROR,
  86                       "WGLGC_DestroyOGLContext: context is null");
  87         return;
  88     }
  89 
  90     // at this point, this context will be current to its scratch surface,
  91     // so the following operations should be safe...
  92 
  93     OGLContext_DestroyContextResources(oglc);
  94 
  95     ctxinfo = (WGLCtxInfo *)oglc->ctxInfo;
  96     if (ctxinfo != NULL) {
  97         // release the current context before we continue
  98         j2d_wglMakeCurrent(NULL, NULL);
  99 
 100         if (ctxinfo->context != 0) {
 101             j2d_wglDeleteContext(ctxinfo->context);
 102         }
 103         if (ctxinfo->scratchSurface != 0) {
 104             if (ctxinfo->scratchSurfaceDC != 0) {
 105                 j2d_wglReleasePbufferDCARB(ctxinfo->scratchSurface,
 106                                            ctxinfo->scratchSurfaceDC);
 107             }
 108             j2d_wglDestroyPbufferARB(ctxinfo->scratchSurface);
 109         }
 110 
 111         free(ctxinfo);
 112     }
 113 
 114     free(oglc);
 115 }
 116 
 117 /**
 118  * Disposes all memory and resources associated with the given
 119  * WGLGraphicsConfigInfo (including its native OGLContext data).
 120  */
 121 void
 122 OGLGC_DestroyOGLGraphicsConfig(jlong pConfigInfo)
 123 {
 124     WGLGraphicsConfigInfo *wglinfo =
 125         (WGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
 126 
 127     J2dTraceLn(J2D_TRACE_INFO, "OGLGC_DestroyOGLGraphicsConfig");
 128 
 129     if (wglinfo == NULL) {
 130         J2dRlsTraceLn(J2D_TRACE_ERROR,
 131                       "OGLGC_DestroyOGLGraphicsConfig: info is null");
 132         return;
 133     }
 134 
 135     if (wglinfo->context != NULL) {
 136         WGLGC_DestroyOGLContext(wglinfo->context);
 137     }
 138 
 139     free(wglinfo);
 140 }
 141 
 142 /**
 143  * Creates a temporary (non-visible) window that can be used for querying
 144  * the OpenGL capabilities of a given device.
 145  *
 146  * REMIND: should be able to create a window on a specific device...
 147  */
 148 HWND
 149 WGLGC_CreateScratchWindow(jint screennum)
 150 {
 151     static jboolean firsttime = JNI_TRUE;
 152 
 153     J2dTraceLn(J2D_TRACE_INFO, "WGLGC_CreateScratchWindow");
 154 
 155     if (firsttime) {
 156         WNDCLASS wc;
 157 
 158         // setup window class information
 159         ZeroMemory(&wc, sizeof(WNDCLASS));
 160         wc.hInstance = GetModuleHandle(NULL);
 161         wc.lpfnWndProc = DefWindowProc;
 162         wc.lpszClassName = L"Tmp";
 163         if (RegisterClass(&wc) == 0) {
 164             J2dRlsTraceLn(J2D_TRACE_ERROR,
 165                 "WGLGC_CreateScratchWindow: error registering window class");
 166             return 0;
 167         }
 168 
 169         firsttime = JNI_FALSE;
 170     }
 171 
 172     // create scratch window
 173     return CreateWindow(L"Tmp", L"Tmp", 0,
 174                         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
 175                         CW_USEDEFAULT, NULL, NULL,
 176                         GetModuleHandle(NULL), NULL);
 177 }
 178 
 179 /**
 180  * Returns a pixel format identifier that is suitable for Java 2D's needs
 181  * (must have a depth buffer, support for pbuffers, etc).  This method will
 182  * iterate through all pixel formats (if any) that match the requested
 183  * attributes and will attempt to find a pixel format with a minimal combined
 184  * depth+stencil buffer.  Note that we currently only need depth capabilities
 185  * (for shape clipping purposes), but wglChoosePixelFormatARB() will often
 186  * return a list of pixel formats with the largest depth buffer (and stencil)
 187  * sizes at the top of the list.  Therefore, we scan through the whole list
 188  * to find the most VRAM-efficient pixel format.  If no appropriate pixel
 189  * format can be found, this method returns 0.
 190  */
 191 static int
 192 WGLGC_GetPixelFormatForDC(HDC hdc)
 193 {
 194     int attrs[] = {
 195         WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
 196         WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
 197         WGL_DRAW_TO_PBUFFER_ARB, GL_TRUE,
 198         WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
 199         WGL_DEPTH_BITS_ARB, 16, // anything >= 16 will work for us
 200         0
 201     };
 202     int pixfmts[32];
 203     int chosenPixFmt = 0;
 204     int nfmts, i;
 205 
 206     // this is the initial minimum value for the combined depth+stencil size
 207     // (we initialize it to some absurdly high value; realistic values will
 208     // be much less than this number)
 209     int minDepthPlusStencil = 512;
 210 
 211     J2dRlsTraceLn(J2D_TRACE_INFO, "WGLGC_GetPixelFormatForDC");
 212 
 213     // find all pixel formats (maximum of 32) with the provided attributes
 214     if (!j2d_wglChoosePixelFormatARB(hdc, attrs, NULL, 32, pixfmts, &nfmts)) {
 215         J2dRlsTraceLn(J2D_TRACE_ERROR,
 216             "WGLGC_GetPixelFormatForDC: error choosing pixel format");
 217         return 0;
 218     }
 219 
 220     if (nfmts <= 0) {
 221         J2dRlsTraceLn(J2D_TRACE_ERROR,
 222             "WGLGC_GetPixelFormatForDC: no pixel formats found");
 223         return 0;
 224     }
 225 
 226     J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  candidate pixel formats:");
 227 
 228     // iterate through the list of pixel formats, looking for the one that
 229     // meets our requirements while keeping the combined depth+stencil sizes
 230     // to a minimum
 231     for (i = 0; i < nfmts; i++) {
 232         int attrKeys[] = {
 233             WGL_DEPTH_BITS_ARB, WGL_STENCIL_BITS_ARB,
 234             WGL_DOUBLE_BUFFER_ARB, WGL_ALPHA_BITS_ARB
 235         };
 236         int attrVals[4];
 237         int pixfmt = pixfmts[i];
 238         int depth, stencil, db, alpha;
 239 
 240         j2d_wglGetPixelFormatAttribivARB(hdc, pixfmt, 0, 4,
 241                                          attrKeys, attrVals);
 242 
 243         depth   = attrVals[0];
 244         stencil = attrVals[1];
 245         db      = attrVals[2];
 246         alpha   = attrVals[3];
 247 
 248         J2dRlsTrace5(J2D_TRACE_VERBOSE,
 249             "[V]     pixfmt=%d db=%d alpha=%d depth=%d stencil=%d valid=",
 250                      pixfmt, db, alpha, depth, stencil);
 251 
 252         if ((depth + stencil) < minDepthPlusStencil) {
 253             J2dRlsTrace(J2D_TRACE_VERBOSE, "true\n");
 254             minDepthPlusStencil = depth + stencil;
 255             chosenPixFmt = pixfmt;
 256         } else {
 257             J2dRlsTrace(J2D_TRACE_VERBOSE, "false (large depth)\n");
 258         }
 259     }
 260 
 261     if (chosenPixFmt == 0) {
 262         J2dRlsTraceLn(J2D_TRACE_ERROR,
 263             "WGLGC_GetPixelFormatForDC: could not find appropriate pixfmt");
 264         return 0;
 265     }
 266 
 267     J2dRlsTraceLn1(J2D_TRACE_INFO,
 268         "WGLGC_GetPixelFormatForDC: chose %d as the best pixel format",
 269                    chosenPixFmt);
 270 
 271     return chosenPixFmt;
 272 }
 273 
 274 /**
 275  * Sets a "basic" pixel format for the given HDC.  This method is used only
 276  * for initializing a scratch window far enough such that we can load
 277  * GL/WGL extension function pointers using wglGetProcAddress.  (This method
 278  * differs from the one above in that it does not use wglChoosePixelFormatARB,
 279  * which is a WGL extension function, since we can't use that method without
 280  * first loading the extension functions under a "basic" pixel format.)
 281  */
 282 static jboolean
 283 WGLGC_SetBasicPixelFormatForDC(HDC hdc)
 284 {
 285     PIXELFORMATDESCRIPTOR pfd;
 286     int pixfmt;
 287 
 288     J2dTraceLn(J2D_TRACE_INFO, "WGLGC_SetBasicPixelFormatForDC");
 289 
 290     // find pixel format
 291     ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
 292     pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
 293     pfd.nVersion = 1;
 294     pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
 295     pfd.iPixelType = PFD_TYPE_RGBA;
 296     pixfmt = ChoosePixelFormat(hdc, &pfd);
 297 
 298     if (!SetPixelFormat(hdc, pixfmt, &pfd)) {
 299         J2dRlsTraceLn(J2D_TRACE_ERROR,
 300             "WGLGC_SetBasicPixelFormatForDC: error setting pixel format");
 301         return JNI_FALSE;
 302     }
 303 
 304     return JNI_TRUE;
 305 }
 306 
 307 /**
 308  * Creates a context that is compatible with the given pixel format
 309  * identifier.  Returns 0 if the context could not be created properly.
 310  */
 311 static HGLRC
 312 WGLGC_CreateContext(jint screennum, jint pixfmt)
 313 {
 314     PIXELFORMATDESCRIPTOR pfd;
 315     HWND hwnd;
 316     HDC hdc;
 317     HGLRC hglrc;
 318 
 319     J2dTraceLn(J2D_TRACE_INFO, "WGLGC_CreateContext");
 320 
 321     hwnd = WGLGC_CreateScratchWindow(screennum);
 322     if (hwnd == 0) {
 323         J2dRlsTraceLn(J2D_TRACE_ERROR,
 324             "WGLGC_CreateContext: could not create scratch window");
 325         return 0;
 326     }
 327 
 328     // get the HDC for the scratch window
 329     hdc = GetDC(hwnd);
 330     if (hdc == 0) {
 331         J2dRlsTraceLn(J2D_TRACE_ERROR,
 332             "WGLGC_CreateContext: could not get dc for scratch window");
 333         DestroyWindow(hwnd);
 334         return 0;
 335     }
 336 
 337     // set the pixel format for the scratch window
 338     if (!SetPixelFormat(hdc, pixfmt, &pfd)) {
 339         J2dRlsTraceLn(J2D_TRACE_ERROR,
 340             "WGLGC_CreateContext: error setting pixel format");
 341         ReleaseDC(hwnd, hdc);
 342         DestroyWindow(hwnd);
 343         return 0;
 344     }
 345 
 346     // create a context based on the scratch window
 347     hglrc = j2d_wglCreateContext(hdc);
 348 
 349     // release the temporary resources
 350     ReleaseDC(hwnd, hdc);
 351     DestroyWindow(hwnd);
 352 
 353     return hglrc;
 354 }
 355 
 356 /**
 357  * Initializes the extension function pointers for the given device.  Note
 358  * that under WGL, extension functions have different entrypoints depending
 359  * on the device, so we must first make a context current for the given
 360  * device before attempting to load the function pointers via
 361  * wglGetProcAddress.
 362  *
 363  * REMIND: ideally the extension function pointers would not be global, but
 364  *         rather would be stored in a structure associated with the
 365  *         WGLGraphicsConfig, so that we use the correct function entrypoint
 366  *         depending on the destination device...
 367  */
 368 static jboolean
 369 WGLGC_InitExtFuncs(jint screennum)
 370 {
 371     HWND hwnd;
 372     HDC hdc;
 373     HGLRC context;
 374 
 375     J2dTraceLn(J2D_TRACE_INFO, "WGLGC_InitExtFuncs");
 376 
 377     // create a scratch window
 378     hwnd = WGLGC_CreateScratchWindow(screennum);
 379     if (hwnd == 0) {
 380         return JNI_FALSE;
 381     }
 382 
 383     // get the HDC for the scratch window
 384     hdc = GetDC(hwnd);
 385     if (hdc == 0) {
 386         DestroyWindow(hwnd);
 387         return JNI_FALSE;
 388     }
 389 
 390     // find and set a basic pixel format for the scratch window
 391     if (!WGLGC_SetBasicPixelFormatForDC(hdc)) {
 392         J2dRlsTraceLn(J2D_TRACE_ERROR,
 393             "WGLGC_InitExtFuncs: could not find appropriate pixfmt");
 394         ReleaseDC(hwnd, hdc);
 395         DestroyWindow(hwnd);
 396         return JNI_FALSE;
 397     }
 398 
 399     // create a temporary context
 400     context = j2d_wglCreateContext(hdc);
 401     if (context == 0) {
 402         J2dRlsTraceLn(J2D_TRACE_ERROR,
 403             "WGLGC_InitExtFuncs: could not create temp WGL context");
 404         ReleaseDC(hwnd, hdc);
 405         DestroyWindow(hwnd);
 406         return JNI_FALSE;
 407     }
 408 
 409     // make the context current so that we can load the function pointers
 410     // using wglGetProcAddress
 411     if (!j2d_wglMakeCurrent(hdc, context)) {
 412         J2dRlsTraceLn(J2D_TRACE_ERROR,
 413             "WGLGC_InitExtFuncs: could not make temp context current");
 414         j2d_wglDeleteContext(context);
 415         ReleaseDC(hwnd, hdc);
 416         DestroyWindow(hwnd);
 417         return JNI_FALSE;
 418     }
 419 
 420     if (!OGLFuncs_InitExtFuncs()) {
 421         J2dRlsTraceLn(J2D_TRACE_ERROR,
 422             "WGLGC_InitExtFuncs: could not initialize extension funcs");
 423         j2d_wglMakeCurrent(NULL, NULL);
 424         j2d_wglDeleteContext(context);
 425         ReleaseDC(hwnd, hdc);
 426         DestroyWindow(hwnd);
 427         return JNI_FALSE;
 428     }
 429 
 430     // destroy the temporary resources
 431     j2d_wglMakeCurrent(NULL, NULL);
 432     j2d_wglDeleteContext(context);
 433     ReleaseDC(hwnd, hdc);
 434     DestroyWindow(hwnd);
 435 
 436     return JNI_TRUE;
 437 }
 438 
 439 /**
 440  * Initializes a new OGLContext, which includes the native WGL context handle
 441  * and some other important information such as the associated pixel format.
 442  */
 443 static OGLContext *
 444 WGLGC_InitOGLContext(jint pixfmt, HGLRC context,
 445                      HPBUFFERARB scratch, HDC scratchDC, jint caps)
 446 {
 447     OGLContext *oglc;
 448     WGLCtxInfo *ctxinfo;
 449 
 450     J2dTraceLn(J2D_TRACE_INFO, "WGLGC_InitOGLContext");
 451 
 452     oglc = (OGLContext *)malloc(sizeof(OGLContext));
 453     if (oglc == NULL) {
 454         J2dRlsTraceLn(J2D_TRACE_ERROR,
 455             "WGLGC_InitOGLContext: could not allocate memory for oglc");
 456         return NULL;
 457     }
 458 
 459     memset(oglc, 0, sizeof(OGLContext));
 460 
 461     ctxinfo = (WGLCtxInfo *)malloc(sizeof(WGLCtxInfo));
 462     if (ctxinfo == NULL) {
 463         J2dRlsTraceLn(J2D_TRACE_ERROR,
 464             "WGLGC_InitOGLContext: could not allocate memory for ctxinfo");
 465         free(oglc);
 466         return NULL;
 467     }
 468 
 469     ctxinfo->context = context;
 470     ctxinfo->scratchSurface = scratch;
 471     ctxinfo->scratchSurfaceDC = scratchDC;
 472     oglc->ctxInfo = ctxinfo;
 473     oglc->caps = caps;
 474 
 475     return oglc;
 476 }
 477 
 478 /**
 479  * Determines whether the WGL pipeline can be used for a given GraphicsConfig
 480  * provided its screen number and visual ID.  If the minimum requirements are
 481  * met, the native WGLGraphicsConfigInfo structure is initialized for this
 482  * GraphicsConfig with the necessary information (pixel format, etc.)
 483  * and a pointer to this structure is returned as a jlong.  If
 484  * initialization fails at any point, zero is returned, indicating that WGL
 485  * cannot be used for this GraphicsConfig (we should fallback on the existing
 486  * DX pipeline).
 487  */
 488 JNIEXPORT jlong JNICALL
 489 Java_sun_java2d_opengl_WGLGraphicsConfig_getWGLConfigInfo(JNIEnv *env,
 490                                                           jclass wglgc,
 491                                                           jint screennum,
 492                                                           jint pixfmt)
 493 {
 494     OGLContext *oglc;
 495     PIXELFORMATDESCRIPTOR pfd;
 496     HWND hwnd;
 497     HDC hdc;
 498     HGLRC context;
 499     HPBUFFERARB scratch;
 500     HDC scratchDC;
 501     WGLGraphicsConfigInfo *wglinfo;
 502     const unsigned char *versionstr;
 503     const char *extstr;
 504     jint caps = CAPS_EMPTY;
 505     int attrKeys[] = { WGL_DOUBLE_BUFFER_ARB, WGL_ALPHA_BITS_ARB };
 506     int attrVals[2];
 507 
 508     J2dRlsTraceLn(J2D_TRACE_INFO, "WGLGraphicsConfig_getWGLConfigInfo");
 509 
 510     // initialize GL/WGL extension functions
 511     if (!WGLGC_InitExtFuncs(screennum)) {
 512         J2dRlsTraceLn(J2D_TRACE_ERROR,
 513             "WGLGraphicsConfig_getWGLConfigInfo: could not init ext funcs");
 514         return 0L;
 515     }
 516 
 517     // create a scratch window
 518     hwnd = WGLGC_CreateScratchWindow(screennum);
 519     if (hwnd == 0) {
 520         return 0L;
 521     }
 522 
 523     // get the HDC for the scratch window
 524     hdc = GetDC(hwnd);
 525     if (hdc == 0) {
 526         J2dRlsTraceLn(J2D_TRACE_ERROR,
 527             "WGLGraphicsConfig_getWGLConfigInfo: could not get dc for scratch window");
 528         DestroyWindow(hwnd);
 529         return 0L;
 530     }
 531 
 532     if (pixfmt == 0) {
 533         // find an appropriate pixel format
 534         pixfmt = WGLGC_GetPixelFormatForDC(hdc);
 535         if (pixfmt == 0) {
 536             J2dRlsTraceLn(J2D_TRACE_ERROR,
 537                 "WGLGraphicsConfig_getWGLConfigInfo: could not find appropriate pixfmt");
 538             ReleaseDC(hwnd, hdc);
 539             DestroyWindow(hwnd);
 540             return 0L;
 541         }
 542     }
 543 
 544     if (sharedContext == 0) {
 545         // create the one shared context
 546         sharedContext = WGLGC_CreateContext(screennum, pixfmt);
 547         if (sharedContext == 0) {
 548             J2dRlsTraceLn(J2D_TRACE_ERROR,
 549                 "WGLGraphicsConfig_getWGLConfigInfo: could not create shared context");
 550             ReleaseDC(hwnd, hdc);
 551             DestroyWindow(hwnd);
 552             return 0L;
 553         }
 554     }
 555 
 556     // set the pixel format for the scratch window
 557     if (!SetPixelFormat(hdc, pixfmt, &pfd)) {
 558         J2dRlsTraceLn(J2D_TRACE_ERROR,
 559             "WGLGraphicsconfig_getWGLConfigInfo: error setting pixel format");
 560         ReleaseDC(hwnd, hdc);
 561         DestroyWindow(hwnd);
 562         return 0L;
 563     }
 564 
 565     // create the HGLRC (context) for this WGLGraphicsConfig
 566     context = j2d_wglCreateContext(hdc);
 567     if (context == 0) {
 568         J2dRlsTraceLn(J2D_TRACE_ERROR,
 569             "WGLGraphicsConfig_getWGLConfigInfo: could not create WGL context");
 570         ReleaseDC(hwnd, hdc);
 571         DestroyWindow(hwnd);
 572         return 0L;
 573     }
 574 
 575     // REMIND: when using wglShareLists, the two contexts must use an
 576     //         identical pixel format...
 577     if (!j2d_wglShareLists(sharedContext, context)) {
 578         J2dRlsTraceLn(J2D_TRACE_WARNING,
 579             "WGLGraphicsConfig_getWGLConfigInfo: unable to share lists");
 580     }
 581 
 582     // make the context current so that we can query the OpenGL version
 583     // and extension strings
 584     if (!j2d_wglMakeCurrent(hdc, context)) {
 585         J2dRlsTraceLn(J2D_TRACE_ERROR,
 586             "WGLGraphicsConfig_getWGLConfigInfo: could not make temp context current");
 587         j2d_wglDeleteContext(context);
 588         ReleaseDC(hwnd, hdc);
 589         DestroyWindow(hwnd);
 590         return 0L;
 591     }
 592 
 593     // get version and extension strings
 594     versionstr = j2d_glGetString(GL_VERSION);
 595     extstr = j2d_wglGetExtensionsStringARB(hdc);
 596     OGLContext_GetExtensionInfo(env, &caps);
 597 
 598     J2dRlsTraceLn1(J2D_TRACE_INFO,
 599         "WGLGraphicsConfig_getWGLConfigInfo: OpenGL version=%s",
 600                    (versionstr == NULL) ? "null" : (char *)versionstr);
 601 
 602     if (!OGLContext_IsVersionSupported(versionstr)) {
 603         J2dRlsTraceLn(J2D_TRACE_ERROR,
 604             "WGLGraphicsConfig_getWGLConfigInfo: OpenGL 1.2 is required");
 605         j2d_wglMakeCurrent(NULL, NULL);
 606         j2d_wglDeleteContext(context);
 607         ReleaseDC(hwnd, hdc);
 608         DestroyWindow(hwnd);
 609         return 0L;
 610     }
 611 
 612     // check for required WGL extensions
 613     if (!OGLContext_IsExtensionAvailable(extstr, "WGL_ARB_pbuffer") ||
 614         !OGLContext_IsExtensionAvailable(extstr, "WGL_ARB_make_current_read")||
 615         !OGLContext_IsExtensionAvailable(extstr, "WGL_ARB_pixel_format"))
 616     {
 617         J2dRlsTraceLn(J2D_TRACE_ERROR,
 618             "WGLGraphicsConfig_getWGLConfigInfo: required ext(s) unavailable");
 619         j2d_wglMakeCurrent(NULL, NULL);
 620         j2d_wglDeleteContext(context);
 621         ReleaseDC(hwnd, hdc);
 622         DestroyWindow(hwnd);
 623         return 0L;
 624     }
 625 
 626     // get config-specific capabilities
 627     j2d_wglGetPixelFormatAttribivARB(hdc, pixfmt, 0, 2, attrKeys, attrVals);
 628     if (attrVals[0]) {
 629         caps |= CAPS_DOUBLEBUFFERED;
 630     }
 631     if (attrVals[1] > 0) {
 632         caps |= CAPS_STORED_ALPHA;
 633     }
 634 
 635     // create the scratch pbuffer
 636     scratch = j2d_wglCreatePbufferARB(hdc, pixfmt, 1, 1, NULL);
 637 
 638     // destroy the temporary resources
 639     j2d_wglMakeCurrent(NULL, NULL);
 640     ReleaseDC(hwnd, hdc);
 641     DestroyWindow(hwnd);
 642 
 643     if (scratch == 0) {
 644         J2dRlsTraceLn(J2D_TRACE_ERROR,
 645             "WGLGraphicsConfig_getWGLConfigInfo: could not create scratch surface");
 646         j2d_wglDeleteContext(context);
 647         return 0L;
 648     }
 649 
 650     // get the HDC for the scratch pbuffer
 651     scratchDC = j2d_wglGetPbufferDCARB(scratch);
 652     if (scratchDC == 0) {
 653         J2dRlsTraceLn(J2D_TRACE_ERROR,
 654             "WGLGraphicsConfig_getWGLConfigInfo: could not get hdc for scratch surface");
 655         j2d_wglDeleteContext(context);
 656         j2d_wglDestroyPbufferARB(scratch);
 657         return 0L;
 658     }
 659 
 660     // initialize the OGLContext, which wraps the pixfmt and HGLRC (context)
 661     oglc = WGLGC_InitOGLContext(pixfmt, context, scratch, scratchDC, caps);
 662     if (oglc == NULL) {
 663         J2dRlsTraceLn(J2D_TRACE_ERROR,
 664             "WGLGraphicsConfig_getWGLConfigInfo: could not create oglc");
 665         j2d_wglDeleteContext(context);
 666         j2d_wglReleasePbufferDCARB(scratch, scratchDC);
 667         j2d_wglDestroyPbufferARB(scratch);
 668         return 0L;
 669     }
 670 
 671     J2dTraceLn(J2D_TRACE_VERBOSE,
 672         "WGLGraphicsConfig_getWGLConfigInfo: finished checking dependencies");
 673 
 674     // create the WGLGraphicsConfigInfo record for this config
 675     wglinfo = (WGLGraphicsConfigInfo *)malloc(sizeof(WGLGraphicsConfigInfo));
 676     if (wglinfo == NULL) {
 677         J2dRlsTraceLn(J2D_TRACE_ERROR,
 678             "WGLGraphicsConfig_getWGLConfigInfo: could not allocate memory for wglinfo");
 679         WGLGC_DestroyOGLContext(oglc);
 680         return 0L;
 681     }
 682 
 683     wglinfo->screen = screennum;
 684     wglinfo->pixfmt = pixfmt;
 685     wglinfo->context = oglc;
 686 
 687     return ptr_to_jlong(wglinfo);
 688 }
 689 
 690 JNIEXPORT jint JNICALL
 691 Java_sun_java2d_opengl_WGLGraphicsConfig_getDefaultPixFmt(JNIEnv *env,
 692                                                           jclass wglgc,
 693                                                           jint screennum)
 694 {
 695     J2dTraceLn(J2D_TRACE_INFO, "WGLGraphicsConfig_getDefaultPixFmt");
 696 
 697     // REMIND: eventually we should implement this method so that it finds
 698     //         the most appropriate default pixel format for the given
 699     //         device; for now, we'll just return 0, and then we'll find
 700     //         an appropriate pixel format in WGLGC_GetWGLConfigInfo()...
 701     return 0;
 702 }
 703 
 704 JNIEXPORT jint JNICALL
 705 Java_sun_java2d_opengl_WGLGraphicsConfig_getOGLCapabilities(JNIEnv *env,
 706                                                             jclass wglgc,
 707                                                             jlong configInfo)
 708 {
 709     WGLGraphicsConfigInfo *wglinfo =
 710         (WGLGraphicsConfigInfo *)jlong_to_ptr(configInfo);
 711 
 712     J2dTraceLn(J2D_TRACE_INFO, "WGLGraphicsConfig_getOGLCapabilities");
 713 
 714     if (wglinfo == NULL || wglinfo->context == NULL) {
 715         return CAPS_EMPTY;
 716     }
 717 
 718     return wglinfo->context->caps;
 719 }