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
Java_sun_java2d_opengl_GLXSurfaceData_initOps(JNIEnv * env,jobject glxsd,jobject gc,jobject peer,jlong aData)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
OGLSD_DestroyOGLSurface(JNIEnv * env,OGLSDOps * oglsdo)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
GLXSD_MakeCurrentToScratch(JNIEnv * env,OGLContext * oglc)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 *
OGLSD_SetScratchSurface(JNIEnv * env,jlong pConfigInfo)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 *
OGLSD_MakeOGLContextCurrent(JNIEnv * env,OGLSDOps * srcOps,OGLSDOps * dstOps)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
OGLSD_InitOGLWindow(JNIEnv * env,OGLSDOps * oglsdo)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
GLXSD_BadAllocXErrHandler(Display * display,XErrorEvent * xerr)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
OGLSD_SwapBuffers(JNIEnv * env,jlong window)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
OGLSD_Flush(JNIEnv * env)341 OGLSD_Flush(JNIEnv *env)
342 {
343 }
344
345 #endif /* !HEADLESS */
346