1 /*
   2  * Copyright (c) 2004, 2013, 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 
  28 #include "sun_java2d_opengl_WGLSurfaceData.h"
  29 
  30 #include "jni.h"
  31 #include "jlong.h"
  32 #include "jni_util.h"
  33 #include "sizecalc.h"
  34 #include "OGLRenderQueue.h"
  35 #include "WGLGraphicsConfig.h"
  36 #include "WGLSurfaceData.h"
  37 
  38 /**
  39  * The methods in this file implement the native windowing system specific
  40  * layer (WGL) for the OpenGL-based Java 2D pipeline.
  41  */
  42 
  43 extern LockFunc                     OGLSD_Lock;
  44 extern GetRasInfoFunc               OGLSD_GetRasInfo;
  45 extern UnlockFunc                   OGLSD_Unlock;
  46 extern DisposeFunc                  OGLSD_Dispose;
  47 
  48 extern OGLPixelFormat PixelFormats[];
  49 extern void AwtWindow_UpdateWindow(JNIEnv *env, jobject peer,
  50                                    jint w, jint h, HBITMAP hBitmap);
  51 extern HBITMAP BitmapUtil_CreateBitmapFromARGBPre(int width, int height,
  52                                                   int srcStride,
  53                                                   int* imageData);
  54 extern void AwtComponent_GetInsets(JNIEnv *env, jobject peer, RECT *insets);
  55 
  56 extern void
  57     OGLSD_SetNativeDimensions(JNIEnv *env, OGLSDOps *oglsdo, jint w, jint h);
  58 
  59 JNIEXPORT void JNICALL
  60 Java_sun_java2d_opengl_WGLSurfaceData_initOps(JNIEnv *env, jobject wglsd,
  61                                               jlong pConfigInfo,
  62                                               jobject peer, jlong hwnd)
  63 {
  64     OGLSDOps *oglsdo = (OGLSDOps *)SurfaceData_InitOps(env, wglsd,
  65                                                        sizeof(OGLSDOps));
  66     WGLSDOps *wglsdo = (WGLSDOps *)malloc(sizeof(WGLSDOps));
  67 
  68     J2dTraceLn(J2D_TRACE_INFO, "WGLSurfaceData_initOps");
  69 
  70     if (wglsdo == NULL) {
  71         JNU_ThrowOutOfMemoryError(env, "creating native wgl ops");
  72         return;
  73     }
  74     if (oglsdo == NULL) {
  75         free(wglsdo);
  76         JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed.");
  77         return;
  78     }
  79 
  80     oglsdo->privOps = wglsdo;
  81 
  82     oglsdo->sdOps.Lock               = OGLSD_Lock;
  83     oglsdo->sdOps.GetRasInfo         = OGLSD_GetRasInfo;
  84     oglsdo->sdOps.Unlock             = OGLSD_Unlock;
  85     oglsdo->sdOps.Dispose            = OGLSD_Dispose;
  86 
  87     oglsdo->drawableType = OGLSD_UNDEFINED;
  88     oglsdo->activeBuffer = GL_FRONT;
  89     oglsdo->needsInit = JNI_TRUE;
  90     if (peer != NULL) {
  91         RECT insets;
  92         AwtComponent_GetInsets(env, peer, &insets);
  93         oglsdo->xOffset = -insets.left;
  94         oglsdo->yOffset = -insets.bottom;
  95     } else {
  96         oglsdo->xOffset = 0;
  97         oglsdo->yOffset = 0;
  98     }
  99 
 100     wglsdo->window = (HWND)jlong_to_ptr(hwnd);
 101     wglsdo->configInfo = (WGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
 102     if (wglsdo->configInfo == NULL) {
 103         free(wglsdo);
 104         JNU_ThrowNullPointerException(env, "Config info is null in initOps");
 105     }
 106 }
 107 
 108 /**
 109  * This function disposes of any native windowing system resources associated
 110  * with this surface.  For instance, if the given OGLSDOps is of type
 111  * OGLSD_PBUFFER, this method implementation will destroy the actual pbuffer
 112  * surface.
 113  */
 114 void
 115 OGLSD_DestroyOGLSurface(JNIEnv *env, OGLSDOps *oglsdo)
 116 {
 117     WGLSDOps *wglsdo = (WGLSDOps *)oglsdo->privOps;
 118 
 119     J2dTraceLn(J2D_TRACE_INFO, "OGLSD_DestroyOGLSurface");
 120 
 121     if (oglsdo->drawableType == OGLSD_PBUFFER) {
 122         if (wglsdo->pbuffer != 0) {
 123             if (wglsdo->pbufferDC != 0) {
 124                 j2d_wglReleasePbufferDCARB(wglsdo->pbuffer,
 125                                            wglsdo->pbufferDC);
 126                 wglsdo->pbufferDC = 0;
 127             }
 128             j2d_wglDestroyPbufferARB(wglsdo->pbuffer);
 129             wglsdo->pbuffer = 0;
 130         }
 131     }
 132 }
 133 
 134 /**
 135  * Makes the given context current to its associated "scratch" surface.  If
 136  * the operation is successful, this method will return JNI_TRUE; otherwise,
 137  * returns JNI_FALSE.
 138  */
 139 static jboolean
 140 WGLSD_MakeCurrentToScratch(JNIEnv *env, OGLContext *oglc)
 141 {
 142     WGLCtxInfo *ctxInfo;
 143 
 144     J2dTraceLn(J2D_TRACE_INFO, "WGLSD_MakeCurrentToScratch");
 145 
 146     if (oglc == NULL) {
 147         J2dRlsTraceLn(J2D_TRACE_ERROR,
 148                       "WGLSD_MakeCurrentToScratch: context is null");
 149         return JNI_FALSE;
 150     }
 151 
 152     ctxInfo = (WGLCtxInfo *)oglc->ctxInfo;
 153     if (!j2d_wglMakeCurrent(ctxInfo->scratchSurfaceDC, ctxInfo->context)) {
 154         J2dRlsTraceLn(J2D_TRACE_ERROR,
 155                       "WGLSD_MakeCurrentToScratch: could not make current");
 156         return JNI_FALSE;
 157     }
 158 
 159     return JNI_TRUE;
 160 }
 161 
 162 /**
 163  * Returns a pointer (as a jlong) to the native WGLGraphicsConfigInfo
 164  * associated with the given OGLSDOps.  This method can be called from
 165  * shared code to retrieve the native GraphicsConfig data in a platform-
 166  * independent manner.
 167  */
 168 jlong
 169 OGLSD_GetNativeConfigInfo(OGLSDOps *oglsdo)
 170 {
 171     WGLSDOps *wglsdo;
 172 
 173     if (oglsdo == NULL) {
 174         J2dRlsTraceLn(J2D_TRACE_ERROR,
 175                       "OGLSD_GetNativeConfigInfo: ops are null");
 176         return 0L;
 177     }
 178 
 179     wglsdo = (WGLSDOps *)oglsdo->privOps;
 180     if (wglsdo == NULL) {
 181         J2dRlsTraceLn(J2D_TRACE_ERROR,
 182                       "OGLSD_GetNativeConfigInfo: wgl ops are null");
 183         return 0L;
 184     }
 185 
 186     return ptr_to_jlong(wglsdo->configInfo);
 187 }
 188 
 189 /**
 190  * Makes the given GraphicsConfig's context current to its associated
 191  * "scratch" surface.  If there is a problem making the context current,
 192  * this method will return NULL; otherwise, returns a pointer to the
 193  * OGLContext that is associated with the given GraphicsConfig.
 194  */
 195 OGLContext *
 196 OGLSD_SetScratchSurface(JNIEnv *env, jlong pConfigInfo)
 197 {
 198     WGLGraphicsConfigInfo *wglInfo =
 199         (WGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
 200     OGLContext *oglc;
 201 
 202     J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SetScratchContext");
 203 
 204     if (wglInfo == NULL) {
 205         J2dRlsTraceLn(J2D_TRACE_ERROR,
 206                       "OGLSD_SetScratchContext: wgl config info is null");
 207         return NULL;
 208     }
 209 
 210     oglc = wglInfo->context;
 211     if (!WGLSD_MakeCurrentToScratch(env, oglc)) {
 212         return NULL;
 213     }
 214 
 215     if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) {
 216         // the GL_EXT_framebuffer_object extension is present, so this call
 217         // will ensure that we are bound to the scratch pbuffer (and not
 218         // some other framebuffer object)
 219         j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
 220     }
 221 
 222     return oglc;
 223 }
 224 
 225 /**
 226  * Makes a context current to the given source and destination
 227  * surfaces.  If there is a problem making the context current, this method
 228  * will return NULL; otherwise, returns a pointer to the OGLContext that is
 229  * associated with the destination surface.
 230  */
 231 OGLContext *
 232 OGLSD_MakeOGLContextCurrent(JNIEnv *env, OGLSDOps *srcOps, OGLSDOps *dstOps)
 233 {
 234     WGLSDOps *srcWGLOps = (WGLSDOps *)srcOps->privOps;
 235     WGLSDOps *dstWGLOps = (WGLSDOps *)dstOps->privOps;
 236     OGLContext *oglc;
 237     WGLCtxInfo *ctxinfo;
 238     HDC srcHDC, dstHDC;
 239     BOOL success;
 240 
 241     J2dTraceLn(J2D_TRACE_INFO, "OGLSD_MakeOGLContextCurrent");
 242 
 243     J2dTraceLn4(J2D_TRACE_VERBOSE, "  src: %d %p dst: %d %p",
 244                 srcOps->drawableType, srcOps,
 245                 dstOps->drawableType, dstOps);
 246 
 247     oglc = dstWGLOps->configInfo->context;
 248     if (oglc == NULL) {
 249         J2dRlsTraceLn(J2D_TRACE_ERROR,
 250                       "OGLSD_MakeOGLContextCurrent: context is null");
 251         return NULL;
 252     }
 253 
 254     if (dstOps->drawableType == OGLSD_FBOBJECT) {
 255         OGLContext *currentContext = OGLRenderQueue_GetCurrentContext();
 256 
 257         // first make sure we have a current context (if the context isn't
 258         // already current to some drawable, we will make it current to
 259         // its scratch surface)
 260         if (oglc != currentContext) {
 261             if (!WGLSD_MakeCurrentToScratch(env, oglc)) {
 262                 return NULL;
 263             }
 264         }
 265 
 266         // now bind to the fbobject associated with the destination surface;
 267         // this means that all rendering will go into the fbobject destination
 268         // (note that we unbind the currently bound texture first; this is
 269         // recommended procedure when binding an fbobject)
 270         j2d_glBindTexture(dstOps->textureTarget, 0);
 271         j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dstOps->fbobjectID);
 272 
 273         return oglc;
 274     }
 275 
 276     ctxinfo = (WGLCtxInfo *)oglc->ctxInfo;
 277 
 278     // get the hdc for the destination surface
 279     if (dstOps->drawableType == OGLSD_PBUFFER) {
 280         dstHDC = dstWGLOps->pbufferDC;
 281     } else {
 282         dstHDC = GetDC(dstWGLOps->window);
 283     }
 284 
 285     // get the hdc for the source surface
 286     if (srcOps->drawableType == OGLSD_PBUFFER) {
 287         srcHDC = srcWGLOps->pbufferDC;
 288     } else {
 289         // the source will always be equal to the destination in this case
 290         srcHDC = dstHDC;
 291     }
 292 
 293     // REMIND: in theory we should be able to use wglMakeContextCurrentARB()
 294     // even when the src/dst surfaces are the same, but this causes problems
 295     // on ATI's drivers (see 6525997); for now we will only use it when the
 296     // surfaces are different, otherwise we will use the old
 297     // wglMakeCurrent() approach...
 298     if (srcHDC != dstHDC) {
 299         // use WGL_ARB_make_current_read extension to make context current
 300         success =
 301             j2d_wglMakeContextCurrentARB(dstHDC, srcHDC, ctxinfo->context);
 302     } else {
 303         // use the old approach for making current to the destination
 304         success = j2d_wglMakeCurrent(dstHDC, ctxinfo->context);
 305     }
 306     if (!success) {
 307         J2dRlsTraceLn(J2D_TRACE_ERROR,
 308                       "OGLSD_MakeOGLContextCurrent: could not make current");
 309         if (dstOps->drawableType != OGLSD_PBUFFER) {
 310             ReleaseDC(dstWGLOps->window, dstHDC);
 311         }
 312         return NULL;
 313     }
 314 
 315     if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) {
 316         // the GL_EXT_framebuffer_object extension is present, so we
 317         // must bind to the default (windowing system provided)
 318         // framebuffer
 319         j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
 320     }
 321 
 322     if (dstOps->drawableType != OGLSD_PBUFFER) {
 323         ReleaseDC(dstWGLOps->window, dstHDC);
 324     }
 325 
 326     return oglc;
 327 }
 328 
 329 /**
 330  * This function initializes a native window surface and caches the window
 331  * bounds in the given OGLSDOps.  Returns JNI_TRUE if the operation was
 332  * successful; JNI_FALSE otherwise.
 333  */
 334 jboolean
 335 OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo)
 336 {
 337     PIXELFORMATDESCRIPTOR pfd;
 338     WGLSDOps *wglsdo;
 339     WGLGraphicsConfigInfo *wglInfo;
 340     HWND window;
 341     RECT wbounds;
 342     HDC hdc;
 343 
 344     J2dTraceLn(J2D_TRACE_INFO, "OGLSD_InitOGLWindow");
 345 
 346     if (oglsdo == NULL) {
 347         J2dRlsTraceLn(J2D_TRACE_ERROR,
 348                       "OGLSD_InitOGLWindow: ops are null");
 349         return JNI_FALSE;
 350     }
 351 
 352     wglsdo = (WGLSDOps *)oglsdo->privOps;
 353     if (wglsdo == NULL) {
 354         J2dRlsTraceLn(J2D_TRACE_ERROR,
 355                       "OGLSD_InitOGLWindow: wgl ops are null");
 356         return JNI_FALSE;
 357     }
 358 
 359     wglInfo = wglsdo->configInfo;
 360     if (wglInfo == NULL) {
 361         J2dRlsTraceLn(J2D_TRACE_ERROR,
 362                       "OGLSD_InitOGLWindow: graphics config info is null");
 363         return JNI_FALSE;
 364     }
 365 
 366     window = wglsdo->window;
 367     if (!IsWindow(window)) {
 368         J2dRlsTraceLn(J2D_TRACE_ERROR,
 369                       "OGLSD_InitOGLWindow: disposed component");
 370         return JNI_FALSE;
 371     }
 372 
 373     GetWindowRect(window, &wbounds);
 374 
 375     hdc = GetDC(window);
 376     if (hdc == 0) {
 377         J2dRlsTraceLn(J2D_TRACE_ERROR,
 378                       "OGLSD_InitOGLWindow: invalid hdc");
 379         return JNI_FALSE;
 380     }
 381 
 382     if (!SetPixelFormat(hdc, wglInfo->pixfmt, &pfd)) {
 383         J2dRlsTraceLn(J2D_TRACE_ERROR,
 384                       "OGLSD_InitOGLWindow: error setting pixel format");
 385         ReleaseDC(window, hdc);
 386         return JNI_FALSE;
 387     }
 388 
 389     ReleaseDC(window, hdc);
 390 
 391     oglsdo->drawableType = OGLSD_WINDOW;
 392     oglsdo->isOpaque = JNI_TRUE;
 393     oglsdo->width = wbounds.right - wbounds.left;
 394     oglsdo->height = wbounds.bottom - wbounds.top;
 395     wglsdo->pbufferDC = 0;
 396 
 397     J2dTraceLn2(J2D_TRACE_VERBOSE, "  created window: w=%d h=%d",
 398                 oglsdo->width, oglsdo->height);
 399 
 400     return JNI_TRUE;
 401 }
 402 
 403 JNIEXPORT jboolean JNICALL
 404 Java_sun_java2d_opengl_WGLSurfaceData_initPbuffer
 405     (JNIEnv *env, jobject wglsd,
 406      jlong pData, jlong pConfigInfo,
 407      jboolean isOpaque,
 408      jint width, jint height)
 409 {
 410     int attrKeys[] = {
 411         WGL_MAX_PBUFFER_WIDTH_ARB,
 412         WGL_MAX_PBUFFER_HEIGHT_ARB,
 413     };
 414     int attrVals[2];
 415     int pbAttrList[] = { 0 };
 416     OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData);
 417     WGLGraphicsConfigInfo *wglInfo =
 418         (WGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
 419     WGLSDOps *wglsdo;
 420     HWND hwnd;
 421     HDC hdc, pbufferDC;
 422     HPBUFFERARB pbuffer;
 423     int maxWidth, maxHeight;
 424     int actualWidth, actualHeight;
 425 
 426     J2dTraceLn3(J2D_TRACE_INFO,
 427                 "WGLSurfaceData_initPbuffer: w=%d h=%d opq=%d",
 428                 width, height, isOpaque);
 429 
 430     if (oglsdo == NULL) {
 431         J2dRlsTraceLn(J2D_TRACE_ERROR,
 432             "WGLSurfaceData_initPbuffer: ops are null");
 433         return JNI_FALSE;
 434     }
 435 
 436     wglsdo = (WGLSDOps *)oglsdo->privOps;
 437     if (wglsdo == NULL) {
 438         J2dRlsTraceLn(J2D_TRACE_ERROR,
 439             "WGLSurfaceData_initPbuffer: wgl ops are null");
 440         return JNI_FALSE;
 441     }
 442 
 443     if (wglInfo == NULL) {
 444         J2dRlsTraceLn(J2D_TRACE_ERROR,
 445             "WGLSurfaceData_initPbuffer: wgl config info is null");
 446         return JNI_FALSE;
 447     }
 448 
 449     // create a scratch window
 450     hwnd = WGLGC_CreateScratchWindow(wglInfo->screen);
 451     if (hwnd == 0) {
 452         J2dRlsTraceLn(J2D_TRACE_ERROR,
 453             "WGLSurfaceData_initPbuffer: could not create scratch window");
 454         return JNI_FALSE;
 455     }
 456 
 457     // get the HDC for the scratch window
 458     hdc = GetDC(hwnd);
 459     if (hdc == 0) {
 460         J2dRlsTraceLn(J2D_TRACE_ERROR,
 461             "WGLSurfaceData_initPbuffer: could not get dc for scratch window");
 462         DestroyWindow(hwnd);
 463         return JNI_FALSE;
 464     }
 465 
 466     // get the maximum allowable pbuffer dimensions
 467     j2d_wglGetPixelFormatAttribivARB(hdc, wglInfo->pixfmt, 0, 2,
 468                                      attrKeys, attrVals);
 469     maxWidth  = attrVals[0];
 470     maxHeight = attrVals[1];
 471 
 472     J2dTraceLn4(J2D_TRACE_VERBOSE,
 473                 "  desired pbuffer dimensions: w=%d h=%d maxw=%d maxh=%d",
 474                 width, height, maxWidth, maxHeight);
 475 
 476     // if either dimension is 0 or larger than the maximum, we cannot
 477     // allocate a pbuffer with the requested dimensions
 478     if (width  == 0 || width  > maxWidth ||
 479         height == 0 || height > maxHeight)
 480     {
 481         J2dRlsTraceLn(J2D_TRACE_ERROR,
 482             "WGLSurfaceData_initPbuffer: invalid dimensions");
 483         ReleaseDC(hwnd, hdc);
 484         DestroyWindow(hwnd);
 485         return JNI_FALSE;
 486     }
 487 
 488     pbuffer = j2d_wglCreatePbufferARB(hdc, wglInfo->pixfmt,
 489                                       width, height, pbAttrList);
 490 
 491     ReleaseDC(hwnd, hdc);
 492     DestroyWindow(hwnd);
 493 
 494     if (pbuffer == 0) {
 495         J2dRlsTraceLn(J2D_TRACE_ERROR,
 496             "WGLSurfaceData_initPbuffer: could not create wgl pbuffer");
 497         return JNI_FALSE;
 498     }
 499 
 500     // note that we get the DC for the pbuffer at creation time, and then
 501     // release the DC when the pbuffer is disposed; the WGL_ARB_pbuffer
 502     // spec is vague about such things, but from past experience we know
 503     // this approach to be more robust than, for example, doing a
 504     // Get/ReleasePbufferDC() everytime we make a context current
 505     pbufferDC = j2d_wglGetPbufferDCARB(pbuffer);
 506     if (pbufferDC == 0) {
 507         J2dRlsTraceLn(J2D_TRACE_ERROR,
 508             "WGLSurfaceData_initPbuffer: could not get dc for pbuffer");
 509         j2d_wglDestroyPbufferARB(pbuffer);
 510         return JNI_FALSE;
 511     }
 512 
 513     // make sure the actual dimensions match those that we requested
 514     j2d_wglQueryPbufferARB(pbuffer, WGL_PBUFFER_WIDTH_ARB, &actualWidth);
 515     j2d_wglQueryPbufferARB(pbuffer, WGL_PBUFFER_HEIGHT_ARB, &actualHeight);
 516 
 517     if (width != actualWidth || height != actualHeight) {
 518         J2dRlsTraceLn2(J2D_TRACE_ERROR,
 519             "WGLSurfaceData_initPbuffer: actual (w=%d h=%d) != requested",
 520                        actualWidth, actualHeight);
 521         j2d_wglReleasePbufferDCARB(pbuffer, pbufferDC);
 522         j2d_wglDestroyPbufferARB(pbuffer);
 523         return JNI_FALSE;
 524     }
 525 
 526     oglsdo->drawableType = OGLSD_PBUFFER;
 527     oglsdo->isOpaque = isOpaque;
 528     oglsdo->width = width;
 529     oglsdo->height = height;
 530     wglsdo->pbuffer = pbuffer;
 531     wglsdo->pbufferDC = pbufferDC;
 532 
 533     OGLSD_SetNativeDimensions(env, oglsdo, width, height);
 534 
 535     return JNI_TRUE;
 536 }
 537 
 538 void
 539 OGLSD_SwapBuffers(JNIEnv *env, jlong pPeerData)
 540 {
 541     HWND window;
 542     HDC hdc;
 543 
 544     J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SwapBuffers");
 545 
 546     window = AwtComponent_GetHWnd(env, pPeerData);
 547     if (!IsWindow(window)) {
 548         J2dRlsTraceLn(J2D_TRACE_ERROR,
 549                       "OGLSD_SwapBuffers: disposed component");
 550         return;
 551     }
 552 
 553     hdc = GetDC(window);
 554     if (hdc == 0) {
 555         J2dRlsTraceLn(J2D_TRACE_ERROR,
 556                       "OGLSD_SwapBuffers: invalid hdc");
 557         return;
 558     }
 559 
 560     if (!SwapBuffers(hdc)) {
 561         J2dRlsTraceLn(J2D_TRACE_ERROR,
 562                       "OGLSD_SwapBuffers: error in SwapBuffers");
 563     }
 564 
 565     if (!ReleaseDC(window, hdc)) {
 566         J2dRlsTraceLn(J2D_TRACE_ERROR,
 567                       "OGLSD_SwapBuffers: error while releasing dc");
 568     }
 569 }
 570 
 571 // needed by Mac OS X port, no-op on other platforms
 572 void
 573 OGLSD_Flush(JNIEnv *env)
 574 {
 575 }
 576 
 577 /*
 578  * Class:     sun_java2d_opengl_WGLSurfaceData
 579  * Method:    updateWindowAccelImpl
 580  * Signature: (JJII)Z
 581  */
 582 JNIEXPORT jboolean JNICALL
 583     Java_sun_java2d_opengl_WGLSurfaceData_updateWindowAccelImpl
 584   (JNIEnv *env, jclass clazz, jlong pData, jobject peer, jint w, jint h)
 585 {
 586     OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData);
 587     OGLPixelFormat pf = PixelFormats[0/*PF_INT_ARGB_PRE*/];
 588     HBITMAP hBitmap = NULL;
 589     void *pDst;
 590     jint srcx, srcy, dstx, dsty, width, height;
 591     jint pixelStride = 4;
 592     jint scanStride = pixelStride * w;
 593 
 594     J2dTraceLn(J2D_TRACE_INFO, "WGLSurfaceData_updateWindowAccelImpl");
 595 
 596     if (w <= 0 || h <= 0) {
 597         return JNI_TRUE;
 598     }
 599     if (oglsdo == NULL) {
 600         return JNI_FALSE;
 601     }
 602     RESET_PREVIOUS_OP();
 603 
 604     width = w;
 605     height = h;
 606     srcx = srcy = dstx = dsty = 0;
 607 
 608     pDst = SAFE_SIZE_ARRAY_ALLOC(malloc, height, scanStride);
 609     if (pDst == NULL) {
 610         return JNI_FALSE;
 611     }
 612     ZeroMemory(pDst, height * scanStride);
 613 
 614     // the code below is mostly copied from OGLBlitLoops_SurfaceToSwBlit
 615 
 616     j2d_glPixelStorei(GL_PACK_SKIP_PIXELS, dstx);
 617     j2d_glPixelStorei(GL_PACK_ROW_LENGTH, scanStride / pixelStride);
 618     j2d_glPixelStorei(GL_PACK_ALIGNMENT, pf.alignment);
 619 
 620     // this accounts for lower-left origin of the source region
 621     srcx = oglsdo->xOffset + srcx;
 622     srcy = oglsdo->yOffset + oglsdo->height - (srcy + 1);
 623     // we must read one scanline at a time because there is no way
 624     // to read starting at the top-left corner of the source region
 625     while (height > 0) {
 626         j2d_glPixelStorei(GL_PACK_SKIP_ROWS, dsty);
 627         j2d_glReadPixels(srcx, srcy, width, 1,
 628                          pf.format, pf.type, pDst);
 629         srcy--;
 630         dsty++;
 631         height--;
 632     }
 633 
 634     j2d_glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
 635     j2d_glPixelStorei(GL_PACK_SKIP_ROWS, 0);
 636     j2d_glPixelStorei(GL_PACK_ROW_LENGTH, 0);
 637     j2d_glPixelStorei(GL_PACK_ALIGNMENT, 4);
 638 
 639     // the pixels read from the surface are already premultiplied
 640     hBitmap = BitmapUtil_CreateBitmapFromARGBPre(w, h, scanStride,
 641                                                  (int*)pDst);
 642     free(pDst);
 643 
 644     if (hBitmap == NULL) {
 645         return JNI_FALSE;
 646     }
 647 
 648     AwtWindow_UpdateWindow(env, peer, w, h, hBitmap);
 649 
 650     // hBitmap is released in UpdateWindow
 651 
 652     return JNI_TRUE;
 653 }