1 /* 2 * Copyright (c) 2011, 2012, 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 #import <stdlib.h> 27 #import <JavaNativeFoundation/JavaNativeFoundation.h> 28 29 #import "sun_java2d_opengl_CGLSurfaceData.h" 30 31 #import "jni.h" 32 #import "jni_util.h" 33 #import "OGLRenderQueue.h" 34 #import "CGLGraphicsConfig.h" 35 #import "CGLSurfaceData.h" 36 #import "CGLLayer.h" 37 #import "ThreadUtilities.h" 38 39 /* JDK's glext.h is already included and will prevent the Apple glext.h 40 * being included, so define the externs directly 41 */ 42 extern void glBindFramebufferEXT(GLenum target, GLuint framebuffer); 43 extern CGLError CGLTexImageIOSurface2D( 44 CGLContextObj ctx, GLenum target, GLenum internal_format, 45 GLsizei width, GLsizei height, GLenum format, GLenum type, 46 IOSurfaceRef ioSurface, GLuint plane); 47 48 /** 49 * The methods in this file implement the native windowing system specific 50 * layer (CGL) for the OpenGL-based Java 2D pipeline. 51 */ 52 53 #pragma mark - 54 #pragma mark "--- Mac OS X specific methods for GL pipeline ---" 55 56 // TODO: hack that's called from OGLRenderQueue to test out unlockFocus behavior 57 #if 0 58 void 59 OGLSD_UnlockFocus(OGLContext *oglc, OGLSDOps *dstOps) 60 { 61 CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo; 62 CGLSDOps *cglsdo = (CGLSDOps *)dstOps->privOps; 63 fprintf(stderr, "about to unlock focus: %p %p\n", 64 cglsdo->peerData, ctxinfo->context); 65 66 NSOpenGLView *nsView = cglsdo->peerData; 67 if (nsView != NULL) { 68 JNF_COCOA_ENTER(env); 69 [nsView unlockFocus]; 70 JNF_COCOA_EXIT(env); 71 } 72 } 73 #endif 74 75 /** 76 * Makes the given context current to its associated "scratch" surface. If 77 * the operation is successful, this method will return JNI_TRUE; otherwise, 78 * returns JNI_FALSE. 79 */ 80 static jboolean 81 CGLSD_MakeCurrentToScratch(JNIEnv *env, OGLContext *oglc) 82 { 83 J2dTraceLn(J2D_TRACE_INFO, "CGLSD_MakeCurrentToScratch"); 84 85 if (oglc == NULL) { 86 J2dRlsTraceLn(J2D_TRACE_ERROR, 87 "CGLSD_MakeCurrentToScratch: context is null"); 88 return JNI_FALSE; 89 } 90 91 JNF_COCOA_ENTER(env); 92 93 CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo; 94 #if USE_NSVIEW_FOR_SCRATCH 95 [ctxinfo->context makeCurrentContext]; 96 [ctxinfo->context setView: ctxinfo->scratchSurface]; 97 #else 98 [ctxinfo->context clearDrawable]; 99 [ctxinfo->context makeCurrentContext]; 100 [ctxinfo->context setPixelBuffer: ctxinfo->scratchSurface 101 cubeMapFace: 0 102 mipMapLevel: 0 103 currentVirtualScreen: [ctxinfo->context currentVirtualScreen]]; 104 #endif 105 106 JNF_COCOA_EXIT(env); 107 108 return JNI_TRUE; 109 } 110 111 /** 112 * This function disposes of any native windowing system resources associated 113 * with this surface. For instance, if the given OGLSDOps is of type 114 * OGLSD_PBUFFER, this method implementation will destroy the actual pbuffer 115 * surface. 116 */ 117 void 118 OGLSD_DestroyOGLSurface(JNIEnv *env, OGLSDOps *oglsdo) 119 { 120 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_DestroyOGLSurface"); 121 122 JNF_COCOA_ENTER(env); 123 124 CGLSDOps *cglsdo = (CGLSDOps *)oglsdo->privOps; 125 if (oglsdo->drawableType == OGLSD_PBUFFER) { 126 if (oglsdo->textureID != 0) { 127 j2d_glDeleteTextures(1, &oglsdo->textureID); 128 oglsdo->textureID = 0; 129 } 130 if (cglsdo->pbuffer != NULL) { 131 [cglsdo->pbuffer release]; 132 cglsdo->pbuffer = NULL; 133 } 134 } else if (oglsdo->drawableType == OGLSD_WINDOW) { 135 // detach the NSView from the NSOpenGLContext 136 CGLGraphicsConfigInfo *cglInfo = cglsdo->configInfo; 137 OGLContext *oglc = cglInfo->context; 138 CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo; 139 [ctxinfo->context clearDrawable]; 140 } 141 142 oglsdo->drawableType = OGLSD_UNDEFINED; 143 144 JNF_COCOA_EXIT(env); 145 } 146 147 /** 148 * Makes the given GraphicsConfig's context current to its associated 149 * "scratch" surface. If there is a problem making the context current, 150 * this method will return NULL; otherwise, returns a pointer to the 151 * OGLContext that is associated with the given GraphicsConfig. 152 */ 153 OGLContext * 154 OGLSD_SetScratchSurface(JNIEnv *env, jlong pConfigInfo) 155 { 156 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SetScratchContext"); 157 158 CGLGraphicsConfigInfo *cglInfo = (CGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo); 159 if (cglInfo == NULL) { 160 J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_SetScratchContext: cgl config info is null"); 161 return NULL; 162 } 163 164 OGLContext *oglc = cglInfo->context; 165 if (oglc == NULL) { 166 J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_SetScratchContext: ogl context is null"); 167 return NULL; 168 } 169 170 CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo; 171 172 JNF_COCOA_ENTER(env); 173 174 // avoid changing the context's target view whenever possible, since 175 // calling setView causes flickering; as long as our context is current 176 // to some view, it's not necessary to switch to the scratch surface 177 if ([ctxinfo->context view] == nil) { 178 // it seems to be necessary to explicitly flush between context changes 179 OGLContext *currentContext = OGLRenderQueue_GetCurrentContext(); 180 if (currentContext != NULL) { 181 j2d_glFlush(); 182 } 183 184 if (!CGLSD_MakeCurrentToScratch(env, oglc)) { 185 return NULL; 186 } 187 // make sure our context is current 188 } else if ([NSOpenGLContext currentContext] != ctxinfo->context) { 189 [ctxinfo->context makeCurrentContext]; 190 } 191 192 if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) { 193 // the GL_EXT_framebuffer_object extension is present, so this call 194 // will ensure that we are bound to the scratch surface (and not 195 // some other framebuffer object) 196 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 197 } 198 199 JNF_COCOA_EXIT(env); 200 201 return oglc; 202 } 203 204 /** 205 * Makes a context current to the given source and destination 206 * surfaces. If there is a problem making the context current, this method 207 * will return NULL; otherwise, returns a pointer to the OGLContext that is 208 * associated with the destination surface. 209 */ 210 OGLContext * 211 OGLSD_MakeOGLContextCurrent(JNIEnv *env, OGLSDOps *srcOps, OGLSDOps *dstOps) 212 { 213 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_MakeOGLContextCurrent"); 214 215 CGLSDOps *dstCGLOps = (CGLSDOps *)dstOps->privOps; 216 217 J2dTraceLn4(J2D_TRACE_VERBOSE, " src: %d %p dst: %d %p", srcOps->drawableType, srcOps, dstOps->drawableType, dstOps); 218 219 OGLContext *oglc = dstCGLOps->configInfo->context; 220 if (oglc == NULL) { 221 J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_MakeOGLContextCurrent: context is null"); 222 return NULL; 223 } 224 225 CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo; 226 227 // it seems to be necessary to explicitly flush between context changes 228 OGLContext *currentContext = OGLRenderQueue_GetCurrentContext(); 229 if (currentContext != NULL) { 230 j2d_glFlush(); 231 } 232 233 if (dstOps->drawableType == OGLSD_FBOBJECT) { 234 // first make sure we have a current context (if the context isn't 235 // already current to some drawable, we will make it current to 236 // its scratch surface) 237 if (oglc != currentContext) { 238 if (!CGLSD_MakeCurrentToScratch(env, oglc)) { 239 return NULL; 240 } 241 } 242 243 // now bind to the fbobject associated with the destination surface; 244 // this means that all rendering will go into the fbobject destination 245 // (note that we unbind the currently bound texture first; this is 246 // recommended procedure when binding an fbobject) 247 j2d_glBindTexture(GL_TEXTURE_2D, 0); 248 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dstOps->fbobjectID); 249 250 return oglc; 251 } 252 253 JNF_COCOA_ENTER(env); 254 255 // set the current surface 256 if (dstOps->drawableType == OGLSD_PBUFFER) { 257 // REMIND: pbuffers are not fully tested yet... 258 [ctxinfo->context clearDrawable]; 259 [ctxinfo->context makeCurrentContext]; 260 [ctxinfo->context setPixelBuffer: dstCGLOps->pbuffer 261 cubeMapFace: 0 262 mipMapLevel: 0 263 currentVirtualScreen: [ctxinfo->context currentVirtualScreen]]; 264 } else { 265 CGLSDOps *cglsdo = (CGLSDOps *)dstOps->privOps; 266 NSView *nsView = (NSView *)cglsdo->peerData; 267 268 if ([ctxinfo->context view] != nsView) { 269 [ctxinfo->context makeCurrentContext]; 270 [ctxinfo->context setView: nsView]; 271 } 272 } 273 274 if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) { 275 // the GL_EXT_framebuffer_object extension is present, so we 276 // must bind to the default (windowing system provided) 277 // framebuffer 278 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 279 } 280 281 if ((srcOps != dstOps) && (srcOps->drawableType == OGLSD_PBUFFER)) { 282 // bind pbuffer to the render texture object (since we are preparing 283 // to copy from the pbuffer) 284 CGLSDOps *srcCGLOps = (CGLSDOps *)srcOps->privOps; 285 j2d_glBindTexture(GL_TEXTURE_2D, srcOps->textureID); 286 [ctxinfo->context 287 setTextureImageToPixelBuffer: srcCGLOps->pbuffer 288 colorBuffer: GL_FRONT]; 289 } 290 291 JNF_COCOA_EXIT(env); 292 293 return oglc; 294 } 295 296 /** 297 * This function initializes a native window surface and caches the window 298 * bounds in the given OGLSDOps. Returns JNI_TRUE if the operation was 299 * successful; JNI_FALSE otherwise. 300 */ 301 jboolean 302 OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo) 303 { 304 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_InitOGLWindow"); 305 306 if (oglsdo == NULL) { 307 J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_InitOGLWindow: ops are null"); 308 return JNI_FALSE; 309 } 310 311 CGLSDOps *cglsdo = (CGLSDOps *)oglsdo->privOps; 312 if (cglsdo == NULL) { 313 J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_InitOGLWindow: cgl ops are null"); 314 return JNI_FALSE; 315 } 316 317 AWTView *v = cglsdo->peerData; 318 if (v == NULL) { 319 J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_InitOGLWindow: view is invalid"); 320 return JNI_FALSE; 321 } 322 323 JNF_COCOA_ENTER(env); 324 NSRect surfaceBounds = [v bounds]; 325 oglsdo->drawableType = OGLSD_WINDOW; 326 oglsdo->isOpaque = JNI_TRUE; 327 oglsdo->width = surfaceBounds.size.width; 328 oglsdo->height = surfaceBounds.size.height; 329 JNF_COCOA_EXIT(env); 330 331 J2dTraceLn2(J2D_TRACE_VERBOSE, " created window: w=%d h=%d", oglsdo->width, oglsdo->height); 332 333 return JNI_TRUE; 334 } 335 336 void 337 OGLSD_SwapBuffers(JNIEnv *env, jlong pPeerData) 338 { 339 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SwapBuffers"); 340 341 JNF_COCOA_ENTER(env); 342 [[NSOpenGLContext currentContext] flushBuffer]; 343 JNF_COCOA_EXIT(env); 344 } 345 346 void 347 OGLSD_Flush(JNIEnv *env) 348 { 349 OGLSDOps *dstOps = OGLRenderQueue_GetCurrentDestination(); 350 if (dstOps != NULL) { 351 CGLSDOps *dstCGLOps = (CGLSDOps *)dstOps->privOps; 352 CGLLayer *layer = (CGLLayer*)dstCGLOps->layer; 353 if (layer != NULL) { 354 [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ 355 AWT_ASSERT_APPKIT_THREAD; 356 [layer setNeedsDisplay]; 357 358 #ifdef REMOTELAYER 359 /* If there's a remote layer (being used for testing) 360 * then we want to have that also receive the texture. 361 * First sync. up its dimensions with that of the layer 362 * we have attached to the local window and tell it that 363 * it also needs to copy the texture. 364 */ 365 if (layer.remoteLayer != nil) { 366 CGLLayer* remoteLayer = layer.remoteLayer; 367 remoteLayer.target = GL_TEXTURE_2D; 368 remoteLayer.textureID = layer.textureID; 369 remoteLayer.textureWidth = layer.textureWidth; 370 remoteLayer.textureHeight = layer.textureHeight; 371 [remoteLayer setNeedsDisplay]; 372 } 373 #endif /* REMOTELAYER */ 374 }]; 375 } 376 } 377 } 378 379 #pragma mark - 380 #pragma mark "--- CGLSurfaceData methods ---" 381 382 extern LockFunc OGLSD_Lock; 383 extern GetRasInfoFunc OGLSD_GetRasInfo; 384 extern UnlockFunc OGLSD_Unlock; 385 extern DisposeFunc OGLSD_Dispose; 386 387 JNIEXPORT void JNICALL 388 Java_sun_java2d_opengl_CGLSurfaceData_initOps 389 (JNIEnv *env, jobject cglsd, jobject gc, 390 jlong pConfigInfo, jlong pPeerData, jlong layerPtr, 391 jint xoff, jint yoff, jboolean isOpaque) 392 { 393 J2dTraceLn(J2D_TRACE_INFO, "CGLSurfaceData_initOps"); 394 J2dTraceLn1(J2D_TRACE_INFO, " pPeerData=%p", jlong_to_ptr(pPeerData)); 395 J2dTraceLn2(J2D_TRACE_INFO, " xoff=%d, yoff=%d", (int)xoff, (int)yoff); 396 397 gc = (*env)->NewGlobalRef(env, gc); 398 if (gc == NULL) { 399 JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed."); 400 return; 401 } 402 403 OGLSDOps *oglsdo = (OGLSDOps *) 404 SurfaceData_InitOps(env, cglsd, sizeof(OGLSDOps)); 405 if (oglsdo == NULL) { 406 (*env)->DeleteGlobalRef(env, gc); 407 JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed."); 408 return; 409 } 410 // later the graphicsConfig will be used for deallocation of oglsdo 411 oglsdo->graphicsConfig = gc; 412 413 CGLSDOps *cglsdo = (CGLSDOps *)malloc(sizeof(CGLSDOps)); 414 if (cglsdo == NULL) { 415 JNU_ThrowOutOfMemoryError(env, "creating native cgl ops"); 416 return; 417 } 418 419 oglsdo->privOps = cglsdo; 420 421 oglsdo->sdOps.Lock = OGLSD_Lock; 422 oglsdo->sdOps.GetRasInfo = OGLSD_GetRasInfo; 423 oglsdo->sdOps.Unlock = OGLSD_Unlock; 424 oglsdo->sdOps.Dispose = OGLSD_Dispose; 425 426 oglsdo->drawableType = OGLSD_UNDEFINED; 427 oglsdo->activeBuffer = GL_FRONT; 428 oglsdo->needsInit = JNI_TRUE; 429 oglsdo->xOffset = xoff; 430 oglsdo->yOffset = yoff; 431 oglsdo->isOpaque = isOpaque; 432 433 cglsdo->peerData = (AWTView *)jlong_to_ptr(pPeerData); 434 cglsdo->layer = (CGLLayer *)jlong_to_ptr(layerPtr); 435 cglsdo->configInfo = (CGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo); 436 437 if (cglsdo->configInfo == NULL) { 438 free(cglsdo); 439 JNU_ThrowNullPointerException(env, "Config info is null in initOps"); 440 } 441 } 442 443 JNIEXPORT void JNICALL 444 Java_sun_java2d_opengl_CGLSurfaceData_clearWindow 445 (JNIEnv *env, jobject cglsd) 446 { 447 J2dTraceLn(J2D_TRACE_INFO, "CGLSurfaceData_clearWindow"); 448 449 OGLSDOps *oglsdo = (OGLSDOps*) SurfaceData_GetOps(env, cglsd); 450 CGLSDOps *cglsdo = (CGLSDOps*) oglsdo->privOps; 451 452 cglsdo->peerData = NULL; 453 cglsdo->layer = NULL; 454 } 455 456 JNIEXPORT jboolean JNICALL 457 Java_sun_java2d_opengl_CGLSurfaceData_initPbuffer 458 (JNIEnv *env, jobject cglsd, 459 jlong pData, jlong pConfigInfo, jboolean isOpaque, 460 jint width, jint height) 461 { 462 J2dTraceLn3(J2D_TRACE_INFO, "CGLSurfaceData_initPbuffer: w=%d h=%d opq=%d", width, height, isOpaque); 463 464 OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData); 465 if (oglsdo == NULL) { 466 J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: ops are null"); 467 return JNI_FALSE; 468 } 469 470 CGLSDOps *cglsdo = (CGLSDOps *)oglsdo->privOps; 471 if (cglsdo == NULL) { 472 J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: cgl ops are null"); 473 return JNI_FALSE; 474 } 475 476 CGLGraphicsConfigInfo *cglInfo = (CGLGraphicsConfigInfo *) 477 jlong_to_ptr(pConfigInfo); 478 if (cglInfo == NULL) { 479 J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: cgl config info is null"); 480 return JNI_FALSE; 481 } 482 483 // find the maximum allowable texture dimensions (this value ultimately 484 // determines our maximum pbuffer size) 485 int pbMax = 0; 486 j2d_glGetIntegerv(GL_MAX_TEXTURE_SIZE, &pbMax); 487 488 int pbWidth = 0; 489 int pbHeight = 0; 490 if (OGLC_IS_CAP_PRESENT(cglInfo->context, CAPS_TEXNONPOW2)) { 491 // use non-power-of-two dimensions directly 492 pbWidth = (width <= pbMax) ? width : 0; 493 pbHeight = (height <= pbMax) ? height : 0; 494 } else { 495 // find the appropriate power-of-two dimensions 496 pbWidth = OGLSD_NextPowerOfTwo(width, pbMax); 497 pbHeight = OGLSD_NextPowerOfTwo(height, pbMax); 498 } 499 500 J2dTraceLn3(J2D_TRACE_VERBOSE, " desired pbuffer dimensions: w=%d h=%d max=%d", pbWidth, pbHeight, pbMax); 501 502 // if either dimension is 0, we cannot allocate a pbuffer/texture with the 503 // requested dimensions 504 if (pbWidth == 0 || pbHeight == 0) { 505 J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: dimensions too large"); 506 return JNI_FALSE; 507 } 508 509 int format = isOpaque ? GL_RGB : GL_RGBA; 510 511 JNF_COCOA_ENTER(env); 512 513 cglsdo->pbuffer = 514 [[NSOpenGLPixelBuffer alloc] 515 initWithTextureTarget: GL_TEXTURE_2D 516 textureInternalFormat: format 517 textureMaxMipMapLevel: 0 518 pixelsWide: pbWidth 519 pixelsHigh: pbHeight]; 520 if (cglsdo->pbuffer == nil) { 521 J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: could not create pbuffer"); 522 return JNI_FALSE; 523 } 524 525 // make sure the actual dimensions match those that we requested 526 GLsizei actualWidth = [cglsdo->pbuffer pixelsWide]; 527 GLsizei actualHeight = [cglsdo->pbuffer pixelsHigh]; 528 if (actualWidth != pbWidth || actualHeight != pbHeight) { 529 J2dRlsTraceLn2(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: actual (w=%d h=%d) != requested", actualWidth, actualHeight); 530 [cglsdo->pbuffer release]; 531 return JNI_FALSE; 532 } 533 534 GLuint texID = 0; 535 j2d_glGenTextures(1, &texID); 536 j2d_glBindTexture(GL_TEXTURE_2D, texID); 537 538 oglsdo->drawableType = OGLSD_PBUFFER; 539 oglsdo->isOpaque = isOpaque; 540 oglsdo->width = width; 541 oglsdo->height = height; 542 oglsdo->textureID = texID; 543 oglsdo->textureWidth = pbWidth; 544 oglsdo->textureHeight = pbHeight; 545 oglsdo->activeBuffer = GL_FRONT; 546 oglsdo->needsInit = JNI_TRUE; 547 548 OGLSD_INIT_TEXTURE_FILTER(oglsdo, GL_NEAREST); 549 550 JNF_COCOA_EXIT(env); 551 552 return JNI_TRUE; 553 } 554 555 #pragma mark - 556 #pragma mark "--- CGLSurfaceData methods - Mac OS X specific ---" 557 558 // Must be called on the QFT... 559 JNIEXPORT void JNICALL 560 Java_sun_java2d_opengl_CGLSurfaceData_validate 561 (JNIEnv *env, jobject jsurfacedata, 562 jint xoff, jint yoff, jint width, jint height, jboolean isOpaque) 563 { 564 J2dTraceLn2(J2D_TRACE_INFO, "CGLSurfaceData_validate: w=%d h=%d", width, height); 565 566 OGLSDOps *oglsdo = (OGLSDOps*)SurfaceData_GetOps(env, jsurfacedata); 567 oglsdo->needsInit = JNI_TRUE; 568 oglsdo->xOffset = xoff; 569 oglsdo->yOffset = yoff; 570 571 oglsdo->width = width; 572 oglsdo->height = height; 573 oglsdo->isOpaque = isOpaque; 574 575 if (oglsdo->drawableType == OGLSD_WINDOW) { 576 OGLContext_SetSurfaces(env, ptr_to_jlong(oglsdo), ptr_to_jlong(oglsdo)); 577 578 // we have to explicitly tell the NSOpenGLContext that its target 579 // drawable has changed size 580 CGLSDOps *cglsdo = (CGLSDOps *)oglsdo->privOps; 581 OGLContext *oglc = cglsdo->configInfo->context; 582 CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo; 583 584 JNF_COCOA_ENTER(env); 585 [ctxinfo->context update]; 586 JNF_COCOA_EXIT(env); 587 } 588 }