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