blob: b34872aaf7cf719e49f2bf0a9d4f3b8468198410 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2004-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 <stdlib.h>
27
28#include "sun_java2d_opengl_WGLSurfaceData.h"
29
30#include "jni.h"
31#include "jlong.h"
32#include "jni_util.h"
33#include "OGLRenderQueue.h"
34#include "WGLGraphicsConfig.h"
35#include "WGLSurfaceData.h"
36
37/**
38 * The methods in this file implement the native windowing system specific
39 * layer (WGL) for the OpenGL-based Java 2D pipeline.
40 */
41
42extern LockFunc OGLSD_Lock;
43extern GetRasInfoFunc OGLSD_GetRasInfo;
44extern UnlockFunc OGLSD_Unlock;
45extern DisposeFunc OGLSD_Dispose;
46
47JNIEXPORT void JNICALL
48Java_sun_java2d_opengl_WGLSurfaceData_initOps(JNIEnv *env, jobject wglsd,
49 jlong pConfigInfo,
50 jlong pPeerData,
51 jint xoff, jint yoff)
52{
53 OGLSDOps *oglsdo = (OGLSDOps *)SurfaceData_InitOps(env, wglsd,
54 sizeof(OGLSDOps));
55 WGLSDOps *wglsdo = (WGLSDOps *)malloc(sizeof(WGLSDOps));
56
57 J2dTraceLn(J2D_TRACE_INFO, "WGLSurfaceData_initOps");
58
59 if (wglsdo == NULL) {
60 JNU_ThrowOutOfMemoryError(env, "creating native wgl ops");
61 return;
62 }
63
64 oglsdo->privOps = wglsdo;
65
66 oglsdo->sdOps.Lock = OGLSD_Lock;
67 oglsdo->sdOps.GetRasInfo = OGLSD_GetRasInfo;
68 oglsdo->sdOps.Unlock = OGLSD_Unlock;
69 oglsdo->sdOps.Dispose = OGLSD_Dispose;
70
71 oglsdo->drawableType = OGLSD_UNDEFINED;
72 oglsdo->activeBuffer = GL_FRONT;
73 oglsdo->needsInit = JNI_TRUE;
74 oglsdo->xOffset = xoff;
75 oglsdo->yOffset = yoff;
76
77 wglsdo->peerData = pPeerData;
78 wglsdo->configInfo = (WGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
79 if (wglsdo->configInfo == NULL) {
80 free(wglsdo);
81 JNU_ThrowNullPointerException(env, "Config info is null in initOps");
82 }
83}
84
85/**
86 * This function disposes of any native windowing system resources associated
87 * with this surface. For instance, if the given OGLSDOps is of type
88 * OGLSD_PBUFFER, this method implementation will destroy the actual pbuffer
89 * surface.
90 */
91void
92OGLSD_DestroyOGLSurface(JNIEnv *env, OGLSDOps *oglsdo)
93{
94 WGLSDOps *wglsdo = (WGLSDOps *)oglsdo->privOps;
95
96 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_DestroyOGLSurface");
97
98 if (oglsdo->drawableType == OGLSD_PBUFFER) {
99 if (wglsdo->drawable.pbuffer != 0) {
100 if (wglsdo->pbufferDC != 0) {
101 j2d_wglReleasePbufferDCARB(wglsdo->drawable.pbuffer,
102 wglsdo->pbufferDC);
103 wglsdo->pbufferDC = 0;
104 }
105 j2d_wglDestroyPbufferARB(wglsdo->drawable.pbuffer);
106 wglsdo->drawable.pbuffer = 0;
107 }
108 }
109}
110
111/**
112 * Makes the given context current to its associated "scratch" surface. If
113 * the operation is successful, this method will return JNI_TRUE; otherwise,
114 * returns JNI_FALSE.
115 */
116static jboolean
117WGLSD_MakeCurrentToScratch(JNIEnv *env, OGLContext *oglc)
118{
119 WGLCtxInfo *ctxInfo;
120
121 J2dTraceLn(J2D_TRACE_INFO, "WGLSD_MakeCurrentToScratch");
122
123 if (oglc == NULL) {
124 J2dRlsTraceLn(J2D_TRACE_ERROR,
125 "WGLSD_MakeCurrentToScratch: context is null");
126 return JNI_FALSE;
127 }
128
129 ctxInfo = (WGLCtxInfo *)oglc->ctxInfo;
130 if (!j2d_wglMakeCurrent(ctxInfo->scratchSurfaceDC, ctxInfo->context)) {
131 J2dRlsTraceLn(J2D_TRACE_ERROR,
132 "WGLSD_MakeCurrentToScratch: could not make current");
133 return JNI_FALSE;
134 }
135
136 return JNI_TRUE;
137}
138
139/**
140 * Returns a pointer (as a jlong) to the native WGLGraphicsConfigInfo
141 * associated with the given OGLSDOps. This method can be called from
142 * shared code to retrieve the native GraphicsConfig data in a platform-
143 * independent manner.
144 */
145jlong
146OGLSD_GetNativeConfigInfo(OGLSDOps *oglsdo)
147{
148 WGLSDOps *wglsdo;
149
150 if (oglsdo == NULL) {
151 J2dRlsTraceLn(J2D_TRACE_ERROR,
152 "OGLSD_GetNativeConfigInfo: ops are null");
153 return 0L;
154 }
155
156 wglsdo = (WGLSDOps *)oglsdo->privOps;
157 if (wglsdo == NULL) {
158 J2dRlsTraceLn(J2D_TRACE_ERROR,
159 "OGLSD_GetNativeConfigInfo: wgl ops are null");
160 return 0L;
161 }
162
163 return ptr_to_jlong(wglsdo->configInfo);
164}
165
166/**
167 * Makes the given GraphicsConfig's context current to its associated
168 * "scratch" surface. If there is a problem making the context current,
169 * this method will return NULL; otherwise, returns a pointer to the
170 * OGLContext that is associated with the given GraphicsConfig.
171 */
172OGLContext *
173OGLSD_SetScratchSurface(JNIEnv *env, jlong pConfigInfo)
174{
175 WGLGraphicsConfigInfo *wglInfo =
176 (WGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
177 OGLContext *oglc;
178
179 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SetScratchContext");
180
181 if (wglInfo == NULL) {
182 J2dRlsTraceLn(J2D_TRACE_ERROR,
183 "OGLSD_SetScratchContext: wgl config info is null");
184 return NULL;
185 }
186
187 oglc = wglInfo->context;
188 if (!WGLSD_MakeCurrentToScratch(env, oglc)) {
189 return NULL;
190 }
191
192 if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) {
193 // the GL_EXT_framebuffer_object extension is present, so this call
194 // will ensure that we are bound to the scratch pbuffer (and not
195 // some other framebuffer object)
196 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
197 }
198
199 return oglc;
200}
201
202/**
203 * Makes a context current to the given source and destination
204 * surfaces. If there is a problem making the context current, this method
205 * will return NULL; otherwise, returns a pointer to the OGLContext that is
206 * associated with the destination surface.
207 */
208OGLContext *
209OGLSD_MakeOGLContextCurrent(JNIEnv *env, OGLSDOps *srcOps, OGLSDOps *dstOps)
210{
211 WGLSDOps *srcWGLOps = (WGLSDOps *)srcOps->privOps;
212 WGLSDOps *dstWGLOps = (WGLSDOps *)dstOps->privOps;
213 OGLContext *oglc;
214 WGLCtxInfo *ctxinfo;
215 HDC srcHDC, dstHDC;
216 BOOL success;
217
218 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_MakeOGLContextCurrent");
219
220 J2dTraceLn4(J2D_TRACE_VERBOSE, " src: %d %p dst: %d %p",
221 srcOps->drawableType, srcOps,
222 dstOps->drawableType, dstOps);
223
224 oglc = dstWGLOps->configInfo->context;
225 if (oglc == NULL) {
226 J2dRlsTraceLn(J2D_TRACE_ERROR,
227 "OGLSD_MakeOGLContextCurrent: context is null");
228 return NULL;
229 }
230
231 if (dstOps->drawableType == OGLSD_FBOBJECT) {
232 OGLContext *currentContext = OGLRenderQueue_GetCurrentContext();
233
234 // first make sure we have a current context (if the context isn't
235 // already current to some drawable, we will make it current to
236 // its scratch surface)
237 if (oglc != currentContext) {
238 if (!WGLSD_MakeCurrentToScratch(env, oglc)) {
239 return NULL;
240 }
241 }
242
243 // now bind to the fbobject associated with the destination surface;
244 // this means that all rendering will go into the fbobject destination
245 // (note that we unbind the currently bound texture first; this is
246 // recommended procedure when binding an fbobject)
247 j2d_glBindTexture(dstOps->textureTarget, 0);
248 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dstOps->fbobjectID);
249
250 return oglc;
251 }
252
253 ctxinfo = (WGLCtxInfo *)oglc->ctxInfo;
254
255 // get the hdc for the destination surface
256 if (dstOps->drawableType == OGLSD_PBUFFER) {
257 dstHDC = dstWGLOps->pbufferDC;
258 } else {
259 dstHDC = GetDC(dstWGLOps->drawable.window);
260 }
261
262 // get the hdc for the source surface
263 if (srcOps->drawableType == OGLSD_PBUFFER) {
264 srcHDC = srcWGLOps->pbufferDC;
265 } else {
266 // the source will always be equal to the destination in this case
267 srcHDC = dstHDC;
268 }
269
270 // REMIND: in theory we should be able to use wglMakeContextCurrentARB()
271 // even when the src/dst surfaces are the same, but this causes problems
272 // on ATI's drivers (see 6525997); for now we will only use it when the
273 // surfaces are different, otherwise we will use the old
274 // wglMakeCurrent() approach...
275 if (srcHDC != dstHDC) {
276 // use WGL_ARB_make_current_read extension to make context current
277 success =
278 j2d_wglMakeContextCurrentARB(dstHDC, srcHDC, ctxinfo->context);
279 } else {
280 // use the old approach for making current to the destination
281 success = j2d_wglMakeCurrent(dstHDC, ctxinfo->context);
282 }
283 if (!success) {
284 J2dRlsTraceLn(J2D_TRACE_ERROR,
285 "OGLSD_MakeOGLContextCurrent: could not make current");
286 if (dstOps->drawableType != OGLSD_PBUFFER) {
287 ReleaseDC(dstWGLOps->drawable.window, dstHDC);
288 }
289 return NULL;
290 }
291
292 if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) {
293 // the GL_EXT_framebuffer_object extension is present, so we
294 // must bind to the default (windowing system provided)
295 // framebuffer
296 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
297 }
298
299 if (dstOps->drawableType != OGLSD_PBUFFER) {
300 ReleaseDC(dstWGLOps->drawable.window, dstHDC);
301 }
302
303 return oglc;
304}
305
306/**
307 * This function initializes a native window surface and caches the window
308 * bounds in the given OGLSDOps. Returns JNI_TRUE if the operation was
309 * successful; JNI_FALSE otherwise.
310 */
311jboolean
312OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo)
313{
314 PIXELFORMATDESCRIPTOR pfd;
315 WGLSDOps *wglsdo;
316 WGLGraphicsConfigInfo *wglInfo;
317 HWND window;
318 RECT wbounds;
319 HDC hdc;
320
321 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_InitOGLWindow");
322
323 if (oglsdo == NULL) {
324 J2dRlsTraceLn(J2D_TRACE_ERROR,
325 "OGLSD_InitOGLWindow: ops are null");
326 return JNI_FALSE;
327 }
328
329 wglsdo = (WGLSDOps *)oglsdo->privOps;
330 if (wglsdo == NULL) {
331 J2dRlsTraceLn(J2D_TRACE_ERROR,
332 "OGLSD_InitOGLWindow: wgl ops are null");
333 return JNI_FALSE;
334 }
335
336 wglInfo = wglsdo->configInfo;
337 if (wglInfo == NULL) {
338 J2dRlsTraceLn(J2D_TRACE_ERROR,
339 "OGLSD_InitOGLWindow: graphics config info is null");
340 return JNI_FALSE;
341 }
342
343 window = AwtComponent_GetHWnd(env, wglsdo->peerData);
344 if (!IsWindow(window)) {
345 J2dRlsTraceLn(J2D_TRACE_ERROR,
346 "OGLSD_InitOGLWindow: disposed component");
347 return JNI_FALSE;
348 }
349
350 GetWindowRect(window, &wbounds);
351
352 hdc = GetDC(window);
353 if (hdc == 0) {
354 J2dRlsTraceLn(J2D_TRACE_ERROR,
355 "OGLSD_InitOGLWindow: invalid hdc");
356 return JNI_FALSE;
357 }
358
359 if (!SetPixelFormat(hdc, wglInfo->pixfmt, &pfd)) {
360 J2dRlsTraceLn(J2D_TRACE_ERROR,
361 "OGLSD_InitOGLWindow: error setting pixel format");
362 ReleaseDC(window, hdc);
363 return JNI_FALSE;
364 }
365
366 ReleaseDC(window, hdc);
367
368 oglsdo->drawableType = OGLSD_WINDOW;
369 oglsdo->isOpaque = JNI_TRUE;
370 oglsdo->width = wbounds.right - wbounds.left;
371 oglsdo->height = wbounds.bottom - wbounds.top;
372 wglsdo->drawable.window = window;
373 wglsdo->pbufferDC = 0;
374
375 J2dTraceLn2(J2D_TRACE_VERBOSE, " created window: w=%d h=%d",
376 oglsdo->width, oglsdo->height);
377
378 return JNI_TRUE;
379}
380
381JNIEXPORT jboolean JNICALL
382Java_sun_java2d_opengl_WGLSurfaceData_initPbuffer
383 (JNIEnv *env, jobject wglsd,
384 jlong pData, jlong pConfigInfo,
385 jboolean isOpaque,
386 jint width, jint height)
387{
388 int attrKeys[] = {
389 WGL_MAX_PBUFFER_WIDTH_ARB,
390 WGL_MAX_PBUFFER_HEIGHT_ARB,
391 };
392 int attrVals[2];
393 int pbAttrList[] = { 0 };
394 OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData);
395 WGLGraphicsConfigInfo *wglInfo =
396 (WGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
397 WGLSDOps *wglsdo;
398 HWND hwnd;
399 HDC hdc, pbufferDC;
400 HPBUFFERARB pbuffer;
401 int maxWidth, maxHeight;
402 int actualWidth, actualHeight;
403
404 J2dTraceLn3(J2D_TRACE_INFO,
405 "WGLSurfaceData_initPbuffer: w=%d h=%d opq=%d",
406 width, height, isOpaque);
407
408 if (oglsdo == NULL) {
409 J2dRlsTraceLn(J2D_TRACE_ERROR,
410 "WGLSurfaceData_initPbuffer: ops are null");
411 return JNI_FALSE;
412 }
413
414 wglsdo = (WGLSDOps *)oglsdo->privOps;
415 if (wglsdo == NULL) {
416 J2dRlsTraceLn(J2D_TRACE_ERROR,
417 "WGLSurfaceData_initPbuffer: wgl ops are null");
418 return JNI_FALSE;
419 }
420
421 if (wglInfo == NULL) {
422 J2dRlsTraceLn(J2D_TRACE_ERROR,
423 "WGLSurfaceData_initPbuffer: wgl config info is null");
424 return JNI_FALSE;
425 }
426
427 // create a scratch window
428 hwnd = WGLGC_CreateScratchWindow(wglInfo->screen);
429 if (hwnd == 0) {
430 J2dRlsTraceLn(J2D_TRACE_ERROR,
431 "WGLSurfaceData_initPbuffer: could not create scratch window");
432 return JNI_FALSE;
433 }
434
435 // get the HDC for the scratch window
436 hdc = GetDC(hwnd);
437 if (hdc == 0) {
438 J2dRlsTraceLn(J2D_TRACE_ERROR,
439 "WGLSurfaceData_initPbuffer: could not get dc for scratch window");
440 DestroyWindow(hwnd);
441 return JNI_FALSE;
442 }
443
444 // get the maximum allowable pbuffer dimensions
445 j2d_wglGetPixelFormatAttribivARB(hdc, wglInfo->pixfmt, 0, 2,
446 attrKeys, attrVals);
447 maxWidth = attrVals[0];
448 maxHeight = attrVals[1];
449
450 J2dTraceLn4(J2D_TRACE_VERBOSE,
451 " desired pbuffer dimensions: w=%d h=%d maxw=%d maxh=%d",
452 width, height, maxWidth, maxHeight);
453
454 // if either dimension is 0 or larger than the maximum, we cannot
455 // allocate a pbuffer with the requested dimensions
456 if (width == 0 || width > maxWidth ||
457 height == 0 || height > maxHeight)
458 {
459 J2dRlsTraceLn(J2D_TRACE_ERROR,
460 "WGLSurfaceData_initPbuffer: invalid dimensions");
461 ReleaseDC(hwnd, hdc);
462 DestroyWindow(hwnd);
463 return JNI_FALSE;
464 }
465
466 pbuffer = j2d_wglCreatePbufferARB(hdc, wglInfo->pixfmt,
467 width, height, pbAttrList);
468
469 ReleaseDC(hwnd, hdc);
470 DestroyWindow(hwnd);
471
472 if (pbuffer == 0) {
473 J2dRlsTraceLn(J2D_TRACE_ERROR,
474 "WGLSurfaceData_initPbuffer: could not create wgl pbuffer");
475 return JNI_FALSE;
476 }
477
478 // note that we get the DC for the pbuffer at creation time, and then
479 // release the DC when the pbuffer is disposed; the WGL_ARB_pbuffer
480 // spec is vague about such things, but from past experience we know
481 // this approach to be more robust than, for example, doing a
482 // Get/ReleasePbufferDC() everytime we make a context current
483 pbufferDC = j2d_wglGetPbufferDCARB(pbuffer);
484 if (pbufferDC == 0) {
485 J2dRlsTraceLn(J2D_TRACE_ERROR,
486 "WGLSurfaceData_initPbuffer: could not get dc for pbuffer");
487 j2d_wglDestroyPbufferARB(pbuffer);
488 return JNI_FALSE;
489 }
490
491 // make sure the actual dimensions match those that we requested
492 j2d_wglQueryPbufferARB(pbuffer, WGL_PBUFFER_WIDTH_ARB, &actualWidth);
493 j2d_wglQueryPbufferARB(pbuffer, WGL_PBUFFER_HEIGHT_ARB, &actualHeight);
494
495 if (width != actualWidth || height != actualHeight) {
496 J2dRlsTraceLn2(J2D_TRACE_ERROR,
497 "WGLSurfaceData_initPbuffer: actual (w=%d h=%d) != requested",
498 actualWidth, actualHeight);
499 j2d_wglReleasePbufferDCARB(pbuffer, pbufferDC);
500 j2d_wglDestroyPbufferARB(pbuffer);
501 return JNI_FALSE;
502 }
503
504 oglsdo->drawableType = OGLSD_PBUFFER;
505 oglsdo->isOpaque = isOpaque;
506 oglsdo->width = width;
507 oglsdo->height = height;
508 wglsdo->drawable.pbuffer = pbuffer;
509 wglsdo->pbufferDC = pbufferDC;
510
511 return JNI_TRUE;
512}
513
514void
515OGLSD_SwapBuffers(JNIEnv *env, jlong pPeerData)
516{
517 HWND window;
518 HDC hdc;
519
520 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SwapBuffers");
521
522 window = AwtComponent_GetHWnd(env, pPeerData);
523 if (!IsWindow(window)) {
524 J2dRlsTraceLn(J2D_TRACE_ERROR,
525 "OGLSD_SwapBuffers: disposed component");
526 return;
527 }
528
529 hdc = GetDC(window);
530 if (hdc == 0) {
531 J2dRlsTraceLn(J2D_TRACE_ERROR,
532 "OGLSD_SwapBuffers: invalid hdc");
533 return;
534 }
535
536 if (!SwapBuffers(hdc)) {
537 J2dRlsTraceLn(J2D_TRACE_ERROR,
538 "OGLSD_SwapBuffers: error in SwapBuffers");
539 }
540
541 if (!ReleaseDC(window, hdc)) {
542 J2dRlsTraceLn(J2D_TRACE_ERROR,
543 "OGLSD_SwapBuffers: error while releasing dc");
544 }
545}