1 /* 2 * Copyright (c) 2003, 2015, 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. 115 */ 116 void 117 OGLSD_DestroyOGLSurface(JNIEnv *env, OGLSDOps *oglsdo) 118 { 119 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_DestroyOGLSurface"); 120 // X Window is free'd later by AWT code... 121 } 122 123 /** 124 * Makes the given context current to its associated "scratch" surface. If 125 * the operation is successful, this method will return JNI_TRUE; otherwise, 126 * returns JNI_FALSE. 127 */ 128 static jboolean 129 GLXSD_MakeCurrentToScratch(JNIEnv *env, OGLContext *oglc) 130 { 131 GLXCtxInfo *ctxInfo; 132 133 J2dTraceLn(J2D_TRACE_INFO, "GLXSD_MakeCurrentToScratch"); 134 135 if (oglc == NULL) { 136 J2dRlsTraceLn(J2D_TRACE_ERROR, 137 "GLXSD_MakeCurrentToScratch: context is null"); 138 return JNI_FALSE; 139 } 140 141 ctxInfo = (GLXCtxInfo *)oglc->ctxInfo; 142 if (!j2d_glXMakeContextCurrent(awt_display, 143 ctxInfo->scratchSurface, 144 ctxInfo->scratchSurface, 145 ctxInfo->context)) 146 { 147 J2dRlsTraceLn(J2D_TRACE_ERROR, 148 "GLXSD_MakeCurrentToScratch: could not make current"); 149 return JNI_FALSE; 150 } 151 152 return JNI_TRUE; 153 } 154 155 /** 156 * Returns a pointer (as a jlong) to the native GLXGraphicsConfigInfo 157 * associated with the given OGLSDOps. This method can be called from 158 * shared code to retrieve the native GraphicsConfig data in a platform- 159 * independent manner. 160 */ 161 jlong 162 OGLSD_GetNativeConfigInfo(OGLSDOps *oglsdo) 163 { 164 GLXSDOps *glxsdo; 165 166 if (oglsdo == NULL) { 167 J2dRlsTraceLn(J2D_TRACE_ERROR, 168 "OGLSD_GetNativeConfigInfo: ops are null"); 169 return 0L; 170 } 171 172 glxsdo = (GLXSDOps *)oglsdo->privOps; 173 if (glxsdo == NULL) { 174 J2dRlsTraceLn(J2D_TRACE_ERROR, 175 "OGLSD_GetNativeConfigInfo: glx ops are null"); 176 return 0L; 177 } 178 179 if (glxsdo->configData == NULL) { 180 J2dRlsTraceLn(J2D_TRACE_ERROR, 181 "OGLSD_GetNativeConfigInfo: config data is null"); 182 return 0L; 183 } 184 185 return ptr_to_jlong(glxsdo->configData->glxInfo); 186 } 187 188 /** 189 * Makes the given GraphicsConfig's context current to its associated 190 * "scratch" surface. If there is a problem making the context current, 191 * this method will return NULL; otherwise, returns a pointer to the 192 * OGLContext that is associated with the given GraphicsConfig. 193 */ 194 OGLContext * 195 OGLSD_SetScratchSurface(JNIEnv *env, jlong pConfigInfo) 196 { 197 GLXGraphicsConfigInfo *glxInfo = 198 (GLXGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo); 199 OGLContext *oglc; 200 201 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SetScratchContext"); 202 203 if (glxInfo == NULL) { 204 J2dRlsTraceLn(J2D_TRACE_ERROR, 205 "OGLSD_SetScratchContext: glx config info is null"); 206 return NULL; 207 } 208 209 oglc = glxInfo->context; 210 if (!GLXSD_MakeCurrentToScratch(env, oglc)) { 211 return NULL; 212 } 213 214 if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) { 215 // the GL_EXT_framebuffer_object extension is present, so this call 216 // will ensure that we are bound to the scratch pbuffer (and not 217 // some other framebuffer object) 218 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 219 } 220 221 return oglc; 222 } 223 224 /** 225 * Makes a context current to the given source and destination 226 * surfaces. If there is a problem making the context current, this method 227 * will return NULL; otherwise, returns a pointer to the OGLContext that is 228 * associated with the destination surface. 229 */ 230 OGLContext * 231 OGLSD_MakeOGLContextCurrent(JNIEnv *env, OGLSDOps *srcOps, OGLSDOps *dstOps) 232 { 233 GLXSDOps *dstGLXOps = (GLXSDOps *)dstOps->privOps; 234 OGLContext *oglc; 235 236 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_MakeOGLContextCurrent"); 237 238 oglc = dstGLXOps->configData->glxInfo->context; 239 if (oglc == NULL) { 240 J2dRlsTraceLn(J2D_TRACE_ERROR, 241 "OGLSD_MakeOGLContextCurrent: context is null"); 242 return NULL; 243 } 244 245 if (dstOps->drawableType == OGLSD_FBOBJECT) { 246 OGLContext *currentContext = OGLRenderQueue_GetCurrentContext(); 247 248 // first make sure we have a current context (if the context isn't 249 // already current to some drawable, we will make it current to 250 // its scratch surface) 251 if (oglc != currentContext) { 252 if (!GLXSD_MakeCurrentToScratch(env, oglc)) { 253 return NULL; 254 } 255 } 256 257 // now bind to the fbobject associated with the destination surface; 258 // this means that all rendering will go into the fbobject destination 259 // (note that we unbind the currently bound texture first; this is 260 // recommended procedure when binding an fbobject) 261 j2d_glBindTexture(dstOps->textureTarget, 0); 262 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dstOps->fbobjectID); 263 } else { 264 GLXSDOps *srcGLXOps = (GLXSDOps *)srcOps->privOps; 265 GLXCtxInfo *ctxinfo = (GLXCtxInfo *)oglc->ctxInfo; 266 267 // make the context current 268 if (!j2d_glXMakeContextCurrent(awt_display, 269 dstGLXOps->drawable, 270 srcGLXOps->drawable, 271 ctxinfo->context)) 272 { 273 J2dRlsTraceLn(J2D_TRACE_ERROR, 274 "OGLSD_MakeOGLContextCurrent: could not make current"); 275 return NULL; 276 } 277 278 if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) { 279 // the GL_EXT_framebuffer_object extension is present, so we 280 // must bind to the default (windowing system provided) 281 // framebuffer 282 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 283 } 284 } 285 286 return oglc; 287 } 288 289 /** 290 * This function initializes a native window surface and caches the window 291 * bounds in the given OGLSDOps. Returns JNI_TRUE if the operation was 292 * successful; JNI_FALSE otherwise. 293 */ 294 jboolean 295 OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo) 296 { 297 GLXSDOps *glxsdo; 298 Window window; 299 XWindowAttributes attr; 300 301 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_InitOGLWindow"); 302 303 if (oglsdo == NULL) { 304 J2dRlsTraceLn(J2D_TRACE_ERROR, 305 "OGLSD_InitOGLWindow: ops are null"); 306 return JNI_FALSE; 307 } 308 309 glxsdo = (GLXSDOps *)oglsdo->privOps; 310 if (glxsdo == NULL) { 311 J2dRlsTraceLn(J2D_TRACE_ERROR, 312 "OGLSD_InitOGLWindow: glx ops are null"); 313 return JNI_FALSE; 314 } 315 316 window = glxsdo->window; 317 if (window == 0) { 318 J2dRlsTraceLn(J2D_TRACE_ERROR, 319 "OGLSD_InitOGLWindow: window is invalid"); 320 return JNI_FALSE; 321 } 322 323 XGetWindowAttributes(awt_display, window, &attr); 324 oglsdo->width = attr.width; 325 oglsdo->height = attr.height; 326 327 oglsdo->drawableType = OGLSD_WINDOW; 328 oglsdo->isOpaque = JNI_TRUE; 329 oglsdo->xOffset = 0; 330 oglsdo->yOffset = 0; 331 glxsdo->drawable = window; 332 glxsdo->xdrawable = window; 333 334 J2dTraceLn2(J2D_TRACE_VERBOSE, " created window: w=%d h=%d", 335 oglsdo->width, oglsdo->height); 336 337 return JNI_TRUE; 338 } 339 340 static int 341 GLXSD_BadAllocXErrHandler(Display *display, XErrorEvent *xerr) 342 { 343 if (xerr->error_code == BadAlloc) { 344 surfaceCreationFailed = JNI_TRUE; 345 } 346 return 0; 347 } 348 349 void 350 OGLSD_SwapBuffers(JNIEnv *env, jlong window) 351 { 352 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SwapBuffers"); 353 354 if (window == 0L) { 355 J2dRlsTraceLn(J2D_TRACE_ERROR, 356 "OGLSD_SwapBuffers: window is null"); 357 return; 358 } 359 360 j2d_glXSwapBuffers(awt_display, (Window)window); 361 } 362 363 // needed by Mac OS X port, no-op on other platforms 364 void 365 OGLSD_Flush(JNIEnv *env) 366 { 367 } 368 369 #endif /* !HEADLESS */