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 }