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