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 void 49 OGLSD_SetNativeDimensions(JNIEnv *env, OGLSDOps *oglsdo, jint w, jint h); 50 51 jboolean surfaceCreationFailed = JNI_FALSE; 52 53 #endif /* !HEADLESS */ 54 55 JNIEXPORT void JNICALL 56 Java_sun_java2d_opengl_GLXSurfaceData_initOps(JNIEnv *env, jobject glxsd, 57 jobject peer, jlong aData) 58 { 59 #ifndef HEADLESS 60 OGLSDOps *oglsdo = (OGLSDOps *)SurfaceData_InitOps(env, glxsd, 61 sizeof(OGLSDOps)); 62 GLXSDOps *glxsdo = (GLXSDOps *)malloc(sizeof(GLXSDOps)); 63 64 J2dTraceLn(J2D_TRACE_INFO, "GLXSurfaceData_initOps"); 65 66 if (oglsdo == NULL) { 67 JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed."); 68 return; 69 } 70 71 if (glxsdo == NULL) { 72 JNU_ThrowOutOfMemoryError(env, "creating native GLX ops"); 73 return; 74 } 75 76 oglsdo->privOps = glxsdo; 77 78 oglsdo->sdOps.Lock = OGLSD_Lock; 79 oglsdo->sdOps.GetRasInfo = OGLSD_GetRasInfo; 80 oglsdo->sdOps.Unlock = OGLSD_Unlock; 81 oglsdo->sdOps.Dispose = OGLSD_Dispose; 82 83 oglsdo->drawableType = OGLSD_UNDEFINED; 84 oglsdo->activeBuffer = GL_FRONT; 85 oglsdo->needsInit = JNI_TRUE; 86 87 if (peer != NULL) { 88 glxsdo->window = JNU_CallMethodByName(env, NULL, peer, 89 "getContentWindow", "()J").j; 90 } else { 91 glxsdo->window = 0; 92 } 93 glxsdo->configData = (AwtGraphicsConfigDataPtr)jlong_to_ptr(aData); 94 if (glxsdo->configData == NULL) { 95 free(glxsdo); 96 JNU_ThrowNullPointerException(env, 97 "Native GraphicsConfig data block missing"); 98 return; 99 } 100 101 if (glxsdo->configData->glxInfo == NULL) { 102 free(glxsdo); 103 JNU_ThrowNullPointerException(env, "GLXGraphicsConfigInfo missing"); 104 return; 105 } 106 #endif /* HEADLESS */ 107 } 108 109 #ifndef HEADLESS 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 GLXSDOps *glxsdo = (GLXSDOps *)oglsdo->privOps; 121 122 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_DestroyOGLSurface"); 123 124 if (oglsdo->drawableType == OGLSD_PBUFFER) { 125 if (glxsdo->drawable != 0) { 126 j2d_glXDestroyPbuffer(awt_display, glxsdo->drawable); 127 glxsdo->drawable = 0; 128 } 129 } else if (oglsdo->drawableType == OGLSD_WINDOW) { 130 // X Window is free'd later by AWT code... 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 GLXSD_MakeCurrentToScratch(JNIEnv *env, OGLContext *oglc) 141 { 142 GLXCtxInfo *ctxInfo; 143 144 J2dTraceLn(J2D_TRACE_INFO, "GLXSD_MakeCurrentToScratch"); 145 146 if (oglc == NULL) { 147 J2dRlsTraceLn(J2D_TRACE_ERROR, 148 "GLXSD_MakeCurrentToScratch: context is null"); 149 return JNI_FALSE; 150 } 151 152 ctxInfo = (GLXCtxInfo *)oglc->ctxInfo; 153 if (!j2d_glXMakeContextCurrent(awt_display, 154 ctxInfo->scratchSurface, 155 ctxInfo->scratchSurface, 156 ctxInfo->context)) 157 { 158 J2dRlsTraceLn(J2D_TRACE_ERROR, 159 "GLXSD_MakeCurrentToScratch: could not make current"); 160 return JNI_FALSE; 161 } 162 163 return JNI_TRUE; 164 } 165 166 /** 167 * Returns a pointer (as a jlong) to the native GLXGraphicsConfigInfo 168 * associated with the given OGLSDOps. This method can be called from 169 * shared code to retrieve the native GraphicsConfig data in a platform- 170 * independent manner. 171 */ 172 jlong 173 OGLSD_GetNativeConfigInfo(OGLSDOps *oglsdo) 174 { 175 GLXSDOps *glxsdo; 176 177 if (oglsdo == NULL) { 178 J2dRlsTraceLn(J2D_TRACE_ERROR, 179 "OGLSD_GetNativeConfigInfo: ops are null"); 180 return 0L; 181 } 182 183 glxsdo = (GLXSDOps *)oglsdo->privOps; 184 if (glxsdo == NULL) { 185 J2dRlsTraceLn(J2D_TRACE_ERROR, 186 "OGLSD_GetNativeConfigInfo: glx ops are null"); 187 return 0L; 188 } 189 190 if (glxsdo->configData == NULL) { 191 J2dRlsTraceLn(J2D_TRACE_ERROR, 192 "OGLSD_GetNativeConfigInfo: config data is null"); 193 return 0L; 194 } 195 196 return ptr_to_jlong(glxsdo->configData->glxInfo); 197 } 198 199 /** 200 * Makes the given GraphicsConfig's context current to its associated 201 * "scratch" surface. If there is a problem making the context current, 202 * this method will return NULL; otherwise, returns a pointer to the 203 * OGLContext that is associated with the given GraphicsConfig. 204 */ 205 OGLContext * 206 OGLSD_SetScratchSurface(JNIEnv *env, jlong pConfigInfo) 207 { 208 GLXGraphicsConfigInfo *glxInfo = 209 (GLXGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo); 210 OGLContext *oglc; 211 212 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SetScratchContext"); 213 214 if (glxInfo == NULL) { 215 J2dRlsTraceLn(J2D_TRACE_ERROR, 216 "OGLSD_SetScratchContext: glx config info is null"); 217 return NULL; 218 } 219 220 oglc = glxInfo->context; 221 if (!GLXSD_MakeCurrentToScratch(env, oglc)) { 222 return NULL; 223 } 224 225 if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) { 226 // the GL_EXT_framebuffer_object extension is present, so this call 227 // will ensure that we are bound to the scratch pbuffer (and not 228 // some other framebuffer object) 229 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 230 } 231 232 return oglc; 233 } 234 235 /** 236 * Makes a context current to the given source and destination 237 * surfaces. If there is a problem making the context current, this method 238 * will return NULL; otherwise, returns a pointer to the OGLContext that is 239 * associated with the destination surface. 240 */ 241 OGLContext * 242 OGLSD_MakeOGLContextCurrent(JNIEnv *env, OGLSDOps *srcOps, OGLSDOps *dstOps) 243 { 244 GLXSDOps *dstGLXOps = (GLXSDOps *)dstOps->privOps; 245 OGLContext *oglc; 246 247 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_MakeOGLContextCurrent"); 248 249 oglc = dstGLXOps->configData->glxInfo->context; 250 if (oglc == NULL) { 251 J2dRlsTraceLn(J2D_TRACE_ERROR, 252 "OGLSD_MakeOGLContextCurrent: context is null"); 253 return NULL; 254 } 255 256 if (dstOps->drawableType == OGLSD_FBOBJECT) { 257 OGLContext *currentContext = OGLRenderQueue_GetCurrentContext(); 258 259 // first make sure we have a current context (if the context isn't 260 // already current to some drawable, we will make it current to 261 // its scratch surface) 262 if (oglc != currentContext) { 263 if (!GLXSD_MakeCurrentToScratch(env, oglc)) { 264 return NULL; 265 } 266 } 267 268 // now bind to the fbobject associated with the destination surface; 269 // this means that all rendering will go into the fbobject destination 270 // (note that we unbind the currently bound texture first; this is 271 // recommended procedure when binding an fbobject) 272 j2d_glBindTexture(dstOps->textureTarget, 0); 273 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dstOps->fbobjectID); 274 } else { 275 GLXSDOps *srcGLXOps = (GLXSDOps *)srcOps->privOps; 276 GLXCtxInfo *ctxinfo = (GLXCtxInfo *)oglc->ctxInfo; 277 278 // make the context current 279 if (!j2d_glXMakeContextCurrent(awt_display, 280 dstGLXOps->drawable, 281 srcGLXOps->drawable, 282 ctxinfo->context)) 283 { 284 J2dRlsTraceLn(J2D_TRACE_ERROR, 285 "OGLSD_MakeOGLContextCurrent: could not make current"); 286 return NULL; 287 } 288 289 if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) { 290 // the GL_EXT_framebuffer_object extension is present, so we 291 // must bind to the default (windowing system provided) 292 // framebuffer 293 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 294 } 295 } 296 297 return oglc; 298 } 299 300 /** 301 * This function initializes a native window surface and caches the window 302 * bounds in the given OGLSDOps. Returns JNI_TRUE if the operation was 303 * successful; JNI_FALSE otherwise. 304 */ 305 jboolean 306 OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo) 307 { 308 GLXSDOps *glxsdo; 309 Window window; 310 XWindowAttributes attr; 311 312 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_InitOGLWindow"); 313 314 if (oglsdo == NULL) { 315 J2dRlsTraceLn(J2D_TRACE_ERROR, 316 "OGLSD_InitOGLWindow: ops are null"); 317 return JNI_FALSE; 318 } 319 320 glxsdo = (GLXSDOps *)oglsdo->privOps; 321 if (glxsdo == NULL) { 322 J2dRlsTraceLn(J2D_TRACE_ERROR, 323 "OGLSD_InitOGLWindow: glx ops are null"); 324 return JNI_FALSE; 325 } 326 327 window = glxsdo->window; 328 if (window == 0) { 329 J2dRlsTraceLn(J2D_TRACE_ERROR, 330 "OGLSD_InitOGLWindow: window is invalid"); 331 return JNI_FALSE; 332 } 333 334 XGetWindowAttributes(awt_display, window, &attr); 335 oglsdo->width = attr.width; 336 oglsdo->height = attr.height; 337 338 oglsdo->drawableType = OGLSD_WINDOW; 339 oglsdo->isOpaque = JNI_TRUE; 340 oglsdo->xOffset = 0; 341 oglsdo->yOffset = 0; 342 glxsdo->drawable = window; 343 glxsdo->xdrawable = window; 344 345 J2dTraceLn2(J2D_TRACE_VERBOSE, " created window: w=%d h=%d", 346 oglsdo->width, oglsdo->height); 347 348 return JNI_TRUE; 349 } 350 351 static int 352 GLXSD_BadAllocXErrHandler(Display *display, XErrorEvent *xerr) 353 { 354 int ret = 0; 355 if (xerr->error_code == BadAlloc) { 356 surfaceCreationFailed = JNI_TRUE; 357 } else { 358 ret = (*xerror_saved_handler)(display, xerr); 359 } 360 return ret; 361 } 362 363 JNIEXPORT jboolean JNICALL 364 Java_sun_java2d_opengl_GLXSurfaceData_initPbuffer 365 (JNIEnv *env, jobject glxsd, 366 jlong pData, jlong pConfigInfo, 367 jboolean isOpaque, 368 jint width, jint height) 369 { 370 OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData); 371 GLXGraphicsConfigInfo *glxinfo = 372 (GLXGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo); 373 GLXSDOps *glxsdo; 374 GLXPbuffer pbuffer; 375 int attrlist[] = {GLX_PBUFFER_WIDTH, 0, 376 GLX_PBUFFER_HEIGHT, 0, 377 GLX_PRESERVED_CONTENTS, GL_FALSE, 0}; 378 379 J2dTraceLn3(J2D_TRACE_INFO, 380 "GLXSurfaceData_initPbuffer: w=%d h=%d opq=%d", 381 width, height, isOpaque); 382 383 if (oglsdo == NULL) { 384 J2dRlsTraceLn(J2D_TRACE_ERROR, 385 "GLXSurfaceData_initPbuffer: ops are null"); 386 return JNI_FALSE; 387 } 388 389 glxsdo = (GLXSDOps *)oglsdo->privOps; 390 if (glxsdo == NULL) { 391 J2dRlsTraceLn(J2D_TRACE_ERROR, 392 "GLXSurfaceData_initPbuffer: glx ops are null"); 393 return JNI_FALSE; 394 } 395 396 if (glxinfo == NULL) { 397 J2dRlsTraceLn(J2D_TRACE_ERROR, 398 "GLXSurfaceData_initPbuffer: glx config info is null"); 399 return JNI_FALSE; 400 } 401 402 attrlist[1] = width; 403 attrlist[3] = height; 404 405 surfaceCreationFailed = JNI_FALSE; 406 EXEC_WITH_XERROR_HANDLER( 407 GLXSD_BadAllocXErrHandler, 408 pbuffer = j2d_glXCreatePbuffer(awt_display, 409 glxinfo->fbconfig, attrlist)); 410 if ((pbuffer == 0) || surfaceCreationFailed) { 411 J2dRlsTraceLn(J2D_TRACE_ERROR, 412 "GLXSurfaceData_initPbuffer: could not create glx pbuffer"); 413 return JNI_FALSE; 414 } 415 416 oglsdo->drawableType = OGLSD_PBUFFER; 417 oglsdo->isOpaque = isOpaque; 418 oglsdo->width = width; 419 oglsdo->height = height; 420 oglsdo->xOffset = 0; 421 oglsdo->yOffset = 0; 422 423 glxsdo->drawable = pbuffer; 424 glxsdo->xdrawable = 0; 425 426 OGLSD_SetNativeDimensions(env, oglsdo, width, height); 427 428 return JNI_TRUE; 429 } 430 431 void 432 OGLSD_SwapBuffers(JNIEnv *env, jlong window) 433 { 434 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SwapBuffers"); 435 436 if (window == 0L) { 437 J2dRlsTraceLn(J2D_TRACE_ERROR, 438 "OGLSD_SwapBuffers: window is null"); 439 return; 440 } 441 442 j2d_glXSwapBuffers(awt_display, (Window)window); 443 } 444 445 // needed by Mac OS X port, no-op on other platforms 446 void 447 OGLSD_Flush(JNIEnv *env) 448 { 449 } 450 451 #endif /* !HEADLESS */