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
23 * questions.
24 */
25
26 #ifndef HEADLESS
27
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "sun_java2d_SunGraphics2D.h"
32
33 #include "jlong.h"
34 #include "jni_util.h"
35 #include "OGLContext.h"
36 #include "OGLRenderQueue.h"
37 #include "OGLSurfaceData.h"
38 #include "GraphicsPrimitiveMgr.h"
39 #include "Region.h"
40
41 #include "jvm.h"
42
43 /**
44 * The following methods are implemented in the windowing system (i.e. GLX
45 * and WGL) source files.
46 */
47 extern jboolean OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo);
48 extern OGLContext *OGLSD_MakeOGLContextCurrent(JNIEnv *env,
49 OGLSDOps *srcOps,
50 OGLSDOps *dstOps);
51
52 /**
53 * This table contains the standard blending rules (or Porter-Duff compositing
54 * factors) used in glBlendFunc(), indexed by the rule constants from the
55 * AlphaComposite class.
56 */
57 OGLBlendRule StdBlendRules[] = {
58 { GL_ZERO, GL_ZERO }, /* 0 - Nothing */
59 { GL_ZERO, GL_ZERO }, /* 1 - RULE_Clear */
60 { GL_ONE, GL_ZERO }, /* 2 - RULE_Src */
61 { GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, /* 3 - RULE_SrcOver */
62 { GL_ONE_MINUS_DST_ALPHA, GL_ONE }, /* 4 - RULE_DstOver */
63 { GL_DST_ALPHA, GL_ZERO }, /* 5 - RULE_SrcIn */
64 { GL_ZERO, GL_SRC_ALPHA }, /* 6 - RULE_DstIn */
65 { GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, /* 7 - RULE_SrcOut */
66 { GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, /* 8 - RULE_DstOut */
67 { GL_ZERO, GL_ONE }, /* 9 - RULE_Dst */
68 { GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /*10 - RULE_SrcAtop */
69 { GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, /*11 - RULE_DstAtop */
70 { GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /*12 - RULE_AlphaXor*/
71 };
72
73 /** Evaluates to "front" or "back", depending on the value of buf. */
74 #define OGLC_ACTIVE_BUFFER_NAME(buf) \
75 (buf == GL_FRONT || buf == GL_COLOR_ATTACHMENT0_EXT) ? "front" : "back"
76
77 /**
78 * Initializes the viewport and projection matrix, effectively positioning
79 * the origin at the top-left corner of the surface. This allows Java 2D
80 * coordinates to be passed directly to OpenGL, which is typically based on
81 * a bottom-right coordinate system. This method also sets the appropriate
82 * read and draw buffers.
83 */
84 static void
OGLContext_SetViewport(OGLSDOps * srcOps,OGLSDOps * dstOps)85 OGLContext_SetViewport(OGLSDOps *srcOps, OGLSDOps *dstOps)
86 {
87 jint width = dstOps->width;
88 jint height = dstOps->height;
89
90 J2dTraceLn4(J2D_TRACE_INFO,
91 "OGLContext_SetViewport: w=%d h=%d read=%s draw=%s",
92 width, height,
93 OGLC_ACTIVE_BUFFER_NAME(srcOps->activeBuffer),
94 OGLC_ACTIVE_BUFFER_NAME(dstOps->activeBuffer));
95
96 // set the viewport and projection matrix
97 j2d_glViewport(dstOps->xOffset, dstOps->yOffset,
98 (GLsizei)width, (GLsizei)height);
99 j2d_glMatrixMode(GL_PROJECTION);
100 j2d_glLoadIdentity();
101 j2d_glOrtho(0.0, (GLdouble)width, (GLdouble)height, 0.0, -1.0, 1.0);
102
103 // set the active read and draw buffers
104 j2d_glReadBuffer(srcOps->activeBuffer);
105 j2d_glDrawBuffer(dstOps->activeBuffer);
106
107 // set the color mask to enable alpha channel only when necessary
108 j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, (GLboolean)!dstOps->isOpaque);
109 }
110
111 /**
112 * Initializes the alpha channel of the current surface so that it contains
113 * fully opaque alpha values.
114 */
115 static void
OGLContext_InitAlphaChannel()116 OGLContext_InitAlphaChannel()
117 {
118 GLboolean scissorEnabled;
119
120 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_InitAlphaChannel");
121
122 // it is possible for the scissor test to be enabled at this point;
123 // if it is, disable it temporarily since it can affect the glClear() op
124 scissorEnabled = j2d_glIsEnabled(GL_SCISSOR_TEST);
125 if (scissorEnabled) {
126 j2d_glDisable(GL_SCISSOR_TEST);
127 }
128
129 // set the color mask so that we only affect the alpha channel
130 j2d_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
131
132 // clear the color buffer so that the alpha channel is fully opaque
133 j2d_glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
134 j2d_glClear(GL_COLOR_BUFFER_BIT);
135
136 // restore the color mask (as it was set in OGLContext_SetViewport())
137 j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
138
139 // re-enable scissor test, only if it was enabled earlier
140 if (scissorEnabled) {
141 j2d_glEnable(GL_SCISSOR_TEST);
142 }
143 }
144
145 /**
146 * Fetches the OGLContext associated with the given destination surface,
147 * makes the context current for those surfaces, updates the destination
148 * viewport, and then returns a pointer to the OGLContext.
149 */
150 OGLContext *
OGLContext_SetSurfaces(JNIEnv * env,jlong pSrc,jlong pDst)151 OGLContext_SetSurfaces(JNIEnv *env, jlong pSrc, jlong pDst)
152 {
153 OGLSDOps *srcOps = (OGLSDOps *)jlong_to_ptr(pSrc);
154 OGLSDOps *dstOps = (OGLSDOps *)jlong_to_ptr(pDst);
155 OGLContext *oglc = NULL;
156
157 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_SetSurfaces");
158
159 if (srcOps == NULL || dstOps == NULL) {
160 J2dRlsTraceLn(J2D_TRACE_ERROR,
161 "OGLContext_SetSurfaces: ops are null");
162 return NULL;
163 }
164
165 J2dTraceLn2(J2D_TRACE_VERBOSE, " srctype=%d dsttype=%d",
166 srcOps->drawableType, dstOps->drawableType);
167
168 if (dstOps->drawableType == OGLSD_TEXTURE) {
169 J2dRlsTraceLn(J2D_TRACE_ERROR,
170 "OGLContext_SetSurfaces: texture cannot be used as destination");
171 return NULL;
172 }
173
174 if (dstOps->drawableType == OGLSD_UNDEFINED) {
175 // initialize the surface as an OGLSD_WINDOW
176 if (!OGLSD_InitOGLWindow(env, dstOps)) {
177 J2dRlsTraceLn(J2D_TRACE_ERROR,
178 "OGLContext_SetSurfaces: could not init OGL window");
179 return NULL;
180 }
181 }
182
183 // make the context current
184 oglc = OGLSD_MakeOGLContextCurrent(env, srcOps, dstOps);
185 if (oglc == NULL) {
186 J2dRlsTraceLn(J2D_TRACE_ERROR,
187 "OGLContext_SetSurfaces: could not make context current");
188 return NULL;
189 }
190
191 // update the viewport
192 OGLContext_SetViewport(srcOps, dstOps);
193
194 // perform additional one-time initialization, if necessary
195 if (dstOps->needsInit) {
196 if (dstOps->isOpaque) {
197 // in this case we are treating the destination as opaque, but
198 // to do so, first we need to ensure that the alpha channel
199 // is filled with fully opaque values (see 6319663)
200 OGLContext_InitAlphaChannel();
201 }
202 dstOps->needsInit = JNI_FALSE;
203 }
204
205 return oglc;
206 }
207
208 /**
209 * Resets the current clip state (disables both scissor and depth tests).
210 */
211 void
OGLContext_ResetClip(OGLContext * oglc)212 OGLContext_ResetClip(OGLContext *oglc)
213 {
214 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_ResetClip");
215
216 RETURN_IF_NULL(oglc);
217 CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
218
219 j2d_glDisable(GL_SCISSOR_TEST);
220 j2d_glDisable(GL_DEPTH_TEST);
221 }
222
223 /**
224 * Sets the OpenGL scissor bounds to the provided rectangular clip bounds.
225 */
226 void
OGLContext_SetRectClip(OGLContext * oglc,OGLSDOps * dstOps,jint x1,jint y1,jint x2,jint y2)227 OGLContext_SetRectClip(OGLContext *oglc, OGLSDOps *dstOps,
228 jint x1, jint y1, jint x2, jint y2)
229 {
230 jint width = x2 - x1;
231 jint height = y2 - y1;
232
233 J2dTraceLn4(J2D_TRACE_INFO,
234 "OGLContext_SetRectClip: x=%d y=%d w=%d h=%d",
235 x1, y1, width, height);
236
237 RETURN_IF_NULL(dstOps);
238 RETURN_IF_NULL(oglc);
239 CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
240
241 if ((width < 0) || (height < 0)) {
242 // use an empty scissor rectangle when the region is empty
243 width = 0;
244 height = 0;
245 }
246
247 j2d_glDisable(GL_DEPTH_TEST);
248 j2d_glEnable(GL_SCISSOR_TEST);
249
250 // the scissor rectangle is specified using the lower-left
251 // origin of the clip region (in the framebuffer's coordinate
252 // space), so we must account for the x/y offsets of the
253 // destination surface
254 j2d_glScissor(dstOps->xOffset + x1,
255 dstOps->yOffset + dstOps->height - (y1 + height),
256 width, height);
257 }
258
259 /**
260 * Sets up a complex (shape) clip using the OpenGL depth buffer. This
261 * method prepares the depth buffer so that the clip Region spans can
262 * be "rendered" into it. The depth buffer is first cleared, then the
263 * depth func is setup so that when we render the clip spans,
264 * nothing is rendered into the color buffer, but for each pixel that would
265 * be rendered, a non-zero value is placed into that location in the depth
266 * buffer. With depth test enabled, pixels will only be rendered into the
267 * color buffer if the corresponding value at that (x,y) location in the
268 * depth buffer differs from the incoming depth value.
269 */
270 void
OGLContext_BeginShapeClip(OGLContext * oglc)271 OGLContext_BeginShapeClip(OGLContext *oglc)
272 {
273 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_BeginShapeClip");
274
275 RETURN_IF_NULL(oglc);
276 RESET_PREVIOUS_OP();
277
278 j2d_glDisable(GL_SCISSOR_TEST);
279
280 // enable depth test and clear depth buffer so that depth values are at
281 // their maximum; also set the depth func to GL_ALWAYS so that the
282 // depth values of the clip spans are forced into the depth buffer
283 j2d_glEnable(GL_DEPTH_TEST);
284 j2d_glClearDepth(1.0);
285 j2d_glClear(GL_DEPTH_BUFFER_BIT);
286 j2d_glDepthFunc(GL_ALWAYS);
287
288 // disable writes into the color buffer while we set up the clip
289 j2d_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
290
291 // save current transform
292 j2d_glMatrixMode(GL_MODELVIEW);
293 j2d_glPushMatrix();
294
295 // use identity transform plus slight translation in the z-axis when
296 // setting the clip spans; this will push the clip spans (which would
297 // normally be at z=0) to the z=1 plane to give them some depth
298 j2d_glLoadIdentity();
299 j2d_glTranslatef(0.0f, 0.0f, 1.0f);
300 }
301
302 /**
303 * Finishes setting up the shape clip by resetting the depth func
304 * so that future rendering operations will once again be written into the
305 * color buffer (while respecting the clip set up in the depth buffer).
306 */
307 void
OGLContext_EndShapeClip(OGLContext * oglc,OGLSDOps * dstOps)308 OGLContext_EndShapeClip(OGLContext *oglc, OGLSDOps *dstOps)
309 {
310 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_EndShapeClip");
311
312 RETURN_IF_NULL(dstOps);
313 RETURN_IF_NULL(oglc);
314 RESET_PREVIOUS_OP();
315
316 // restore transform
317 j2d_glPopMatrix();
318
319 // re-enable writes into the color buffer
320 j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, (GLboolean)!dstOps->isOpaque);
321
322 // enable the depth test so that only fragments within the clip region
323 // (i.e. those fragments whose z-values are >= the values currently
324 // stored in the depth buffer) are rendered
325 j2d_glDepthFunc(GL_GEQUAL);
326 }
327
328 /**
329 * Initializes the OpenGL state responsible for applying extra alpha. This
330 * step is only necessary for any operation that uses glDrawPixels() or
331 * glCopyPixels() with a non-1.0f extra alpha value. Since the source is
332 * always premultiplied, we apply the extra alpha value to both alpha and
333 * color components using GL_*_SCALE.
334 */
335 void
OGLContext_SetExtraAlpha(jfloat ea)336 OGLContext_SetExtraAlpha(jfloat ea)
337 {
338 J2dTraceLn1(J2D_TRACE_INFO, "OGLContext_SetExtraAlpha: ea=%f", ea);
339
340 j2d_glPixelTransferf(GL_ALPHA_SCALE, ea);
341 j2d_glPixelTransferf(GL_RED_SCALE, ea);
342 j2d_glPixelTransferf(GL_GREEN_SCALE, ea);
343 j2d_glPixelTransferf(GL_BLUE_SCALE, ea);
344 }
345
346 /**
347 * Resets all OpenGL compositing state (disables blending and logic
348 * operations).
349 */
350 void
OGLContext_ResetComposite(OGLContext * oglc)351 OGLContext_ResetComposite(OGLContext *oglc)
352 {
353 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_ResetComposite");
354
355 RETURN_IF_NULL(oglc);
356 CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
357
358 // disable blending and XOR mode
359 if (oglc->compState == sun_java2d_SunGraphics2D_COMP_ALPHA) {
360 j2d_glDisable(GL_BLEND);
361 } else if (oglc->compState == sun_java2d_SunGraphics2D_COMP_XOR) {
362 j2d_glDisable(GL_COLOR_LOGIC_OP);
363 j2d_glDisable(GL_ALPHA_TEST);
364 }
365
366 // set state to default values
367 oglc->compState = sun_java2d_SunGraphics2D_COMP_ISCOPY;
368 oglc->extraAlpha = 1.0f;
369 }
370
371 /**
372 * Initializes the OpenGL blending state. XOR mode is disabled and the
373 * appropriate blend functions are setup based on the AlphaComposite rule
374 * constant.
375 */
376 void
OGLContext_SetAlphaComposite(OGLContext * oglc,jint rule,jfloat extraAlpha,jint flags)377 OGLContext_SetAlphaComposite(OGLContext *oglc,
378 jint rule, jfloat extraAlpha, jint flags)
379 {
380 J2dTraceLn1(J2D_TRACE_INFO,
381 "OGLContext_SetAlphaComposite: flags=%d", flags);
382
383 RETURN_IF_NULL(oglc);
384 CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
385
386 // disable XOR mode
387 if (oglc->compState == sun_java2d_SunGraphics2D_COMP_XOR) {
388 j2d_glDisable(GL_COLOR_LOGIC_OP);
389 j2d_glDisable(GL_ALPHA_TEST);
390 }
391
392 // we can safely disable blending when:
393 // - comp is SrcNoEa or SrcOverNoEa, and
394 // - the source is opaque
395 // (turning off blending can have a large positive impact on
396 // performance)
397 if ((rule == RULE_Src || rule == RULE_SrcOver) &&
398 (extraAlpha == 1.0f) &&
399 (flags & OGLC_SRC_IS_OPAQUE))
400 {
401 J2dTraceLn1(J2D_TRACE_VERBOSE,
402 " disabling alpha comp: rule=%d ea=1.0 src=opq", rule);
403 j2d_glDisable(GL_BLEND);
404 } else {
405 J2dTraceLn2(J2D_TRACE_VERBOSE,
406 " enabling alpha comp: rule=%d ea=%f", rule, extraAlpha);
407 j2d_glEnable(GL_BLEND);
408 j2d_glBlendFunc(StdBlendRules[rule].src, StdBlendRules[rule].dst);
409 }
410
411 // update state
412 oglc->compState = sun_java2d_SunGraphics2D_COMP_ALPHA;
413 oglc->extraAlpha = extraAlpha;
414 }
415
416 /**
417 * Initializes the OpenGL logic op state to XOR mode. Blending is disabled
418 * before enabling logic op mode. The XOR pixel value will be applied
419 * later in the OGLContext_SetColor() method.
420 */
421 void
OGLContext_SetXorComposite(OGLContext * oglc,jint xorPixel)422 OGLContext_SetXorComposite(OGLContext *oglc, jint xorPixel)
423 {
424 J2dTraceLn1(J2D_TRACE_INFO,
425 "OGLContext_SetXorComposite: xorPixel=%08x", xorPixel);
426
427 RETURN_IF_NULL(oglc);
428 CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
429
430 // disable blending mode
431 if (oglc->compState == sun_java2d_SunGraphics2D_COMP_ALPHA) {
432 j2d_glDisable(GL_BLEND);
433 }
434
435 // enable XOR mode
436 j2d_glEnable(GL_COLOR_LOGIC_OP);
437 j2d_glLogicOp(GL_XOR);
438
439 // set up the alpha test so that we discard transparent fragments (this
440 // is primarily useful for rendering text in XOR mode)
441 j2d_glEnable(GL_ALPHA_TEST);
442 j2d_glAlphaFunc(GL_NOTEQUAL, 0.0f);
443
444 // update state
445 oglc->compState = sun_java2d_SunGraphics2D_COMP_XOR;
446 oglc->xorPixel = xorPixel;
447 oglc->extraAlpha = 1.0f;
448 }
449
450 /**
451 * Resets the OpenGL transform state back to the identity matrix.
452 */
453 void
OGLContext_ResetTransform(OGLContext * oglc)454 OGLContext_ResetTransform(OGLContext *oglc)
455 {
456 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_ResetTransform");
457
458 RETURN_IF_NULL(oglc);
459 CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
460
461 j2d_glMatrixMode(GL_MODELVIEW);
462 j2d_glLoadIdentity();
463 }
464
465 /**
466 * Initializes the OpenGL transform state by setting the modelview transform
467 * using the given matrix parameters.
468 *
469 * REMIND: it may be worthwhile to add serial id to AffineTransform, so we
470 * could do a quick check to see if the xform has changed since
471 * last time... a simple object compare won't suffice...
472 */
473 void
OGLContext_SetTransform(OGLContext * oglc,jdouble m00,jdouble m10,jdouble m01,jdouble m11,jdouble m02,jdouble m12)474 OGLContext_SetTransform(OGLContext *oglc,
475 jdouble m00, jdouble m10,
476 jdouble m01, jdouble m11,
477 jdouble m02, jdouble m12)
478 {
479 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_SetTransform");
480
481 RETURN_IF_NULL(oglc);
482 CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
483
484 if (oglc->xformMatrix == NULL) {
485 size_t arrsize = 16 * sizeof(GLdouble);
486 oglc->xformMatrix = (GLdouble *)malloc(arrsize);
487 memset(oglc->xformMatrix, 0, arrsize);
488 oglc->xformMatrix[10] = 1.0;
489 oglc->xformMatrix[15] = 1.0;
490 }
491
492 // copy values from AffineTransform object into native matrix array
493 oglc->xformMatrix[0] = m00;
494 oglc->xformMatrix[1] = m10;
495 oglc->xformMatrix[4] = m01;
496 oglc->xformMatrix[5] = m11;
497 oglc->xformMatrix[12] = m02;
498 oglc->xformMatrix[13] = m12;
499
500 J2dTraceLn3(J2D_TRACE_VERBOSE, " [%lf %lf %lf]",
501 oglc->xformMatrix[0], oglc->xformMatrix[4],
502 oglc->xformMatrix[12]);
503 J2dTraceLn3(J2D_TRACE_VERBOSE, " [%lf %lf %lf]",
504 oglc->xformMatrix[1], oglc->xformMatrix[5],
505 oglc->xformMatrix[13]);
506
507 j2d_glMatrixMode(GL_MODELVIEW);
508 j2d_glLoadMatrixd(oglc->xformMatrix);
509 }
510
511 /**
512 * Creates a 2D texture of the given format and dimensions and returns the
513 * texture object identifier. This method is typically used to create a
514 * temporary texture for intermediate work, such as in the
515 * OGLContext_InitBlitTileTexture() method below.
516 */
517 GLuint
OGLContext_CreateBlitTexture(GLenum internalFormat,GLenum pixelFormat,GLuint width,GLuint height)518 OGLContext_CreateBlitTexture(GLenum internalFormat, GLenum pixelFormat,
519 GLuint width, GLuint height)
520 {
521 GLuint texID;
522 GLint sp, sr, rl, align;
523 GLclampf priority = 1.0f;
524
525 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_CreateBlitTexture");
526
527 j2d_glGenTextures(1, &texID);
528 j2d_glBindTexture(GL_TEXTURE_2D, texID);
529 j2d_glPrioritizeTextures(1, &texID, &priority);
530 j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
531 j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
532 OGLSD_RESET_TEXTURE_WRAP(GL_TEXTURE_2D);
533
534 // save pixel store parameters (since this method could be invoked after
535 // the caller has already set up its pixel store parameters)
536 j2d_glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &sp);
537 j2d_glGetIntegerv(GL_UNPACK_SKIP_ROWS, &sr);
538 j2d_glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rl);
539 j2d_glGetIntegerv(GL_UNPACK_ALIGNMENT, &align);
540
541 // set pixel store parameters to default values
542 j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
543 j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
544 j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
545 j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
546
547 j2d_glTexImage2D(GL_TEXTURE_2D, 0, internalFormat,
548 width, height, 0,
549 pixelFormat, GL_UNSIGNED_BYTE, NULL);
550
551 // restore pixel store parameters
552 j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sp);
553 j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sr);
554 j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, rl);
555 j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, align);
556
557 return texID;
558 }
559
560 /**
561 * Initializes a small texture tile for use with tiled blit operations (see
562 * OGLBlitLoops.c and OGLMaskBlit.c for usage examples). The texture ID for
563 * the tile is stored in the given OGLContext. The tile is initially filled
564 * with garbage values, but the tile is updated as needed (via
565 * glTexSubImage2D()) with real RGBA values used in tiled blit situations.
566 * The internal format for the texture is GL_RGBA8, which should be sufficient
567 * for storing system memory surfaces of any known format (see PixelFormats
568 * for a list of compatible surface formats).
569 */
570 jboolean
OGLContext_InitBlitTileTexture(OGLContext * oglc)571 OGLContext_InitBlitTileTexture(OGLContext *oglc)
572 {
573 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_InitBlitTileTexture");
574
575 oglc->blitTextureID =
576 OGLContext_CreateBlitTexture(GL_RGBA8, GL_RGBA,
577 OGLC_BLIT_TILE_SIZE,
578 OGLC_BLIT_TILE_SIZE);
579
580 return JNI_TRUE;
581 }
582
583 /**
584 * Destroys the OpenGL resources associated with the given OGLContext.
585 * It is required that the native context associated with the OGLContext
586 * be made current prior to calling this method.
587 */
588 void
OGLContext_DestroyContextResources(OGLContext * oglc)589 OGLContext_DestroyContextResources(OGLContext *oglc)
590 {
591 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_DestroyContextResources");
592
593 if (oglc->xformMatrix != NULL) {
594 free(oglc->xformMatrix);
595 }
596
597 if (oglc->blitTextureID != 0) {
598 j2d_glDeleteTextures(1, &oglc->blitTextureID);
599 }
600 }
601
602 /**
603 * Returns JNI_TRUE if the given extension name is available for the current
604 * GraphicsConfig; JNI_FALSE otherwise. An extension is considered available
605 * if its identifier string is found amongst the space-delimited GL_EXTENSIONS
606 * string.
607 *
608 * Adapted from the OpenGL Red Book, pg. 506.
609 */
610 jboolean
OGLContext_IsExtensionAvailable(const char * extString,char * extName)611 OGLContext_IsExtensionAvailable(const char *extString, char *extName)
612 {
613 jboolean ret = JNI_FALSE;
614 char *p = (char *)extString;
615 char *end;
616
617 if (extString == NULL) {
618 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsExtensionAvailable");
619 J2dRlsTraceLn(J2D_TRACE_ERROR,
620 "OGLContext_IsExtensionAvailable: extension string is null");
621 return JNI_FALSE;
622 }
623
624 end = p + strlen(p);
625
626 while (p < end) {
627 size_t n = strcspn(p, " ");
628
629 if ((strlen(extName) == n) && (strncmp(extName, p, n) == 0)) {
630 ret = JNI_TRUE;
631 break;
632 }
633
634 p += (n + 1);
635 }
636
637 J2dRlsTraceLn2(J2D_TRACE_INFO,
638 "OGLContext_IsExtensionAvailable: %s=%s",
639 extName, ret ? "true" : "false");
640
641 return ret;
642 }
643
644 /**
645 * Returns JNI_TRUE only if all of the following conditions are met:
646 * - the GL_EXT_framebuffer_object extension is available
647 * - FBO support has been enabled via the system property
648 * - we can successfully create an FBO with depth capabilities
649 */
650 static jboolean
OGLContext_IsFBObjectExtensionAvailable(JNIEnv * env,const char * extString)651 OGLContext_IsFBObjectExtensionAvailable(JNIEnv *env,
652 const char *extString)
653 {
654 jboolean isFBObjectEnabled = JNI_FALSE;
655 GLuint fbobjectID, textureID, depthID;
656 jint width = 1, height = 1;
657
658 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsFBObjectExtensionAvailable");
659
660 // first see if the fbobject extension is available
661 if (!OGLContext_IsExtensionAvailable(extString,
662 "GL_EXT_framebuffer_object"))
663 {
664 return JNI_FALSE;
665 }
666
667 // next see if the depth texture extension is available
668 if (!OGLContext_IsExtensionAvailable(extString,
669 "GL_ARB_depth_texture"))
670 {
671 return JNI_FALSE;
672 }
673
674 // next see if the fbobject system property has been enabled
675 isFBObjectEnabled =
676 JNU_GetStaticFieldByName(env, NULL,
677 "sun/java2d/opengl/OGLSurfaceData",
678 "isFBObjectEnabled", "Z").z;
679 if (!isFBObjectEnabled) {
680 J2dRlsTraceLn(J2D_TRACE_INFO,
681 "OGLContext_IsFBObjectExtensionAvailable: disabled via flag");
682 return JNI_FALSE;
683 }
684
685 // finally, create a dummy fbobject with depth capabilities to see
686 // if this configuration is supported by the drivers/hardware
687 // (first we initialize a color texture object that will be used to
688 // construct the dummy fbobject)
689 j2d_glGenTextures(1, &textureID);
690 j2d_glBindTexture(GL_TEXTURE_2D, textureID);
691 j2d_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
692 width, height, 0,
693 GL_RGB, GL_UNSIGNED_BYTE, NULL);
694 j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
695 j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
696
697 // initialize framebuffer object using color texture created above
698 if (!OGLSD_InitFBObject(&fbobjectID, &depthID,
699 textureID, GL_TEXTURE_2D,
700 width, height))
701 {
702 J2dRlsTraceLn(J2D_TRACE_INFO,
703 "OGLContext_IsFBObjectExtensionAvailable: fbobject unsupported");
704 j2d_glDeleteTextures(1, &textureID);
705 return JNI_FALSE;
706 }
707
708 // delete the temporary resources
709 j2d_glDeleteTextures(1, &textureID);
710 j2d_glDeleteRenderbuffersEXT(1, &depthID);
711 j2d_glDeleteFramebuffersEXT(1, &fbobjectID);
712
713 J2dRlsTraceLn(J2D_TRACE_INFO,
714 "OGLContext_IsFBObjectExtensionAvailable: fbobject supported");
715
716 return JNI_TRUE;
717 }
718
719 /**
720 * Returns JNI_TRUE only if all of the following conditions are met:
721 * - the GL_ARB_fragment_shader extension is available
722 * - the LCD text shader codepath has been enabled via the system property
723 * - the hardware supports the minimum number of texture units
724 */
725 static jboolean
OGLContext_IsLCDShaderSupportAvailable(JNIEnv * env,jboolean fragShaderAvailable)726 OGLContext_IsLCDShaderSupportAvailable(JNIEnv *env,
727 jboolean fragShaderAvailable)
728 {
729 jboolean isLCDShaderEnabled = JNI_FALSE;
730 GLint maxTexUnits;
731
732 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsLCDShaderSupportAvailable");
733
734 // first see if the fragment shader extension is available
735 if (!fragShaderAvailable) {
736 return JNI_FALSE;
737 }
738
739 // next see if the lcdshader system property has been enabled
740 isLCDShaderEnabled =
741 JNU_GetStaticFieldByName(env, NULL,
742 "sun/java2d/opengl/OGLSurfaceData",
743 "isLCDShaderEnabled", "Z").z;
744 if (!isLCDShaderEnabled) {
745 J2dRlsTraceLn(J2D_TRACE_INFO,
746 "OGLContext_IsLCDShaderSupportAvailable: disabled via flag");
747 return JNI_FALSE;
748 }
749
750 // finally, check to see if the hardware supports the required number
751 // of texture units
752 j2d_glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &maxTexUnits);
753 if (maxTexUnits < 2) {
754 J2dRlsTraceLn1(J2D_TRACE_INFO,
755 "OGLContext_IsLCDShaderSupportAvailable: not enough tex units (%d)",
756 maxTexUnits);
757 }
758
759 J2dRlsTraceLn(J2D_TRACE_INFO,
760 "OGLContext_IsLCDShaderSupportAvailable: LCD text shader supported");
761
762 return JNI_TRUE;
763 }
764
765 /**
766 * Returns JNI_TRUE only if all of the following conditions are met:
767 * - the GL_ARB_fragment_shader extension is available
768 * - the BufferedImageOp shader codepath has been enabled via the
769 * system property
770 */
771 static jboolean
OGLContext_IsBIOpShaderSupportAvailable(JNIEnv * env,jboolean fragShaderAvailable)772 OGLContext_IsBIOpShaderSupportAvailable(JNIEnv *env,
773 jboolean fragShaderAvailable)
774 {
775 jboolean isBIOpShaderEnabled = JNI_FALSE;
776
777 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsBIOpShaderSupportAvailable");
778
779 // first see if the fragment shader extension is available
780 if (!fragShaderAvailable) {
781 return JNI_FALSE;
782 }
783
784 // next see if the biopshader system property has been enabled
785 isBIOpShaderEnabled =
786 JNU_GetStaticFieldByName(env, NULL,
787 "sun/java2d/opengl/OGLSurfaceData",
788 "isBIOpShaderEnabled", "Z").z;
789 if (!isBIOpShaderEnabled) {
790 J2dRlsTraceLn(J2D_TRACE_INFO,
791 "OGLContext_IsBIOpShaderSupportAvailable: disabled via flag");
792 return JNI_FALSE;
793 }
794
795 /*
796 * Note: In theory we should probably do some other checks here, like
797 * linking a sample shader to see if the hardware truly supports our
798 * shader programs. However, our current BufferedImageOp shaders were
799 * designed to support first-generation shader-level hardware, so the
800 * assumption is that if our shaders work on those GPUs, then they'll
801 * work on newer ones as well. Also, linking a fragment program can
802 * cost valuable CPU cycles, which is another reason to avoid these
803 * checks at startup.
804 */
805
806 J2dRlsTraceLn(J2D_TRACE_INFO,
807 "OGLContext_IsBIOpShaderSupportAvailable: BufferedImageOp shader supported");
808
809 return JNI_TRUE;
810 }
811
812 /**
813 * Returns JNI_TRUE only if all of the following conditions are met:
814 * - the GL_ARB_fragment_shader extension is available
815 * - the Linear/RadialGradientPaint shader codepath has been enabled via the
816 * system property
817 */
818 static jboolean
OGLContext_IsGradShaderSupportAvailable(JNIEnv * env,jboolean fragShaderAvailable)819 OGLContext_IsGradShaderSupportAvailable(JNIEnv *env,
820 jboolean fragShaderAvailable)
821 {
822 jboolean isGradShaderEnabled = JNI_FALSE;
823
824 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsGradShaderSupportAvailable");
825
826 // first see if the fragment shader extension is available
827 if (!fragShaderAvailable) {
828 return JNI_FALSE;
829 }
830
831 // next see if the gradshader system property has been enabled
832 isGradShaderEnabled =
833 JNU_GetStaticFieldByName(env, NULL,
834 "sun/java2d/opengl/OGLSurfaceData",
835 "isGradShaderEnabled", "Z").z;
836 if (!isGradShaderEnabled) {
837 J2dRlsTraceLn(J2D_TRACE_INFO,
838 "OGLContext_IsGradShaderSupportAvailable: disabled via flag");
839 return JNI_FALSE;
840 }
841
842 J2dRlsTraceLn(J2D_TRACE_INFO,
843 "OGLContext_IsGradShaderSupportAvailable: Linear/RadialGradientPaint shader supported");
844
845 return JNI_TRUE;
846 }
847
848 /**
849 * Checks for the presence of the optional extensions used by
850 * the Java 2D OpenGL pipeline. The given caps bitfield is updated
851 * to reflect the availability of these extensions.
852 */
853 void
OGLContext_GetExtensionInfo(JNIEnv * env,jint * caps)854 OGLContext_GetExtensionInfo(JNIEnv *env, jint *caps)
855 {
856 jint vcap = OGLC_VENDOR_OTHER;
857 const char *vendor = (char *)j2d_glGetString(GL_VENDOR);
858 const char *e = (char *)j2d_glGetString(GL_EXTENSIONS);
859 jboolean fragShaderAvail =
860 OGLContext_IsExtensionAvailable(e, "GL_ARB_fragment_shader");
861
862 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_GetExtensionInfo");
863
864 *caps |= CAPS_TEXNONSQUARE;
865 if (OGLContext_IsExtensionAvailable(e, "GL_ARB_multitexture")) {
866 *caps |= CAPS_MULTITEXTURE;
867 }
868 if (OGLContext_IsExtensionAvailable(e, "GL_ARB_texture_non_power_of_two")){
869 *caps |= CAPS_TEXNONPOW2;
870 }
871 // 6656574: Use of the GL_ARB_texture_rectangle extension by Java 2D
872 // complicates any third-party libraries that try to interact with
873 // the OGL pipeline (and we've run into driver bugs in the past related
874 // to this extension), so for now we will disable its use by default (unless
875 // forced). We will still make use of the GL_ARB_texture_non_power_of_two
876 // extension when available, which is the better choice going forward
877 // anyway.
878 if (OGLContext_IsExtensionAvailable(e, "GL_ARB_texture_rectangle") &&
879 getenv("J2D_OGL_TEXRECT") != NULL)
880 {
881 *caps |= CAPS_EXT_TEXRECT;
882 }
883 if (OGLContext_IsFBObjectExtensionAvailable(env, e)) {
884 *caps |= CAPS_EXT_FBOBJECT;
885 }
886 if (OGLContext_IsLCDShaderSupportAvailable(env, fragShaderAvail)) {
887 *caps |= CAPS_EXT_LCD_SHADER | CAPS_PS20;
888 }
889 if (OGLContext_IsBIOpShaderSupportAvailable(env, fragShaderAvail)) {
890 *caps |= CAPS_EXT_BIOP_SHADER | CAPS_PS20;
891 }
892 if (OGLContext_IsGradShaderSupportAvailable(env, fragShaderAvail)) {
893 *caps |= CAPS_EXT_GRAD_SHADER | CAPS_PS20;
894 }
895 if (OGLContext_IsExtensionAvailable(e, "GL_NV_fragment_program")) {
896 // this is an Nvidia board, at least PS 2.0, but we can't
897 // use the "max instructions" heuristic since GeForce FX
898 // boards report 1024 even though they're only PS 2.0,
899 // so we'll check the following, which does imply PS 3.0
900 if (OGLContext_IsExtensionAvailable(e, "GL_NV_fragment_program2")) {
901 *caps |= CAPS_PS30;
902 }
903 } else {
904 // for all other boards, we look at the "max instructions"
905 // count reported by the GL_ARB_fragment_program extension
906 // as a heuristic for detecting PS 3.0 compatible hardware
907 if (OGLContext_IsExtensionAvailable(e, "GL_ARB_fragment_program")) {
908 GLint instr;
909 j2d_glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
910 GL_MAX_PROGRAM_INSTRUCTIONS_ARB, &instr);
911 if (instr > 512) {
912 *caps |= CAPS_PS30;
913 }
914 }
915 }
916 if (OGLContext_IsExtensionAvailable(e, "GL_NV_texture_barrier")) {
917 *caps |= CAPS_EXT_TEXBARRIER;
918 }
919
920 // stuff vendor descriptor in the upper bits of the caps
921 if (vendor != NULL) {
922 if (strncmp(vendor, "ATI", 3) == 0) {
923 vcap = OGLC_VENDOR_ATI;
924 } else if (strncmp(vendor, "NVIDIA", 6) == 0) {
925 vcap = OGLC_VENDOR_NVIDIA;
926 } else if (strncmp(vendor, "Intel", 5) == 0) {
927 vcap = OGLC_VENDOR_INTEL;
928 }
929 // REMIND: new in 7 - check if needs fixing
930 *caps |= ((vcap & OGLC_VCAP_MASK) << OGLC_VCAP_OFFSET);
931 }
932
933 }
934
935 /**
936 * Returns JNI_TRUE if the given GL_VERSION string meets the minimum
937 * requirements (>= 1.2); JNI_FALSE otherwise.
938 */
939 jboolean
OGLContext_IsVersionSupported(const unsigned char * versionstr)940 OGLContext_IsVersionSupported(const unsigned char *versionstr)
941 {
942 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsVersionSupported");
943
944 if (versionstr == NULL) {
945 J2dRlsTraceLn(J2D_TRACE_ERROR,
946 "OGLContext_IsVersionSupported: version string is null");
947 return JNI_FALSE;
948 }
949
950 // note that this check allows for OpenGL 2.x
951 return ((versionstr[0] == '1' && versionstr[2] >= '2') ||
952 (versionstr[0] >= '2'));
953 }
954
955 /**
956 * Compiles and links the given fragment shader program. If
957 * successful, this function returns a handle to the newly created shader
958 * program; otherwise returns 0.
959 */
960 GLhandleARB
OGLContext_CreateFragmentProgram(const char * fragmentShaderSource)961 OGLContext_CreateFragmentProgram(const char *fragmentShaderSource)
962 {
963 GLhandleARB fragmentShader, fragmentProgram;
964 GLint success;
965 int infoLogLength = 0;
966
967 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_CreateFragmentProgram");
968
969 // create the shader object and compile the shader source code
970 fragmentShader = j2d_glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
971 j2d_glShaderSourceARB(fragmentShader, 1, &fragmentShaderSource, NULL);
972 j2d_glCompileShaderARB(fragmentShader);
973 j2d_glGetObjectParameterivARB(fragmentShader,
974 GL_OBJECT_COMPILE_STATUS_ARB,
975 &success);
976
977 // print the compiler messages, if necessary
978 j2d_glGetObjectParameterivARB(fragmentShader,
979 GL_OBJECT_INFO_LOG_LENGTH_ARB,
980 &infoLogLength);
981 if (infoLogLength > 1) {
982 char infoLog[1024];
983 j2d_glGetInfoLogARB(fragmentShader, 1024, NULL, infoLog);
984 J2dRlsTraceLn2(J2D_TRACE_WARNING,
985 "OGLContext_CreateFragmentProgram: compiler msg (%d):\n%s",
986 infoLogLength, infoLog);
987 }
988
989 if (!success) {
990 J2dRlsTraceLn(J2D_TRACE_ERROR,
991 "OGLContext_CreateFragmentProgram: error compiling shader");
992 j2d_glDeleteObjectARB(fragmentShader);
993 return 0;
994 }
995
996 // create the program object and attach it to the shader
997 fragmentProgram = j2d_glCreateProgramObjectARB();
998 j2d_glAttachObjectARB(fragmentProgram, fragmentShader);
999
1000 // it is now safe to delete the shader object
1001 j2d_glDeleteObjectARB(fragmentShader);
1002
1003 // link the program
1004 j2d_glLinkProgramARB(fragmentProgram);
1005 j2d_glGetObjectParameterivARB(fragmentProgram,
1006 GL_OBJECT_LINK_STATUS_ARB,
1007 &success);
1008
1009 // print the linker messages, if necessary
1010 j2d_glGetObjectParameterivARB(fragmentProgram,
1011 GL_OBJECT_INFO_LOG_LENGTH_ARB,
1012 &infoLogLength);
1013 if (infoLogLength > 1) {
1014 char infoLog[1024];
1015 j2d_glGetInfoLogARB(fragmentProgram, 1024, NULL, infoLog);
1016 J2dRlsTraceLn2(J2D_TRACE_WARNING,
1017 "OGLContext_CreateFragmentProgram: linker msg (%d):\n%s",
1018 infoLogLength, infoLog);
1019 }
1020
1021 if (!success) {
1022 J2dRlsTraceLn(J2D_TRACE_ERROR,
1023 "OGLContext_CreateFragmentProgram: error linking shader");
1024 j2d_glDeleteObjectARB(fragmentProgram);
1025 return 0;
1026 }
1027
1028 return fragmentProgram;
1029 }
1030
1031 /*
1032 * Class: sun_java2d_opengl_OGLContext
1033 * Method: getOGLIdString
1034 * Signature: ()Ljava/lang/String;
1035 */
Java_sun_java2d_opengl_OGLContext_getOGLIdString(JNIEnv * env,jclass oglcc)1036 JNIEXPORT jstring JNICALL Java_sun_java2d_opengl_OGLContext_getOGLIdString
1037 (JNIEnv *env, jclass oglcc)
1038 {
1039 char *vendor, *renderer, *version;
1040 char *pAdapterId;
1041 jobject ret = NULL;
1042 int len;
1043
1044 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_getOGLIdString");
1045
1046 vendor = (char*)j2d_glGetString(GL_VENDOR);
1047 if (vendor == NULL) {
1048 vendor = "Unknown Vendor";
1049 }
1050 renderer = (char*)j2d_glGetString(GL_RENDERER);
1051 if (renderer == NULL) {
1052 renderer = "Unknown Renderer";
1053 }
1054 version = (char*)j2d_glGetString(GL_VERSION);
1055 if (version == NULL) {
1056 version = "unknown version";
1057 }
1058
1059 // 'vendor renderer (version)0'
1060 len = strlen(vendor) + 1 + strlen(renderer) + 1 + 1+strlen(version)+1 + 1;
1061 pAdapterId = malloc(len);
1062 if (pAdapterId != NULL) {
1063
1064 jio_snprintf(pAdapterId, len, "%s %s (%s)", vendor, renderer, version);
1065
1066 J2dTraceLn1(J2D_TRACE_VERBOSE, " id=%s", pAdapterId);
1067
1068 ret = JNU_NewStringPlatform(env, pAdapterId);
1069
1070 free(pAdapterId);
1071 }
1072
1073 return ret;
1074 }
1075
1076 #endif /* !HEADLESS */
1077