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