1 /* 2 * Copyright (c) 2003, 2019, 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 gc, 58 jobject peer, jlong aData) 59 { 60 #ifndef HEADLESS 61 gc = (*env)->NewGlobalRef(env, gc); 62 if (gc == NULL) { 63 JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed."); 64 return; 65 } 66 67 OGLSDOps *oglsdo = (OGLSDOps *)SurfaceData_InitOps(env, glxsd, 68 sizeof(OGLSDOps)); 69 if (oglsdo == NULL) { 70 (*env)->DeleteGlobalRef(env, gc); 71 JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed."); 72 return; 73 } 74 // later the graphicsConfig will be used for deallocation of oglsdo 75 oglsdo->graphicsConfig = gc; 76 77 GLXSDOps *glxsdo = (GLXSDOps *)malloc(sizeof(GLXSDOps)); 78 79 if (glxsdo == NULL) { 80 JNU_ThrowOutOfMemoryError(env, "creating native GLX ops"); 81 return; 82 } 83 84 J2dTraceLn(J2D_TRACE_INFO, "GLXSurfaceData_initOps"); 85 86 oglsdo->privOps = glxsdo; 87 88 oglsdo->sdOps.Lock = OGLSD_Lock; 89 oglsdo->sdOps.GetRasInfo = OGLSD_GetRasInfo; 90 oglsdo->sdOps.Unlock = OGLSD_Unlock; 91 oglsdo->sdOps.Dispose = OGLSD_Dispose; 92 93 oglsdo->drawableType = OGLSD_UNDEFINED; 94 oglsdo->activeBuffer = GL_FRONT; 95 oglsdo->needsInit = JNI_TRUE; 96 97 if (peer != NULL) { 98 glxsdo->window = JNU_CallMethodByName(env, NULL, peer, 99 "getContentWindow", "()J").j; 100 } else { 101 glxsdo->window = 0; 102 } 103 glxsdo->configData = (AwtGraphicsConfigDataPtr)jlong_to_ptr(aData); 104 if (glxsdo->configData == NULL) { 105 free(glxsdo); 106 JNU_ThrowNullPointerException(env, 107 "Native GraphicsConfig data block missing"); 108 return; 109 } 110 111 if (glxsdo->configData->glxInfo == NULL) { 112 free(glxsdo); 113 JNU_ThrowNullPointerException(env, "GLXGraphicsConfigInfo missing"); 114 return; 115 } 116 #endif /* HEADLESS */ 117 } 118 119 #ifndef HEADLESS 120 121 /** 122 * This function disposes of any native windowing system resources associated 123 * with this surface. 124 */ 125 void 126 OGLSD_DestroyOGLSurface(JNIEnv *env, OGLSDOps *oglsdo) 127 { 128 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_DestroyOGLSurface"); 129 // X Window is free'd later by AWT code... 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 * Makes the given GraphicsConfig's context current to its associated 166 * "scratch" surface. If there is a problem making the context current, 167 * this method will return NULL; otherwise, returns a pointer to the 168 * OGLContext that is associated with the given GraphicsConfig. 169 */ 170 OGLContext * 171 OGLSD_SetScratchSurface(JNIEnv *env, jlong pConfigInfo) 172 { 173 GLXGraphicsConfigInfo *glxInfo = 174 (GLXGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo); 175 OGLContext *oglc; 176 177 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SetScratchContext"); 178 179 if (glxInfo == NULL) { 180 J2dRlsTraceLn(J2D_TRACE_ERROR, 181 "OGLSD_SetScratchContext: glx config info is null"); 182 return NULL; 183 } 184 185 oglc = glxInfo->context; 186 if (!GLXSD_MakeCurrentToScratch(env, oglc)) { 187 return NULL; 188 } 189 190 if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) { 191 // the GL_EXT_framebuffer_object extension is present, so this call 192 // will ensure that we are bound to the scratch pbuffer (and not 193 // some other framebuffer object) 194 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 195 } 196 197 return oglc; 198 } 199 200 /** 201 * Makes a context current to the given source and destination 202 * surfaces. If there is a problem making the context current, this method 203 * will return NULL; otherwise, returns a pointer to the OGLContext that is 204 * associated with the destination surface. 205 */ 206 OGLContext * 207 OGLSD_MakeOGLContextCurrent(JNIEnv *env, OGLSDOps *srcOps, OGLSDOps *dstOps) 208 { 209 GLXSDOps *dstGLXOps = (GLXSDOps *)dstOps->privOps; 210 OGLContext *oglc; 211 212 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_MakeOGLContextCurrent"); 213 214 oglc = dstGLXOps->configData->glxInfo->context; 215 if (oglc == NULL) { 216 J2dRlsTraceLn(J2D_TRACE_ERROR, 217 "OGLSD_MakeOGLContextCurrent: context is null"); 218 return NULL; 219 } 220 221 if (dstOps->drawableType == OGLSD_FBOBJECT) { 222 OGLContext *currentContext = OGLRenderQueue_GetCurrentContext(); 223 224 // first make sure we have a current context (if the context isn't 225 // already current to some drawable, we will make it current to 226 // its scratch surface) 227 if (oglc != currentContext) { 228 if (!GLXSD_MakeCurrentToScratch(env, oglc)) { 229 return NULL; 230 } 231 } 232 233 // now bind to the fbobject associated with the destination surface; 234 // this means that all rendering will go into the fbobject destination 235 // (note that we unbind the currently bound texture first; this is 236 // recommended procedure when binding an fbobject) 237 j2d_glBindTexture(dstOps->textureTarget, 0); 238 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dstOps->fbobjectID); 239 } else { 240 GLXSDOps *srcGLXOps = (GLXSDOps *)srcOps->privOps; 241 GLXCtxInfo *ctxinfo = (GLXCtxInfo *)oglc->ctxInfo; 242 243 // make the context current 244 if (!j2d_glXMakeContextCurrent(awt_display, 245 dstGLXOps->drawable, 246 srcGLXOps->drawable, 247 ctxinfo->context)) 248 { 249 J2dRlsTraceLn(J2D_TRACE_ERROR, 250 "OGLSD_MakeOGLContextCurrent: could not make current"); 251 return NULL; 252 } 253 254 if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) { 255 // the GL_EXT_framebuffer_object extension is present, so we 256 // must bind to the default (windowing system provided) 257 // framebuffer 258 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 259 } 260 } 261 262 return oglc; 263 } 264 265 /** 266 * This function initializes a native window surface and caches the window 267 * bounds in the given OGLSDOps. Returns JNI_TRUE if the operation was 268 * successful; JNI_FALSE otherwise. 269 */ 270 jboolean 271 OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo) 272 { 273 GLXSDOps *glxsdo; 274 Window window; 275 XWindowAttributes attr; 276 277 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_InitOGLWindow"); 278 279 if (oglsdo == NULL) { 280 J2dRlsTraceLn(J2D_TRACE_ERROR, 281 "OGLSD_InitOGLWindow: ops are null"); 282 return JNI_FALSE; 283 } 284 285 glxsdo = (GLXSDOps *)oglsdo->privOps; 286 if (glxsdo == NULL) { 287 J2dRlsTraceLn(J2D_TRACE_ERROR, 288 "OGLSD_InitOGLWindow: glx ops are null"); 289 return JNI_FALSE; 290 } 291 292 window = glxsdo->window; 293 if (window == 0) { 294 J2dRlsTraceLn(J2D_TRACE_ERROR, 295 "OGLSD_InitOGLWindow: window is invalid"); 296 return JNI_FALSE; 297 } 298 299 XGetWindowAttributes(awt_display, window, &attr); 300 oglsdo->width = attr.width; 301 oglsdo->height = attr.height; 302 303 oglsdo->drawableType = OGLSD_WINDOW; 304 oglsdo->isOpaque = JNI_TRUE; 305 oglsdo->xOffset = 0; 306 oglsdo->yOffset = 0; 307 glxsdo->drawable = window; 308 glxsdo->xdrawable = window; 309 310 J2dTraceLn2(J2D_TRACE_VERBOSE, " created window: w=%d h=%d", 311 oglsdo->width, oglsdo->height); 312 313 return JNI_TRUE; 314 } 315 316 static int 317 GLXSD_BadAllocXErrHandler(Display *display, XErrorEvent *xerr) 318 { 319 if (xerr->error_code == BadAlloc) { 320 surfaceCreationFailed = JNI_TRUE; 321 } 322 return 0; 323 } 324 325 void 326 OGLSD_SwapBuffers(JNIEnv *env, jlong window) 327 { 328 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SwapBuffers"); 329 330 if (window == 0L) { 331 J2dRlsTraceLn(J2D_TRACE_ERROR, 332 "OGLSD_SwapBuffers: window is null"); 333 return; 334 } 335 336 j2d_glXSwapBuffers(awt_display, (Window)window); 337 } 338 339 // needed by Mac OS X port, no-op on other platforms 340 void 341 OGLSD_Flush(JNIEnv *env) 342 { 343 } 344 345 #endif /* !HEADLESS */