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