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