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