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 }