1 /* 2 * Copyright (c) 2004, 2015, 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. 111 */ 112 void 113 OGLSD_DestroyOGLSurface(JNIEnv *env, OGLSDOps *oglsdo) 114 { 115 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_DestroyOGLSurface"); 116 // Window is free'd later by AWT code... 117 } 118 119 /** 120 * Makes the given context current to its associated "scratch" surface. If 121 * the operation is successful, this method will return JNI_TRUE; otherwise, 122 * returns JNI_FALSE. 123 */ 124 static jboolean 125 WGLSD_MakeCurrentToScratch(JNIEnv *env, OGLContext *oglc) 126 { 127 WGLCtxInfo *ctxInfo; 128 129 J2dTraceLn(J2D_TRACE_INFO, "WGLSD_MakeCurrentToScratch"); 130 131 if (oglc == NULL) { 132 J2dRlsTraceLn(J2D_TRACE_ERROR, 133 "WGLSD_MakeCurrentToScratch: context is null"); 134 return JNI_FALSE; 135 } 136 137 ctxInfo = (WGLCtxInfo *)oglc->ctxInfo; 138 if (!j2d_wglMakeCurrent(ctxInfo->scratchSurfaceDC, ctxInfo->context)) { 139 J2dRlsTraceLn(J2D_TRACE_ERROR, 140 "WGLSD_MakeCurrentToScratch: could not make current"); 141 return JNI_FALSE; 142 } 143 144 return JNI_TRUE; 145 } 146 147 /** 148 * Returns a pointer (as a jlong) to the native WGLGraphicsConfigInfo 149 * associated with the given OGLSDOps. This method can be called from 150 * shared code to retrieve the native GraphicsConfig data in a platform- 151 * independent manner. 152 */ 153 jlong 154 OGLSD_GetNativeConfigInfo(OGLSDOps *oglsdo) 155 { 156 WGLSDOps *wglsdo; 157 158 if (oglsdo == NULL) { 159 J2dRlsTraceLn(J2D_TRACE_ERROR, 160 "OGLSD_GetNativeConfigInfo: ops are null"); 161 return 0L; 162 } 163 164 wglsdo = (WGLSDOps *)oglsdo->privOps; 165 if (wglsdo == NULL) { 166 J2dRlsTraceLn(J2D_TRACE_ERROR, 167 "OGLSD_GetNativeConfigInfo: wgl ops are null"); 168 return 0L; 169 } 170 171 return ptr_to_jlong(wglsdo->configInfo); 172 } 173 174 /** 175 * Makes the given GraphicsConfig's context current to its associated 176 * "scratch" surface. If there is a problem making the context current, 177 * this method will return NULL; otherwise, returns a pointer to the 178 * OGLContext that is associated with the given GraphicsConfig. 179 */ 180 OGLContext * 181 OGLSD_SetScratchSurface(JNIEnv *env, jlong pConfigInfo) 182 { 183 WGLGraphicsConfigInfo *wglInfo = 184 (WGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo); 185 OGLContext *oglc; 186 187 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SetScratchContext"); 188 189 if (wglInfo == NULL) { 190 J2dRlsTraceLn(J2D_TRACE_ERROR, 191 "OGLSD_SetScratchContext: wgl config info is null"); 192 return NULL; 193 } 194 195 oglc = wglInfo->context; 196 if (!WGLSD_MakeCurrentToScratch(env, oglc)) { 197 return NULL; 198 } 199 200 if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) { 201 // the GL_EXT_framebuffer_object extension is present, so this call 202 // will ensure that we are bound to the scratch pbuffer (and not 203 // some other framebuffer object) 204 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 205 } 206 207 return oglc; 208 } 209 210 /** 211 * Makes a context current to the given source and destination 212 * surfaces. If there is a problem making the context current, this method 213 * will return NULL; otherwise, returns a pointer to the OGLContext that is 214 * associated with the destination surface. 215 */ 216 OGLContext * 217 OGLSD_MakeOGLContextCurrent(JNIEnv *env, OGLSDOps *srcOps, OGLSDOps *dstOps) 218 { 219 WGLSDOps *srcWGLOps = (WGLSDOps *)srcOps->privOps; 220 WGLSDOps *dstWGLOps = (WGLSDOps *)dstOps->privOps; 221 OGLContext *oglc; 222 WGLCtxInfo *ctxinfo; 223 HDC srcHDC, dstHDC; 224 BOOL success; 225 226 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_MakeOGLContextCurrent"); 227 228 J2dTraceLn4(J2D_TRACE_VERBOSE, " src: %d %p dst: %d %p", 229 srcOps->drawableType, srcOps, 230 dstOps->drawableType, dstOps); 231 232 oglc = dstWGLOps->configInfo->context; 233 if (oglc == NULL) { 234 J2dRlsTraceLn(J2D_TRACE_ERROR, 235 "OGLSD_MakeOGLContextCurrent: context is null"); 236 return NULL; 237 } 238 239 if (dstOps->drawableType == OGLSD_FBOBJECT) { 240 OGLContext *currentContext = OGLRenderQueue_GetCurrentContext(); 241 242 // first make sure we have a current context (if the context isn't 243 // already current to some drawable, we will make it current to 244 // its scratch surface) 245 if (oglc != currentContext) { 246 if (!WGLSD_MakeCurrentToScratch(env, oglc)) { 247 return NULL; 248 } 249 } 250 251 // now bind to the fbobject associated with the destination surface; 252 // this means that all rendering will go into the fbobject destination 253 // (note that we unbind the currently bound texture first; this is 254 // recommended procedure when binding an fbobject) 255 j2d_glBindTexture(dstOps->textureTarget, 0); 256 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dstOps->fbobjectID); 257 258 return oglc; 259 } 260 261 ctxinfo = (WGLCtxInfo *)oglc->ctxInfo; 262 263 // get the hdc for the destination surface 264 dstHDC = GetDC(dstWGLOps->window); 265 266 // get the hdc for the source surface 267 // the source will always be equal to the destination in this case 268 srcHDC = dstHDC; 269 270 // REMIND: in theory we should be able to use wglMakeContextCurrentARB() 271 // even when the src/dst surfaces are the same, but this causes problems 272 // on ATI's drivers (see 6525997); for now we will only use it when the 273 // surfaces are different, otherwise we will use the old 274 // wglMakeCurrent() approach... 275 if (srcHDC != dstHDC) { 276 // use WGL_ARB_make_current_read extension to make context current 277 success = 278 j2d_wglMakeContextCurrentARB(dstHDC, srcHDC, ctxinfo->context); 279 } else { 280 // use the old approach for making current to the destination 281 success = j2d_wglMakeCurrent(dstHDC, ctxinfo->context); 282 } 283 if (!success) { 284 J2dRlsTraceLn(J2D_TRACE_ERROR, 285 "OGLSD_MakeOGLContextCurrent: could not make current"); 286 ReleaseDC(dstWGLOps->window, dstHDC); 287 return NULL; 288 } 289 290 if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) { 291 // the GL_EXT_framebuffer_object extension is present, so we 292 // must bind to the default (windowing system provided) 293 // framebuffer 294 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 295 } 296 297 ReleaseDC(dstWGLOps->window, dstHDC); 298 299 return oglc; 300 } 301 302 /** 303 * This function initializes a native window surface and caches the window 304 * bounds in the given OGLSDOps. Returns JNI_TRUE if the operation was 305 * successful; JNI_FALSE otherwise. 306 */ 307 jboolean 308 OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo) 309 { 310 PIXELFORMATDESCRIPTOR pfd; 311 WGLSDOps *wglsdo; 312 WGLGraphicsConfigInfo *wglInfo; 313 HWND window; 314 RECT wbounds; 315 HDC hdc; 316 317 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_InitOGLWindow"); 318 319 if (oglsdo == NULL) { 320 J2dRlsTraceLn(J2D_TRACE_ERROR, 321 "OGLSD_InitOGLWindow: ops are null"); 322 return JNI_FALSE; 323 } 324 325 wglsdo = (WGLSDOps *)oglsdo->privOps; 326 if (wglsdo == NULL) { 327 J2dRlsTraceLn(J2D_TRACE_ERROR, 328 "OGLSD_InitOGLWindow: wgl ops are null"); 329 return JNI_FALSE; 330 } 331 332 wglInfo = wglsdo->configInfo; 333 if (wglInfo == NULL) { 334 J2dRlsTraceLn(J2D_TRACE_ERROR, 335 "OGLSD_InitOGLWindow: graphics config info is null"); 336 return JNI_FALSE; 337 } 338 339 window = wglsdo->window; 340 if (!IsWindow(window)) { 341 J2dRlsTraceLn(J2D_TRACE_ERROR, 342 "OGLSD_InitOGLWindow: disposed component"); 343 return JNI_FALSE; 344 } 345 346 GetWindowRect(window, &wbounds); 347 348 hdc = GetDC(window); 349 if (hdc == 0) { 350 J2dRlsTraceLn(J2D_TRACE_ERROR, 351 "OGLSD_InitOGLWindow: invalid hdc"); 352 return JNI_FALSE; 353 } 354 355 if (!SetPixelFormat(hdc, wglInfo->pixfmt, &pfd)) { 356 J2dRlsTraceLn(J2D_TRACE_ERROR, 357 "OGLSD_InitOGLWindow: error setting pixel format"); 358 ReleaseDC(window, hdc); 359 return JNI_FALSE; 360 } 361 362 ReleaseDC(window, hdc); 363 364 oglsdo->drawableType = OGLSD_WINDOW; 365 oglsdo->isOpaque = JNI_TRUE; 366 oglsdo->width = wbounds.right - wbounds.left; 367 oglsdo->height = wbounds.bottom - wbounds.top; 368 wglsdo->pbufferDC = 0; 369 370 J2dTraceLn2(J2D_TRACE_VERBOSE, " created window: w=%d h=%d", 371 oglsdo->width, oglsdo->height); 372 373 return JNI_TRUE; 374 } 375 376 void 377 OGLSD_SwapBuffers(JNIEnv *env, jlong pPeerData) 378 { 379 HWND window; 380 HDC hdc; 381 382 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SwapBuffers"); 383 384 window = AwtComponent_GetHWnd(env, pPeerData); 385 if (!IsWindow(window)) { 386 J2dRlsTraceLn(J2D_TRACE_ERROR, 387 "OGLSD_SwapBuffers: disposed component"); 388 return; 389 } 390 391 hdc = GetDC(window); 392 if (hdc == 0) { 393 J2dRlsTraceLn(J2D_TRACE_ERROR, 394 "OGLSD_SwapBuffers: invalid hdc"); 395 return; 396 } 397 398 if (!SwapBuffers(hdc)) { 399 J2dRlsTraceLn(J2D_TRACE_ERROR, 400 "OGLSD_SwapBuffers: error in SwapBuffers"); 401 } 402 403 if (!ReleaseDC(window, hdc)) { 404 J2dRlsTraceLn(J2D_TRACE_ERROR, 405 "OGLSD_SwapBuffers: error while releasing dc"); 406 } 407 } 408 409 // needed by Mac OS X port, no-op on other platforms 410 void 411 OGLSD_Flush(JNIEnv *env) 412 { 413 } 414 415 /* 416 * Class: sun_java2d_opengl_WGLSurfaceData 417 * Method: updateWindowAccelImpl 418 * Signature: (JJII)Z 419 */ 420 JNIEXPORT jboolean JNICALL 421 Java_sun_java2d_opengl_WGLSurfaceData_updateWindowAccelImpl 422 (JNIEnv *env, jclass clazz, jlong pData, jobject peer, jint w, jint h) 423 { 424 OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData); 425 OGLPixelFormat pf = PixelFormats[0/*PF_INT_ARGB_PRE*/]; 426 HBITMAP hBitmap = NULL; 427 void *pDst; 428 jint srcx, srcy, dstx, dsty, width, height; 429 jint pixelStride = 4; 430 jint scanStride = pixelStride * w; 431 432 J2dTraceLn(J2D_TRACE_INFO, "WGLSurfaceData_updateWindowAccelImpl"); 433 434 if (w <= 0 || h <= 0) { 435 return JNI_TRUE; 436 } 437 if (oglsdo == NULL) { 438 return JNI_FALSE; 439 } 440 RESET_PREVIOUS_OP(); 441 442 width = w; 443 height = h; 444 srcx = srcy = dstx = dsty = 0; 445 446 pDst = SAFE_SIZE_ARRAY_ALLOC(malloc, height, scanStride); 447 if (pDst == NULL) { 448 return JNI_FALSE; 449 } 450 ZeroMemory(pDst, height * scanStride); 451 452 // the code below is mostly copied from OGLBlitLoops_SurfaceToSwBlit 453 454 j2d_glPixelStorei(GL_PACK_SKIP_PIXELS, dstx); 455 j2d_glPixelStorei(GL_PACK_ROW_LENGTH, scanStride / pixelStride); 456 j2d_glPixelStorei(GL_PACK_ALIGNMENT, pf.alignment); 457 458 // this accounts for lower-left origin of the source region 459 srcx = oglsdo->xOffset + srcx; 460 srcy = oglsdo->yOffset + oglsdo->height - (srcy + 1); 461 // we must read one scanline at a time because there is no way 462 // to read starting at the top-left corner of the source region 463 while (height > 0) { 464 j2d_glPixelStorei(GL_PACK_SKIP_ROWS, dsty); 465 j2d_glReadPixels(srcx, srcy, width, 1, 466 pf.format, pf.type, pDst); 467 srcy--; 468 dsty++; 469 height--; 470 } 471 472 j2d_glPixelStorei(GL_PACK_SKIP_PIXELS, 0); 473 j2d_glPixelStorei(GL_PACK_SKIP_ROWS, 0); 474 j2d_glPixelStorei(GL_PACK_ROW_LENGTH, 0); 475 j2d_glPixelStorei(GL_PACK_ALIGNMENT, 4); 476 477 // the pixels read from the surface are already premultiplied 478 hBitmap = BitmapUtil_CreateBitmapFromARGBPre(w, h, scanStride, 479 (int*)pDst); 480 free(pDst); 481 482 if (hBitmap == NULL) { 483 return JNI_FALSE; 484 } 485 486 AwtWindow_UpdateWindow(env, peer, w, h, hBitmap); 487 488 // hBitmap is released in UpdateWindow 489 490 return JNI_TRUE; 491 }