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 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_DestroyOGLSurface");
116 // Window is free'd later by AWT code...
117 }
118
119 /**
120 * Makes the given context current to its associated "scratch" surface. If
121 * the operation is successful, this method will return JNI_TRUE; otherwise,
122 * returns JNI_FALSE.
123 */
124 static jboolean
125 WGLSD_MakeCurrentToScratch(JNIEnv *env, OGLContext *oglc)
126 {
127 WGLCtxInfo *ctxInfo;
128
129 J2dTraceLn(J2D_TRACE_INFO, "WGLSD_MakeCurrentToScratch");
130
131 if (oglc == NULL) {
132 J2dRlsTraceLn(J2D_TRACE_ERROR,
133 "WGLSD_MakeCurrentToScratch: context is null");
134 return JNI_FALSE;
135 }
136
244 // its scratch surface)
245 if (oglc != currentContext) {
246 if (!WGLSD_MakeCurrentToScratch(env, oglc)) {
247 return NULL;
248 }
249 }
250
251 // now bind to the fbobject associated with the destination surface;
252 // this means that all rendering will go into the fbobject destination
253 // (note that we unbind the currently bound texture first; this is
254 // recommended procedure when binding an fbobject)
255 j2d_glBindTexture(dstOps->textureTarget, 0);
256 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dstOps->fbobjectID);
257
258 return oglc;
259 }
260
261 ctxinfo = (WGLCtxInfo *)oglc->ctxInfo;
262
263 // get the hdc for the destination surface
264 dstHDC = GetDC(dstWGLOps->window);
265
266 // get the hdc for the source surface
267 // the source will always be equal to the destination in this case
268 srcHDC = dstHDC;
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 ReleaseDC(dstWGLOps->window, dstHDC);
287 return NULL;
288 }
289
290 if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) {
291 // the GL_EXT_framebuffer_object extension is present, so we
292 // must bind to the default (windowing system provided)
293 // framebuffer
294 j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
295 }
296
297 ReleaseDC(dstWGLOps->window, dstHDC);
298
299 return oglc;
300 }
301
302 /**
303 * This function initializes a native window surface and caches the window
304 * bounds in the given OGLSDOps. Returns JNI_TRUE if the operation was
305 * successful; JNI_FALSE otherwise.
306 */
307 jboolean
308 OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo)
309 {
310 PIXELFORMATDESCRIPTOR pfd;
311 WGLSDOps *wglsdo;
312 WGLGraphicsConfigInfo *wglInfo;
313 HWND window;
314 RECT wbounds;
315 HDC hdc;
316
317 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_InitOGLWindow");
356 J2dRlsTraceLn(J2D_TRACE_ERROR,
357 "OGLSD_InitOGLWindow: error setting pixel format");
358 ReleaseDC(window, hdc);
359 return JNI_FALSE;
360 }
361
362 ReleaseDC(window, hdc);
363
364 oglsdo->drawableType = OGLSD_WINDOW;
365 oglsdo->isOpaque = JNI_TRUE;
366 oglsdo->width = wbounds.right - wbounds.left;
367 oglsdo->height = wbounds.bottom - wbounds.top;
368 wglsdo->pbufferDC = 0;
369
370 J2dTraceLn2(J2D_TRACE_VERBOSE, " created window: w=%d h=%d",
371 oglsdo->width, oglsdo->height);
372
373 return JNI_TRUE;
374 }
375
376 void
377 OGLSD_SwapBuffers(JNIEnv *env, jlong pPeerData)
378 {
379 HWND window;
380 HDC hdc;
381
382 J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SwapBuffers");
383
384 window = AwtComponent_GetHWnd(env, pPeerData);
385 if (!IsWindow(window)) {
386 J2dRlsTraceLn(J2D_TRACE_ERROR,
387 "OGLSD_SwapBuffers: disposed component");
388 return;
389 }
390
391 hdc = GetDC(window);
392 if (hdc == 0) {
393 J2dRlsTraceLn(J2D_TRACE_ERROR,
394 "OGLSD_SwapBuffers: invalid hdc");
395 return;
|