1 /* 2 * Copyright (c) 2003, 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 <jlong.h> 27 28 #include "sun_java2d_opengl_GLXSurfaceData.h" 29 30 #include "OGLRenderQueue.h" 31 #include "GLXGraphicsConfig.h" 32 #include "GLXSurfaceData.h" 33 #include "awt_Component.h" 34 #include "awt_GraphicsEnv.h" 35 36 /** 37 * The methods in this file implement the native windowing system specific 38 * layer (GLX) for the OpenGL-based Java 2D pipeline. 39 */ 40 41 #ifndef HEADLESS 42 43 extern LockFunc OGLSD_Lock; 44 extern GetRasInfoFunc OGLSD_GetRasInfo; 45 extern UnlockFunc OGLSD_Unlock; 46 extern DisposeFunc OGLSD_Dispose; 47 48 extern struct MComponentPeerIDs mComponentPeerIDs; 49 50 extern void 51 OGLSD_SetNativeDimensions(JNIEnv *env, OGLSDOps *oglsdo, jint w, jint h); 52 53 jboolean surfaceCreationFailed = JNI_FALSE; 54 55 #endif /* !HEADLESS */ 56 57 JNIEXPORT void JNICALL 58 Java_sun_java2d_opengl_GLXSurfaceData_initOps(JNIEnv *env, jobject glxsd, 59 jobject peer, jlong aData) 60 { 61 #ifndef HEADLESS 62 OGLSDOps *oglsdo = (OGLSDOps *)SurfaceData_InitOps(env, glxsd, 63 sizeof(OGLSDOps)); 64 GLXSDOps *glxsdo = (GLXSDOps *)malloc(sizeof(GLXSDOps)); 65 66 J2dTraceLn(J2D_TRACE_INFO, "GLXSurfaceData_initOps"); 67 68 if (oglsdo == NULL) { 69 JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed."); 70 return; 71 } 72 73 if (glxsdo == NULL) { 74 JNU_ThrowOutOfMemoryError(env, "creating native GLX ops"); 75 return; 76 } 77 78 oglsdo->privOps = glxsdo; 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 89 #ifdef XAWT 90 if (peer != NULL) { 91 glxsdo->window = JNU_CallMethodByName(env, NULL, peer, 92 "getContentWindow", "()J").j; 93 } else { 94 glxsdo->window = 0; 95 } 96 #else 97 if (peer != NULL) { 98 struct ComponentData *cdata; 99 cdata = (struct ComponentData *) 100 JNU_GetLongFieldAsPtr(env, peer, mComponentPeerIDs.pData); 101 if (cdata == NULL) { 102 free(glxsdo); 103 JNU_ThrowNullPointerException(env, "Component data missing"); 104 return; 105 } 106 if (cdata->widget == NULL) { 107 free(glxsdo); 108 JNU_ThrowInternalError(env, "Widget is NULL in initOps"); 109 return; 110 } 111 glxsdo->widget = cdata->widget; 112 } else { 113 glxsdo->widget = NULL; 114 } 115 #endif 116 117 glxsdo->configData = (AwtGraphicsConfigDataPtr)jlong_to_ptr(aData); 118 if (glxsdo->configData == NULL) { 119 free(glxsdo); 120 JNU_ThrowNullPointerException(env, 121 "Native GraphicsConfig data block missing"); 122 return; 123 } 124 125 if (glxsdo->configData->glxInfo == NULL) { 126 free(glxsdo); 127 JNU_ThrowNullPointerException(env, "GLXGraphicsConfigInfo missing"); 128 return; 129 } 130 #endif /* HEADLESS */ 131 } 132 133 #ifndef HEADLESS 134 135 /** 136 * This function disposes of any native windowing system resources associated 137 * with this surface. For instance, if the given OGLSDOps is of type 138 * OGLSD_PBUFFER, this method implementation will destroy the actual pbuffer 139 * surface. 140 */ 141 void 142 OGLSD_DestroyOGLSurface(JNIEnv *env, OGLSDOps *oglsdo) 143 { 144 GLXSDOps *glxsdo = (GLXSDOps *)oglsdo->privOps; 145 146 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_DestroyOGLSurface"); 147 148 if (oglsdo->drawableType == OGLSD_PBUFFER) { 149 if (glxsdo->drawable != 0) { 150 j2d_glXDestroyPbuffer(awt_display, glxsdo->drawable); 151 glxsdo->drawable = 0; 152 } 153 } else if (oglsdo->drawableType == OGLSD_WINDOW) { 154 // X Window is free'd later by AWT code... 155 } 156 } 157 158 /** 159 * Makes the given context current to its associated "scratch" surface. If 160 * the operation is successful, this method will return JNI_TRUE; otherwise, 161 * returns JNI_FALSE. 162 */ 163 static jboolean 164 GLXSD_MakeCurrentToScratch(JNIEnv *env, OGLContext *oglc) 165 { 166 GLXCtxInfo *ctxInfo; 167 168 J2dTraceLn(J2D_TRACE_INFO, "GLXSD_MakeCurrentToScratch"); 169 170 if (oglc == NULL) { 171 J2dRlsTraceLn(J2D_TRACE_ERROR, 172 "GLXSD_MakeCurrentToScratch: context is null"); 173 return JNI_FALSE; 174 } 175 176 ctxInfo = (GLXCtxInfo *)oglc->ctxInfo; 177 if (!j2d_glXMakeContextCurrent(awt_display, 178 ctxInfo->scratchSurface, 179 ctxInfo->scratchSurface, 180 ctxInfo->context)) 181 { 182 J2dRlsTraceLn(J2D_TRACE_ERROR, 183 "GLXSD_MakeCurrentToScratch: could not make current"); 184 return JNI_FALSE; 185 } 186 187 return JNI_TRUE; 188 } 189 190 /** 191 * Returns a pointer (as a jlong) to the native GLXGraphicsConfigInfo 192 * associated with the given OGLSDOps. This method can be called from 193 * shared code to retrieve the native GraphicsConfig data in a platform- 194 * independent manner. 195 */ 196 jlong 197 OGLSD_GetNativeConfigInfo(OGLSDOps *oglsdo) 198 { 199 GLXSDOps *glxsdo; 200 201 if (oglsdo == NULL) { 202 J2dRlsTraceLn(J2D_TRACE_ERROR, 203 "OGLSD_GetNativeConfigInfo: ops are null"); 204 return 0L; 205 } 206 207 glxsdo = (GLXSDOps *)oglsdo->privOps; 208 if (glxsdo == NULL) { 209 J2dRlsTraceLn(J2D_TRACE_ERROR, 210 "OGLSD_GetNativeConfigInfo: glx ops are null"); 211 return 0L; 212 } 213 214 if (glxsdo->configData == NULL) { 215 J2dRlsTraceLn(J2D_TRACE_ERROR, 216 "OGLSD_GetNativeConfigInfo: config data is null"); 217 return 0L; 218 } 219 220 return ptr_to_jlong(glxsdo->configData->glxInfo); 221 } 222 223 /** 224 * Makes the given GraphicsConfig's context current to its associated 225 * "scratch" surface. If there is a problem making the context current, 226 * this method will return NULL; otherwise, returns a pointer to the 227 * OGLContext that is associated with the given GraphicsConfig. 228 */ 229 OGLContext * 230 OGLSD_SetScratchSurface(JNIEnv *env, jlong pConfigInfo) 231 { 232 GLXGraphicsConfigInfo *glxInfo = 233 (GLXGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo); 234 OGLContext *oglc; 235 236 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SetScratchContext"); 237 238 if (glxInfo == NULL) { 239 J2dRlsTraceLn(J2D_TRACE_ERROR, 240 "OGLSD_SetScratchContext: glx config info is null"); 241 return NULL; 242 } 243 244 oglc = glxInfo->context; 245 if (!GLXSD_MakeCurrentToScratch(env, oglc)) { 246 return NULL; 247 } 248 249 if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) { 250 // the GL_EXT_framebuffer_object extension is present, so this call 251 // will ensure that we are bound to the scratch pbuffer (and not 252 // some other framebuffer object) 253 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 254 } 255 256 return oglc; 257 } 258 259 /** 260 * Makes a context current to the given source and destination 261 * surfaces. If there is a problem making the context current, this method 262 * will return NULL; otherwise, returns a pointer to the OGLContext that is 263 * associated with the destination surface. 264 */ 265 OGLContext * 266 OGLSD_MakeOGLContextCurrent(JNIEnv *env, OGLSDOps *srcOps, OGLSDOps *dstOps) 267 { 268 GLXSDOps *dstGLXOps = (GLXSDOps *)dstOps->privOps; 269 OGLContext *oglc; 270 271 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_MakeOGLContextCurrent"); 272 273 oglc = dstGLXOps->configData->glxInfo->context; 274 if (oglc == NULL) { 275 J2dRlsTraceLn(J2D_TRACE_ERROR, 276 "OGLSD_MakeOGLContextCurrent: context is null"); 277 return NULL; 278 } 279 280 if (dstOps->drawableType == OGLSD_FBOBJECT) { 281 OGLContext *currentContext = OGLRenderQueue_GetCurrentContext(); 282 283 // first make sure we have a current context (if the context isn't 284 // already current to some drawable, we will make it current to 285 // its scratch surface) 286 if (oglc != currentContext) { 287 if (!GLXSD_MakeCurrentToScratch(env, oglc)) { 288 return NULL; 289 } 290 } 291 292 // now bind to the fbobject associated with the destination surface; 293 // this means that all rendering will go into the fbobject destination 294 // (note that we unbind the currently bound texture first; this is 295 // recommended procedure when binding an fbobject) 296 j2d_glBindTexture(dstOps->textureTarget, 0); 297 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dstOps->fbobjectID); 298 } else { 299 GLXSDOps *srcGLXOps = (GLXSDOps *)srcOps->privOps; 300 GLXCtxInfo *ctxinfo = (GLXCtxInfo *)oglc->ctxInfo; 301 302 // make the context current 303 if (!j2d_glXMakeContextCurrent(awt_display, 304 dstGLXOps->drawable, 305 srcGLXOps->drawable, 306 ctxinfo->context)) 307 { 308 J2dRlsTraceLn(J2D_TRACE_ERROR, 309 "OGLSD_MakeOGLContextCurrent: could not make current"); 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 321 return oglc; 322 } 323 324 /** 325 * This function initializes a native window surface and caches the window 326 * bounds in the given OGLSDOps. Returns JNI_TRUE if the operation was 327 * successful; JNI_FALSE otherwise. 328 */ 329 jboolean 330 OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo) 331 { 332 GLXSDOps *glxsdo; 333 Window window; 334 #ifdef XAWT 335 XWindowAttributes attr; 336 #else 337 Widget widget; 338 #endif 339 340 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_InitOGLWindow"); 341 342 if (oglsdo == NULL) { 343 J2dRlsTraceLn(J2D_TRACE_ERROR, 344 "OGLSD_InitOGLWindow: ops are null"); 345 return JNI_FALSE; 346 } 347 348 glxsdo = (GLXSDOps *)oglsdo->privOps; 349 if (glxsdo == NULL) { 350 J2dRlsTraceLn(J2D_TRACE_ERROR, 351 "OGLSD_InitOGLWindow: glx ops are null"); 352 return JNI_FALSE; 353 } 354 355 #ifdef XAWT 356 window = glxsdo->window; 357 if (window == 0) { 358 J2dRlsTraceLn(J2D_TRACE_ERROR, 359 "OGLSD_InitOGLWindow: window is invalid"); 360 return JNI_FALSE; 361 } 362 363 XGetWindowAttributes(awt_display, window, &attr); 364 oglsdo->width = attr.width; 365 oglsdo->height = attr.height; 366 #else 367 widget = glxsdo->widget; 368 if (widget == NULL) { 369 J2dTraceLn(J2D_TRACE_WARNING, "OGLSD_InitOGLWindow: widget is null"); 370 } 371 372 if (!XtIsRealized(widget)) { 373 J2dRlsTraceLn(J2D_TRACE_ERROR, 374 "OGLSD_InitOGLWindow: widget is unrealized"); 375 return JNI_FALSE; 376 } 377 378 window = XtWindow(widget); 379 oglsdo->width = widget->core.width; 380 oglsdo->height = widget->core.height; 381 #endif 382 383 oglsdo->drawableType = OGLSD_WINDOW; 384 oglsdo->isOpaque = JNI_TRUE; 385 oglsdo->xOffset = 0; 386 oglsdo->yOffset = 0; 387 glxsdo->drawable = window; 388 glxsdo->xdrawable = window; 389 390 J2dTraceLn2(J2D_TRACE_VERBOSE, " created window: w=%d h=%d", 391 oglsdo->width, oglsdo->height); 392 393 return JNI_TRUE; 394 } 395 396 static int 397 GLXSD_BadAllocXErrHandler(Display *display, XErrorEvent *xerr) 398 { 399 int ret = 0; 400 if (xerr->error_code == BadAlloc) { 401 surfaceCreationFailed = JNI_TRUE; 402 } else { 403 ret = (*xerror_saved_handler)(display, xerr); 404 } 405 return ret; 406 } 407 408 JNIEXPORT jboolean JNICALL 409 Java_sun_java2d_opengl_GLXSurfaceData_initPbuffer 410 (JNIEnv *env, jobject glxsd, 411 jlong pData, jlong pConfigInfo, 412 jboolean isOpaque, 413 jint width, jint height) 414 { 415 OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData); 416 GLXGraphicsConfigInfo *glxinfo = 417 (GLXGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo); 418 GLXSDOps *glxsdo; 419 GLXPbuffer pbuffer; 420 int attrlist[] = {GLX_PBUFFER_WIDTH, 0, 421 GLX_PBUFFER_HEIGHT, 0, 422 GLX_PRESERVED_CONTENTS, GL_FALSE, 0}; 423 424 J2dTraceLn3(J2D_TRACE_INFO, 425 "GLXSurfaceData_initPbuffer: w=%d h=%d opq=%d", 426 width, height, isOpaque); 427 428 if (oglsdo == NULL) { 429 J2dRlsTraceLn(J2D_TRACE_ERROR, 430 "GLXSurfaceData_initPbuffer: ops are null"); 431 return JNI_FALSE; 432 } 433 434 glxsdo = (GLXSDOps *)oglsdo->privOps; 435 if (glxsdo == NULL) { 436 J2dRlsTraceLn(J2D_TRACE_ERROR, 437 "GLXSurfaceData_initPbuffer: glx ops are null"); 438 return JNI_FALSE; 439 } 440 441 if (glxinfo == NULL) { 442 J2dRlsTraceLn(J2D_TRACE_ERROR, 443 "GLXSurfaceData_initPbuffer: glx config info is null"); 444 return JNI_FALSE; 445 } 446 447 attrlist[1] = width; 448 attrlist[3] = height; 449 450 surfaceCreationFailed = JNI_FALSE; 451 EXEC_WITH_XERROR_HANDLER( 452 GLXSD_BadAllocXErrHandler, 453 pbuffer = j2d_glXCreatePbuffer(awt_display, 454 glxinfo->fbconfig, attrlist)); 455 if ((pbuffer == 0) || surfaceCreationFailed) { 456 J2dRlsTraceLn(J2D_TRACE_ERROR, 457 "GLXSurfaceData_initPbuffer: could not create glx pbuffer"); 458 return JNI_FALSE; 459 } 460 461 oglsdo->drawableType = OGLSD_PBUFFER; 462 oglsdo->isOpaque = isOpaque; 463 oglsdo->width = width; 464 oglsdo->height = height; 465 oglsdo->xOffset = 0; 466 oglsdo->yOffset = 0; 467 468 glxsdo->drawable = pbuffer; 469 glxsdo->xdrawable = 0; 470 471 OGLSD_SetNativeDimensions(env, oglsdo, width, height); 472 473 return JNI_TRUE; 474 } 475 476 void 477 OGLSD_SwapBuffers(JNIEnv *env, jlong window) 478 { 479 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SwapBuffers"); 480 481 if (window == 0L) { 482 J2dRlsTraceLn(J2D_TRACE_ERROR, 483 "OGLSD_SwapBuffers: window is null"); 484 return; 485 } 486 487 j2d_glXSwapBuffers(awt_display, (Window)window); 488 } 489 490 // needed by Mac OS X port, no-op on other platforms 491 void 492 OGLSD_Flush(JNIEnv *env) 493 { 494 } 495 496 #endif /* !HEADLESS */