1 /*
2 * Copyright (c) 2004, 2013, 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
90 if (peer != NULL) {
91 RECT insets;
92 AwtComponent_GetInsets(env, peer, &insets);
93 oglsdo->xOffset = -insets.left;
94 oglsdo->yOffset = -insets.bottom;
95 } else {
96 oglsdo->xOffset = 0;
97 oglsdo->yOffset = 0;
98 }
99
100 wglsdo->window = (HWND)jlong_to_ptr(hwnd);
101 wglsdo->configInfo = (WGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
102 if (wglsdo->configInfo == NULL) {
103 free(wglsdo);
104 JNU_ThrowNullPointerException(env, "Config info is null in initOps");
105 }
106 }
107
108 /**
109 * This function disposes of any native windowing system resources associated
110 * with this surface. For instance, if the given OGLSDOps is of type
111 * OGLSD_PBUFFER, this method implementation will destroy the actual pbuffer
112 * surface.
113 */
114 void
115 OGLSD_DestroyOGLSurface(JNIEnv *env, OGLSDOps *oglsdo)
116 {
117 WGLSDOps *wglsdo = (WGLSDOps *)oglsdo->privOps;
118
119 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_DestroyOGLSurface");
120
121 if (oglsdo->drawableType == OGLSD_PBUFFER) {
122 if (wglsdo->pbuffer != 0) {
123 if (wglsdo->pbufferDC != 0) {
124 j2d_wglReleasePbufferDCARB(wglsdo->pbuffer,
125 wglsdo->pbufferDC);
126 wglsdo->pbufferDC = 0;
127 }
128 j2d_wglDestroyPbufferARB(wglsdo->pbuffer);
129 wglsdo->pbuffer = 0;
130 }
131 }
132 }
133
134 /**
135 * Makes the given context current to its associated "scratch" surface. If
136 * the operation is successful, this method will return JNI_TRUE; otherwise,
137 * returns JNI_FALSE.
138 */
139 static jboolean
140 WGLSD_MakeCurrentToScratch(JNIEnv *env, OGLContext *oglc)
141 {
142 WGLCtxInfo *ctxInfo;
143
144 J2dTraceLn(J2D_TRACE_INFO, "WGLSD_MakeCurrentToScratch");
145
146 if (oglc == NULL) {
147 J2dRlsTraceLn(J2D_TRACE_ERROR,
148 "WGLSD_MakeCurrentToScratch: context is null");
149 return JNI_FALSE;
150 }
151
259 // its scratch surface)
260 if (oglc != currentContext) {
261 if (!WGLSD_MakeCurrentToScratch(env, oglc)) {
262 return NULL;
263 }
264 }
265
266 // now bind to the fbobject associated with the destination surface;
267 // this means that all rendering will go into the fbobject destination
268 // (note that we unbind the currently bound texture first; this is
269 // recommended procedure when binding an fbobject)
270 j2d_glBindTexture(dstOps->textureTarget, 0);
271 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dstOps->fbobjectID);
272
273 return oglc;
274 }
275
276 ctxinfo = (WGLCtxInfo *)oglc->ctxInfo;
277
278 // get the hdc for the destination surface
279 if (dstOps->drawableType == OGLSD_PBUFFER) {
280 dstHDC = dstWGLOps->pbufferDC;
281 } else {
282 dstHDC = GetDC(dstWGLOps->window);
283 }
284
285 // get the hdc for the source surface
286 if (srcOps->drawableType == OGLSD_PBUFFER) {
287 srcHDC = srcWGLOps->pbufferDC;
288 } else {
289 // the source will always be equal to the destination in this case
290 srcHDC = dstHDC;
291 }
292
293 // REMIND: in theory we should be able to use wglMakeContextCurrentARB()
294 // even when the src/dst surfaces are the same, but this causes problems
295 // on ATI's drivers (see 6525997); for now we will only use it when the
296 // surfaces are different, otherwise we will use the old
297 // wglMakeCurrent() approach...
298 if (srcHDC != dstHDC) {
299 // use WGL_ARB_make_current_read extension to make context current
300 success =
301 j2d_wglMakeContextCurrentARB(dstHDC, srcHDC, ctxinfo->context);
302 } else {
303 // use the old approach for making current to the destination
304 success = j2d_wglMakeCurrent(dstHDC, ctxinfo->context);
305 }
306 if (!success) {
307 J2dRlsTraceLn(J2D_TRACE_ERROR,
308 "OGLSD_MakeOGLContextCurrent: could not make current");
309 if (dstOps->drawableType != OGLSD_PBUFFER) {
310 ReleaseDC(dstWGLOps->window, dstHDC);
311 }
312 return NULL;
313 }
314
315 if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) {
316 // the GL_EXT_framebuffer_object extension is present, so we
317 // must bind to the default (windowing system provided)
318 // framebuffer
319 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
320 }
321
322 if (dstOps->drawableType != OGLSD_PBUFFER) {
323 ReleaseDC(dstWGLOps->window, dstHDC);
324 }
325
326 return oglc;
327 }
328
329 /**
330 * This function initializes a native window surface and caches the window
331 * bounds in the given OGLSDOps. Returns JNI_TRUE if the operation was
332 * successful; JNI_FALSE otherwise.
333 */
334 jboolean
335 OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo)
336 {
337 PIXELFORMATDESCRIPTOR pfd;
338 WGLSDOps *wglsdo;
339 WGLGraphicsConfigInfo *wglInfo;
340 HWND window;
341 RECT wbounds;
342 HDC hdc;
343
344 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_InitOGLWindow");
383 J2dRlsTraceLn(J2D_TRACE_ERROR,
384 "OGLSD_InitOGLWindow: error setting pixel format");
385 ReleaseDC(window, hdc);
386 return JNI_FALSE;
387 }
388
389 ReleaseDC(window, hdc);
390
391 oglsdo->drawableType = OGLSD_WINDOW;
392 oglsdo->isOpaque = JNI_TRUE;
393 oglsdo->width = wbounds.right - wbounds.left;
394 oglsdo->height = wbounds.bottom - wbounds.top;
395 wglsdo->pbufferDC = 0;
396
397 J2dTraceLn2(J2D_TRACE_VERBOSE, " created window: w=%d h=%d",
398 oglsdo->width, oglsdo->height);
399
400 return JNI_TRUE;
401 }
402
403 JNIEXPORT jboolean JNICALL
404 Java_sun_java2d_opengl_WGLSurfaceData_initPbuffer
405 (JNIEnv *env, jobject wglsd,
406 jlong pData, jlong pConfigInfo,
407 jboolean isOpaque,
408 jint width, jint height)
409 {
410 int attrKeys[] = {
411 WGL_MAX_PBUFFER_WIDTH_ARB,
412 WGL_MAX_PBUFFER_HEIGHT_ARB,
413 };
414 int attrVals[2];
415 int pbAttrList[] = { 0 };
416 OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData);
417 WGLGraphicsConfigInfo *wglInfo =
418 (WGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
419 WGLSDOps *wglsdo;
420 HWND hwnd;
421 HDC hdc, pbufferDC;
422 HPBUFFERARB pbuffer;
423 int maxWidth, maxHeight;
424 int actualWidth, actualHeight;
425
426 J2dTraceLn3(J2D_TRACE_INFO,
427 "WGLSurfaceData_initPbuffer: w=%d h=%d opq=%d",
428 width, height, isOpaque);
429
430 if (oglsdo == NULL) {
431 J2dRlsTraceLn(J2D_TRACE_ERROR,
432 "WGLSurfaceData_initPbuffer: ops are null");
433 return JNI_FALSE;
434 }
435
436 wglsdo = (WGLSDOps *)oglsdo->privOps;
437 if (wglsdo == NULL) {
438 J2dRlsTraceLn(J2D_TRACE_ERROR,
439 "WGLSurfaceData_initPbuffer: wgl ops are null");
440 return JNI_FALSE;
441 }
442
443 if (wglInfo == NULL) {
444 J2dRlsTraceLn(J2D_TRACE_ERROR,
445 "WGLSurfaceData_initPbuffer: wgl config info is null");
446 return JNI_FALSE;
447 }
448
449 // create a scratch window
450 hwnd = WGLGC_CreateScratchWindow(wglInfo->screen);
451 if (hwnd == 0) {
452 J2dRlsTraceLn(J2D_TRACE_ERROR,
453 "WGLSurfaceData_initPbuffer: could not create scratch window");
454 return JNI_FALSE;
455 }
456
457 // get the HDC for the scratch window
458 hdc = GetDC(hwnd);
459 if (hdc == 0) {
460 J2dRlsTraceLn(J2D_TRACE_ERROR,
461 "WGLSurfaceData_initPbuffer: could not get dc for scratch window");
462 DestroyWindow(hwnd);
463 return JNI_FALSE;
464 }
465
466 // get the maximum allowable pbuffer dimensions
467 j2d_wglGetPixelFormatAttribivARB(hdc, wglInfo->pixfmt, 0, 2,
468 attrKeys, attrVals);
469 maxWidth = attrVals[0];
470 maxHeight = attrVals[1];
471
472 J2dTraceLn4(J2D_TRACE_VERBOSE,
473 " desired pbuffer dimensions: w=%d h=%d maxw=%d maxh=%d",
474 width, height, maxWidth, maxHeight);
475
476 // if either dimension is 0 or larger than the maximum, we cannot
477 // allocate a pbuffer with the requested dimensions
478 if (width == 0 || width > maxWidth ||
479 height == 0 || height > maxHeight)
480 {
481 J2dRlsTraceLn(J2D_TRACE_ERROR,
482 "WGLSurfaceData_initPbuffer: invalid dimensions");
483 ReleaseDC(hwnd, hdc);
484 DestroyWindow(hwnd);
485 return JNI_FALSE;
486 }
487
488 pbuffer = j2d_wglCreatePbufferARB(hdc, wglInfo->pixfmt,
489 width, height, pbAttrList);
490
491 ReleaseDC(hwnd, hdc);
492 DestroyWindow(hwnd);
493
494 if (pbuffer == 0) {
495 J2dRlsTraceLn(J2D_TRACE_ERROR,
496 "WGLSurfaceData_initPbuffer: could not create wgl pbuffer");
497 return JNI_FALSE;
498 }
499
500 // note that we get the DC for the pbuffer at creation time, and then
501 // release the DC when the pbuffer is disposed; the WGL_ARB_pbuffer
502 // spec is vague about such things, but from past experience we know
503 // this approach to be more robust than, for example, doing a
504 // Get/ReleasePbufferDC() everytime we make a context current
505 pbufferDC = j2d_wglGetPbufferDCARB(pbuffer);
506 if (pbufferDC == 0) {
507 J2dRlsTraceLn(J2D_TRACE_ERROR,
508 "WGLSurfaceData_initPbuffer: could not get dc for pbuffer");
509 j2d_wglDestroyPbufferARB(pbuffer);
510 return JNI_FALSE;
511 }
512
513 // make sure the actual dimensions match those that we requested
514 j2d_wglQueryPbufferARB(pbuffer, WGL_PBUFFER_WIDTH_ARB, &actualWidth);
515 j2d_wglQueryPbufferARB(pbuffer, WGL_PBUFFER_HEIGHT_ARB, &actualHeight);
516
517 if (width != actualWidth || height != actualHeight) {
518 J2dRlsTraceLn2(J2D_TRACE_ERROR,
519 "WGLSurfaceData_initPbuffer: actual (w=%d h=%d) != requested",
520 actualWidth, actualHeight);
521 j2d_wglReleasePbufferDCARB(pbuffer, pbufferDC);
522 j2d_wglDestroyPbufferARB(pbuffer);
523 return JNI_FALSE;
524 }
525
526 oglsdo->drawableType = OGLSD_PBUFFER;
527 oglsdo->isOpaque = isOpaque;
528 oglsdo->width = width;
529 oglsdo->height = height;
530 wglsdo->pbuffer = pbuffer;
531 wglsdo->pbufferDC = pbufferDC;
532
533 OGLSD_SetNativeDimensions(env, oglsdo, width, height);
534
535 return JNI_TRUE;
536 }
537
538 void
539 OGLSD_SwapBuffers(JNIEnv *env, jlong pPeerData)
540 {
541 HWND window;
542 HDC hdc;
543
544 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SwapBuffers");
545
546 window = AwtComponent_GetHWnd(env, pPeerData);
547 if (!IsWindow(window)) {
548 J2dRlsTraceLn(J2D_TRACE_ERROR,
549 "OGLSD_SwapBuffers: disposed component");
550 return;
551 }
552
553 hdc = GetDC(window);
554 if (hdc == 0) {
555 J2dRlsTraceLn(J2D_TRACE_ERROR,
556 "OGLSD_SwapBuffers: invalid hdc");
557 return;
|
1 /*
2 * Copyright (c) 2004, 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
90 if (peer != NULL) {
91 RECT insets;
92 AwtComponent_GetInsets(env, peer, &insets);
93 oglsdo->xOffset = -insets.left;
94 oglsdo->yOffset = -insets.bottom;
95 } else {
96 oglsdo->xOffset = 0;
97 oglsdo->yOffset = 0;
98 }
99
100 wglsdo->window = (HWND)jlong_to_ptr(hwnd);
101 wglsdo->configInfo = (WGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
102 if (wglsdo->configInfo == NULL) {
103 free(wglsdo);
104 JNU_ThrowNullPointerException(env, "Config info is null in initOps");
105 }
106 }
107
108 /**
109 * This function disposes of any native windowing system resources associated
110 * with this surface.
111 */
112 void
113 OGLSD_DestroyOGLSurface(JNIEnv *env, OGLSDOps *oglsdo)
114 {
115 // Window is free'd later by AWT code...
116 }
117
118 /**
119 * Makes the given context current to its associated "scratch" surface. If
120 * the operation is successful, this method will return JNI_TRUE; otherwise,
121 * returns JNI_FALSE.
122 */
123 static jboolean
124 WGLSD_MakeCurrentToScratch(JNIEnv *env, OGLContext *oglc)
125 {
126 WGLCtxInfo *ctxInfo;
127
128 J2dTraceLn(J2D_TRACE_INFO, "WGLSD_MakeCurrentToScratch");
129
130 if (oglc == NULL) {
131 J2dRlsTraceLn(J2D_TRACE_ERROR,
132 "WGLSD_MakeCurrentToScratch: context is null");
133 return JNI_FALSE;
134 }
135
243 // its scratch surface)
244 if (oglc != currentContext) {
245 if (!WGLSD_MakeCurrentToScratch(env, oglc)) {
246 return NULL;
247 }
248 }
249
250 // now bind to the fbobject associated with the destination surface;
251 // this means that all rendering will go into the fbobject destination
252 // (note that we unbind the currently bound texture first; this is
253 // recommended procedure when binding an fbobject)
254 j2d_glBindTexture(dstOps->textureTarget, 0);
255 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dstOps->fbobjectID);
256
257 return oglc;
258 }
259
260 ctxinfo = (WGLCtxInfo *)oglc->ctxInfo;
261
262 // get the hdc for the destination surface
263 dstHDC = GetDC(dstWGLOps->window);
264
265 // get the hdc for the source surface
266 // the source will always be equal to the destination in this case
267 srcHDC = dstHDC;
268
269 // REMIND: in theory we should be able to use wglMakeContextCurrentARB()
270 // even when the src/dst surfaces are the same, but this causes problems
271 // on ATI's drivers (see 6525997); for now we will only use it when the
272 // surfaces are different, otherwise we will use the old
273 // wglMakeCurrent() approach...
274 if (srcHDC != dstHDC) {
275 // use WGL_ARB_make_current_read extension to make context current
276 success =
277 j2d_wglMakeContextCurrentARB(dstHDC, srcHDC, ctxinfo->context);
278 } else {
279 // use the old approach for making current to the destination
280 success = j2d_wglMakeCurrent(dstHDC, ctxinfo->context);
281 }
282 if (!success) {
283 J2dRlsTraceLn(J2D_TRACE_ERROR,
284 "OGLSD_MakeOGLContextCurrent: could not make current");
285 ReleaseDC(dstWGLOps->window, dstHDC);
286 return NULL;
287 }
288
289 if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) {
290 // the GL_EXT_framebuffer_object extension is present, so we
291 // must bind to the default (windowing system provided)
292 // framebuffer
293 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
294 }
295
296 ReleaseDC(dstWGLOps->window, dstHDC);
297
298 return oglc;
299 }
300
301 /**
302 * This function initializes a native window surface and caches the window
303 * bounds in the given OGLSDOps. Returns JNI_TRUE if the operation was
304 * successful; JNI_FALSE otherwise.
305 */
306 jboolean
307 OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo)
308 {
309 PIXELFORMATDESCRIPTOR pfd;
310 WGLSDOps *wglsdo;
311 WGLGraphicsConfigInfo *wglInfo;
312 HWND window;
313 RECT wbounds;
314 HDC hdc;
315
316 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_InitOGLWindow");
355 J2dRlsTraceLn(J2D_TRACE_ERROR,
356 "OGLSD_InitOGLWindow: error setting pixel format");
357 ReleaseDC(window, hdc);
358 return JNI_FALSE;
359 }
360
361 ReleaseDC(window, hdc);
362
363 oglsdo->drawableType = OGLSD_WINDOW;
364 oglsdo->isOpaque = JNI_TRUE;
365 oglsdo->width = wbounds.right - wbounds.left;
366 oglsdo->height = wbounds.bottom - wbounds.top;
367 wglsdo->pbufferDC = 0;
368
369 J2dTraceLn2(J2D_TRACE_VERBOSE, " created window: w=%d h=%d",
370 oglsdo->width, oglsdo->height);
371
372 return JNI_TRUE;
373 }
374
375 void
376 OGLSD_SwapBuffers(JNIEnv *env, jlong pPeerData)
377 {
378 HWND window;
379 HDC hdc;
380
381 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SwapBuffers");
382
383 window = AwtComponent_GetHWnd(env, pPeerData);
384 if (!IsWindow(window)) {
385 J2dRlsTraceLn(J2D_TRACE_ERROR,
386 "OGLSD_SwapBuffers: disposed component");
387 return;
388 }
389
390 hdc = GetDC(window);
391 if (hdc == 0) {
392 J2dRlsTraceLn(J2D_TRACE_ERROR,
393 "OGLSD_SwapBuffers: invalid hdc");
394 return;
|