1 /*
2 * Copyright (c) 2007, 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 <jlong.h>
29 #include <string.h>
30
31 #include "sun_java2d_SunGraphics2D.h"
32 #include "sun_java2d_pipe_BufferedPaints.h"
33
34 #include "OGLPaints.h"
35 #include "OGLContext.h"
36 #include "OGLRenderQueue.h"
37 #include "OGLSurfaceData.h"
38
39 void
OGLPaints_ResetPaint(OGLContext * oglc)40 OGLPaints_ResetPaint(OGLContext *oglc)
41 {
42 jubyte ea;
43
44 J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_ResetPaint");
45
46 RETURN_IF_NULL(oglc);
47 J2dTraceLn1(J2D_TRACE_VERBOSE, " state=%d", oglc->paintState);
48 RESET_PREVIOUS_OP();
49
50 if (oglc->useMask) {
51 // switch to texture unit 1, where paint state is currently enabled
52 j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
53 }
54
55 switch (oglc->paintState) {
56 case sun_java2d_SunGraphics2D_PAINT_GRADIENT:
57 j2d_glDisable(GL_TEXTURE_1D);
58 j2d_glDisable(GL_TEXTURE_GEN_S);
59 break;
60
61 case sun_java2d_SunGraphics2D_PAINT_TEXTURE:
62 // Note: The texture object used in SetTexturePaint() will
63 // still be bound at this point, so it is safe to call the following.
64 OGLSD_RESET_TEXTURE_WRAP(GL_TEXTURE_2D);
65 j2d_glDisable(GL_TEXTURE_2D);
66 j2d_glDisable(GL_TEXTURE_GEN_S);
67 j2d_glDisable(GL_TEXTURE_GEN_T);
68 break;
69
70 case sun_java2d_SunGraphics2D_PAINT_LIN_GRADIENT:
71 case sun_java2d_SunGraphics2D_PAINT_RAD_GRADIENT:
72 j2d_glUseProgramObjectARB(0);
73 j2d_glDisable(GL_TEXTURE_1D);
74 break;
75
76 case sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR:
77 default:
78 break;
79 }
80
81 if (oglc->useMask) {
82 // restore control to texture unit 0
83 j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
84 }
85
86 // set each component of the current color state to the extra alpha
87 // value, which will effectively apply the extra alpha to each fragment
88 // in paint/texturing operations
89 ea = (jubyte)(oglc->extraAlpha * 0xff + 0.5f);
90 j2d_glColor4ub(ea, ea, ea, ea);
91 oglc->pixel = (ea << 24) | (ea << 16) | (ea << 8) | (ea << 0);
92 oglc->r = ea;
93 oglc->g = ea;
94 oglc->b = ea;
95 oglc->a = ea;
96 oglc->useMask = JNI_FALSE;
97 oglc->paintState = -1;
98 }
99
100 void
OGLPaints_SetColor(OGLContext * oglc,jint pixel)101 OGLPaints_SetColor(OGLContext *oglc, jint pixel)
102 {
103 jubyte r, g, b, a;
104
105 J2dTraceLn1(J2D_TRACE_INFO, "OGLPaints_SetColor: pixel=%08x", pixel);
106
107 RETURN_IF_NULL(oglc);
108
109 // glColor*() is allowed within glBegin()/glEnd() pairs, so
110 // no need to reset the current op state here unless the paint
111 // state really needs to be changed
112 if (oglc->paintState > sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR) {
113 OGLPaints_ResetPaint(oglc);
114 }
115
116 // store the raw (unmodified) pixel value, which may be used for
117 // special operations later
118 oglc->pixel = pixel;
119
120 if (oglc->compState != sun_java2d_SunGraphics2D_COMP_XOR) {
121 r = (jubyte)(pixel >> 16);
122 g = (jubyte)(pixel >> 8);
123 b = (jubyte)(pixel >> 0);
124 a = (jubyte)(pixel >> 24);
125
126 J2dTraceLn4(J2D_TRACE_VERBOSE,
127 " updating color: r=%02x g=%02x b=%02x a=%02x",
128 r, g, b, a);
129 } else {
130 pixel ^= oglc->xorPixel;
131
132 r = (jubyte)(pixel >> 16);
133 g = (jubyte)(pixel >> 8);
134 b = (jubyte)(pixel >> 0);
135 a = 0xff;
136
137 J2dTraceLn4(J2D_TRACE_VERBOSE,
138 " updating xor color: r=%02x g=%02x b=%02x xorpixel=%08x",
139 r, g, b, oglc->xorPixel);
140 }
141
142 j2d_glColor4ub(r, g, b, a);
143 oglc->r = r;
144 oglc->g = g;
145 oglc->b = b;
146 oglc->a = a;
147 oglc->useMask = JNI_FALSE;
148 oglc->paintState = sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR;
149 }
150
151 /************************* GradientPaint support ****************************/
152
153 static GLuint gradientTexID = 0;
154
155 static void
OGLPaints_InitGradientTexture()156 OGLPaints_InitGradientTexture()
157 {
158 GLclampf priority = 1.0f;
159
160 J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_InitGradientTexture");
161
162 j2d_glGenTextures(1, &gradientTexID);
163 j2d_glBindTexture(GL_TEXTURE_1D, gradientTexID);
164 j2d_glPrioritizeTextures(1, &gradientTexID, &priority);
165 j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
166 j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
167 j2d_glTexImage1D(GL_TEXTURE_1D, 0,
168 GL_RGBA8, 2, 0,
169 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
170 }
171
172 void
OGLPaints_SetGradientPaint(OGLContext * oglc,jboolean useMask,jboolean cyclic,jdouble p0,jdouble p1,jdouble p3,jint pixel1,jint pixel2)173 OGLPaints_SetGradientPaint(OGLContext *oglc,
174 jboolean useMask, jboolean cyclic,
175 jdouble p0, jdouble p1, jdouble p3,
176 jint pixel1, jint pixel2)
177 {
178 GLdouble texParams[4];
179 GLuint pixels[2];
180
181 J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_SetGradientPaint");
182
183 RETURN_IF_NULL(oglc);
184 OGLPaints_ResetPaint(oglc);
185
186 texParams[0] = p0;
187 texParams[1] = p1;
188 texParams[2] = 0.0;
189 texParams[3] = p3;
190
191 pixels[0] = pixel1;
192 pixels[1] = pixel2;
193
194 if (useMask) {
195 // set up the paint on texture unit 1 (instead of the usual unit 0)
196 j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
197 j2d_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
198 } else {
199 // texture unit 0 is already active; we can use the helper macro here
200 OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE);
201 }
202
203 if (gradientTexID == 0) {
204 OGLPaints_InitGradientTexture();
205 }
206
207 j2d_glEnable(GL_TEXTURE_1D);
208 j2d_glEnable(GL_TEXTURE_GEN_S);
209 j2d_glBindTexture(GL_TEXTURE_1D, gradientTexID);
210 j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S,
211 cyclic ? GL_REPEAT : GL_CLAMP_TO_EDGE);
212 j2d_glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
213 j2d_glTexGendv(GL_S, GL_OBJECT_PLANE, texParams);
214
215 j2d_glTexSubImage1D(GL_TEXTURE_1D, 0,
216 0, 2, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixels);
217
218 if (useMask) {
219 // restore control to texture unit 0
220 j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
221 }
222
223 // oglc->pixel has been set appropriately in OGLPaints_ResetPaint()
224 oglc->useMask = useMask;
225 oglc->paintState = sun_java2d_SunGraphics2D_PAINT_GRADIENT;
226 }
227
228 /************************** TexturePaint support ****************************/
229
230 void
OGLPaints_SetTexturePaint(OGLContext * oglc,jboolean useMask,jlong pSrcOps,jboolean filter,jdouble xp0,jdouble xp1,jdouble xp3,jdouble yp0,jdouble yp1,jdouble yp3)231 OGLPaints_SetTexturePaint(OGLContext *oglc,
232 jboolean useMask,
233 jlong pSrcOps, jboolean filter,
234 jdouble xp0, jdouble xp1, jdouble xp3,
235 jdouble yp0, jdouble yp1, jdouble yp3)
236 {
237 OGLSDOps *srcOps = (OGLSDOps *)jlong_to_ptr(pSrcOps);
238 GLdouble xParams[4];
239 GLdouble yParams[4];
240 GLint hint = (filter ? GL_LINEAR : GL_NEAREST);
241
242 J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_SetTexturePaint");
243
244 RETURN_IF_NULL(srcOps);
245 RETURN_IF_NULL(oglc);
246 OGLPaints_ResetPaint(oglc);
247
248 xParams[0] = xp0;
249 xParams[1] = xp1;
250 xParams[2] = 0.0;
251 xParams[3] = xp3;
252
253 yParams[0] = yp0;
254 yParams[1] = yp1;
255 yParams[2] = 0.0;
256 yParams[3] = yp3;
257
258 /*
259 * Note that we explicitly use GL_TEXTURE_2D below rather than using
260 * srcOps->textureTarget. This is because the texture wrap mode employed
261 * here (GL_REPEAT) is not available for GL_TEXTURE_RECTANGLE_ARB targets.
262 * The setup code in OGLPaints.Texture.isPaintValid() and in
263 * OGLSurfaceData.initTexture() ensures that we only get here for
264 * GL_TEXTURE_2D targets.
265 */
266
267 if (useMask) {
268 // set up the paint on texture unit 1 (instead of the usual unit 0)
269 j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
270 j2d_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
271 } else {
272 // texture unit 0 is already active; we can use the helper macro here
273 OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE);
274 }
275
276 j2d_glEnable(GL_TEXTURE_2D);
277 j2d_glEnable(GL_TEXTURE_GEN_S);
278 j2d_glEnable(GL_TEXTURE_GEN_T);
279 j2d_glBindTexture(GL_TEXTURE_2D, srcOps->textureID);
280 OGLSD_UPDATE_TEXTURE_FILTER(srcOps, hint);
281 OGLSD_UPDATE_TEXTURE_WRAP(GL_TEXTURE_2D, GL_REPEAT);
282 j2d_glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
283 j2d_glTexGendv(GL_S, GL_OBJECT_PLANE, xParams);
284 j2d_glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
285 j2d_glTexGendv(GL_T, GL_OBJECT_PLANE, yParams);
286
287 if (useMask) {
288 // restore control to texture unit 0
289 j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
290 }
291
292 // oglc->pixel has been set appropriately in OGLPaints_ResetPaint()
293 oglc->useMask = useMask;
294 oglc->paintState = sun_java2d_SunGraphics2D_PAINT_TEXTURE;
295 }
296
297 /****************** Shared MultipleGradientPaint support ********************/
298
299 /**
300 * These constants are identical to those defined in the
301 * MultipleGradientPaint.CycleMethod enum; they are copied here for
302 * convenience (ideally we would pull them directly from the Java level,
303 * but that entails more hassle than it is worth).
304 */
305 #define CYCLE_NONE 0
306 #define CYCLE_REFLECT 1
307 #define CYCLE_REPEAT 2
308
309 /**
310 * The following constants are flags that can be bitwise-or'ed together
311 * to control how the MultipleGradientPaint shader source code is generated:
312 *
313 * MULTI_CYCLE_METHOD
314 * Placeholder for the CycleMethod enum constant.
315 *
316 * MULTI_LARGE
317 * If set, use the (slower) shader that supports a larger number of
318 * gradient colors; otherwise, use the optimized codepath. See
319 * the MAX_FRACTIONS_SMALL/LARGE constants below for more details.
320 *
321 * MULTI_USE_MASK
322 * If set, apply the alpha mask value from texture unit 0 to the
323 * final color result (only used in the MaskFill case).
324 *
325 * MULTI_LINEAR_RGB
326 * If set, convert the linear RGB result back into the sRGB color space.
327 */
328 #define MULTI_CYCLE_METHOD (3 << 0)
329 #define MULTI_LARGE (1 << 2)
330 #define MULTI_USE_MASK (1 << 3)
331 #define MULTI_LINEAR_RGB (1 << 4)
332
333 /**
334 * This value determines the size of the array of programs for each
335 * MultipleGradientPaint type. This value reflects the maximum value that
336 * can be represented by performing a bitwise-or of all the MULTI_*
337 * constants defined above.
338 */
339 #define MAX_PROGRAMS 32
340
341 /** Evaluates to true if the given bit is set on the local flags variable. */
342 #define IS_SET(flagbit) \
343 (((flags) & (flagbit)) != 0)
344
345 /** Composes the given parameters as flags into the given flags variable.*/
346 #define COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear) \
347 do { \
348 flags |= ((cycleMethod) & MULTI_CYCLE_METHOD); \
349 if (large) flags |= MULTI_LARGE; \
350 if (useMask) flags |= MULTI_USE_MASK; \
351 if (linear) flags |= MULTI_LINEAR_RGB; \
352 } while (0)
353
354 /** Extracts the CycleMethod enum value from the given flags variable. */
355 #define EXTRACT_CYCLE_METHOD(flags) \
356 ((flags) & MULTI_CYCLE_METHOD)
357
358 /**
359 * The maximum number of gradient "stops" supported by the fragment shader
360 * and related code. When the MULTI_LARGE flag is set, we will use
361 * MAX_FRACTIONS_LARGE; otherwise, we use MAX_FRACTIONS_SMALL. By having
362 * two separate values, we can have one highly optimized shader (SMALL) that
363 * supports only a few fractions/colors, and then another, less optimal
364 * shader that supports more stops.
365 */
366 #define MAX_FRACTIONS sun_java2d_pipe_BufferedPaints_MULTI_MAX_FRACTIONS
367 #define MAX_FRACTIONS_LARGE MAX_FRACTIONS
368 #define MAX_FRACTIONS_SMALL 4
369
370 /**
371 * The maximum number of gradient colors supported by all of the gradient
372 * fragment shaders. Note that this value must be a power of two, as it
373 * determines the size of the 1D texture created below. It also must be
374 * greater than or equal to MAX_FRACTIONS (there is no strict requirement
375 * that the two values be equal).
376 */
377 #define MAX_COLORS 16
378
379 /**
380 * The handle to the gradient color table texture object used by the shaders.
381 */
382 static GLuint multiGradientTexID = 0;
383
384 /**
385 * This is essentially a template of the shader source code that can be used
386 * for either LinearGradientPaint or RadialGradientPaint. It includes the
387 * structure and some variables that are common to each; the remaining
388 * code snippets (for CycleMethod, ColorSpaceType, and mask modulation)
389 * are filled in prior to compiling the shader at runtime depending on the
390 * paint parameters. See OGLPaints_CreateMultiGradProgram() for more details.
391 */
392 static const char *multiGradientShaderSource =
393 // gradient texture size (in texels)
394 "const int TEXTURE_SIZE = %d;"
395 // maximum number of fractions/colors supported by this shader
396 "const int MAX_FRACTIONS = %d;"
397 // size of a single texel
398 "const float FULL_TEXEL = (1.0 / float(TEXTURE_SIZE));"
399 // size of half of a single texel
400 "const float HALF_TEXEL = (FULL_TEXEL / 2.0);"
401 // texture containing the gradient colors
402 "uniform sampler1D colors;"
403 // array of gradient stops/fractions
404 "uniform float fractions[MAX_FRACTIONS];"
405 // array of scale factors (one for each interval)
406 "uniform float scaleFactors[MAX_FRACTIONS-1];"
407 // (placeholder for mask variable)
408 "%s"
409 // (placeholder for Linear/RadialGP-specific variables)
410 "%s"
411 ""
412 "void main(void)"
413 "{"
414 " float dist;"
415 // (placeholder for Linear/RadialGradientPaint-specific code)
416 " %s"
417 ""
418 " float tc;"
419 // (placeholder for CycleMethod-specific code)
420 " %s"
421 ""
422 // calculate interpolated color
423 " vec4 result = texture1D(colors, tc);"
424 ""
425 // (placeholder for ColorSpace conversion code)
426 " %s"
427 ""
428 // (placeholder for mask modulation code)
429 " %s"
430 ""
431 // modulate with gl_Color in order to apply extra alpha
432 " gl_FragColor = result * gl_Color;"
433 "}";
434
435 /**
436 * This code takes a "dist" value as input (as calculated earlier by the
437 * LGP/RGP-specific code) in the range [0,1] and produces a texture
438 * coordinate value "tc" that represents the position of the chosen color
439 * in the one-dimensional gradient texture (also in the range [0,1]).
440 *
441 * One naive way to implement this would be to iterate through the fractions
442 * to figure out in which interval "dist" falls, and then compute the
443 * relative distance between the two nearest stops. This approach would
444 * require an "if" check on every iteration, and it is best to avoid
445 * conditionals in fragment shaders for performance reasons. Also, one might
446 * be tempted to use a break statement to jump out of the loop once the
447 * interval was found, but break statements (and non-constant loop bounds)
448 * are not natively available on most graphics hardware today, so that is
449 * a non-starter.
450 *
451 * The more optimal approach used here avoids these issues entirely by using
452 * an accumulation function that is equivalent to the process described above.
453 * The scaleFactors array is pre-initialized at enable time as follows:
454 * scaleFactors[i] = 1.0 / (fractions[i+1] - fractions[i]);
455 *
456 * For each iteration, we subtract fractions[i] from dist and then multiply
457 * that value by scaleFactors[i]. If we are within the target interval,
458 * this value will be a fraction in the range [0,1] indicating the relative
459 * distance between fraction[i] and fraction[i+1]. If we are below the
460 * target interval, this value will be negative, so we clamp it to zero
461 * to avoid accumulating any value. If we are above the target interval,
462 * the value will be greater than one, so we clamp it to one. Upon exiting
463 * the loop, we will have accumulated zero or more 1.0's and a single
464 * fractional value. This accumulated value tells us the position of the
465 * fragment color in the one-dimensional gradient texture, i.e., the
466 * texcoord called "tc".
467 */
468 static const char *texCoordCalcCode =
469 "int i;"
470 "float relFraction = 0.0;"
471 "for (i = 0; i < MAX_FRACTIONS-1; i++) {"
472 " relFraction +="
473 " clamp((dist - fractions[i]) * scaleFactors[i], 0.0, 1.0);"
474 "}"
475 // we offset by half a texel so that we find the linearly interpolated
476 // color between the two texel centers of interest
477 "tc = HALF_TEXEL + (FULL_TEXEL * relFraction);";
478
479 /** Code for NO_CYCLE that gets plugged into the CycleMethod placeholder. */
480 static const char *noCycleCode =
481 "if (dist <= 0.0) {"
482 " tc = 0.0;"
483 "} else if (dist >= 1.0) {"
484 " tc = 1.0;"
485 "} else {"
486 // (placeholder for texcoord calculation)
487 " %s"
488 "}";
489
490 /** Code for REFLECT that gets plugged into the CycleMethod placeholder. */
491 static const char *reflectCode =
492 "dist = 1.0 - (abs(fract(dist * 0.5) - 0.5) * 2.0);"
493 // (placeholder for texcoord calculation)
494 "%s";
495
496 /** Code for REPEAT that gets plugged into the CycleMethod placeholder. */
497 static const char *repeatCode =
498 "dist = fract(dist);"
499 // (placeholder for texcoord calculation)
500 "%s";
501
502 static void
OGLPaints_InitMultiGradientTexture()503 OGLPaints_InitMultiGradientTexture()
504 {
505 GLclampf priority = 1.0f;
506
507 J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_InitMultiGradientTexture");
508
509 j2d_glGenTextures(1, &multiGradientTexID);
510 j2d_glBindTexture(GL_TEXTURE_1D, multiGradientTexID);
511 j2d_glPrioritizeTextures(1, &multiGradientTexID, &priority);
512 j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
513 j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
514 j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
515 j2d_glTexImage1D(GL_TEXTURE_1D, 0,
516 GL_RGBA8, MAX_COLORS, 0,
517 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
518 }
519
520 /**
521 * Compiles and links the MultipleGradientPaint shader program. If
522 * successful, this function returns a handle to the newly created
523 * shader program; otherwise returns 0.
524 */
525 static GLhandleARB
OGLPaints_CreateMultiGradProgram(jint flags,char * paintVars,char * distCode)526 OGLPaints_CreateMultiGradProgram(jint flags,
527 char *paintVars, char *distCode)
528 {
529 GLhandleARB multiGradProgram;
530 GLint loc;
531 char *maskVars = "";
532 char *maskCode = "";
533 char *colorSpaceCode = "";
534 char cycleCode[1500];
535 char finalSource[3000];
536 jint cycleMethod = EXTRACT_CYCLE_METHOD(flags);
537 jint maxFractions = IS_SET(MULTI_LARGE) ?
538 MAX_FRACTIONS_LARGE : MAX_FRACTIONS_SMALL;
539
540 J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_CreateMultiGradProgram");
541
542 if (IS_SET(MULTI_USE_MASK)) {
543 /*
544 * This code modulates the calculated result color with the
545 * corresponding alpha value from the alpha mask texture active
546 * on texture unit 0. Only needed when useMask is true (i.e., only
547 * for MaskFill operations).
548 */
549 maskVars = "uniform sampler2D mask;";
550 maskCode = "result *= texture2D(mask, gl_TexCoord[0].st);";
551 } else {
552 /*
553 * REMIND: This is really wacky, but the gradient shaders will
554 * produce completely incorrect results on ATI hardware (at least
555 * on first-gen (R300-based) boards) if the shader program does not
556 * try to access texture coordinates by using a gl_TexCoord[*]
557 * variable. This problem really should be addressed by ATI, but
558 * in the meantime it seems we can workaround the issue by inserting
559 * a benign operation that accesses gl_TexCoord[0]. Note that we
560 * only need to do this for ATI boards and only in the !useMask case,
561 * because the useMask case already does access gl_TexCoord[1] and
562 * is therefore not affected by this driver bug.
563 */
564 const char *vendor = (const char *)j2d_glGetString(GL_VENDOR);
565 if (vendor != NULL && strncmp(vendor, "ATI", 3) == 0) {
566 maskCode = "dist = gl_TexCoord[0].s;";
567 }
568 }
569
570 if (IS_SET(MULTI_LINEAR_RGB)) {
571 /*
572 * This code converts a single pixel in linear RGB space back
573 * into sRGB (note: this code was adapted from the
574 * MultipleGradientPaintContext.convertLinearRGBtoSRGB() method).
575 */
576 colorSpaceCode =
577 "result.rgb = 1.055 * pow(result.rgb, vec3(0.416667)) - 0.055;";
578 }
579
580 if (cycleMethod == CYCLE_NONE) {
581 sprintf(cycleCode, noCycleCode, texCoordCalcCode);
582 } else if (cycleMethod == CYCLE_REFLECT) {
583 sprintf(cycleCode, reflectCode, texCoordCalcCode);
584 } else { // (cycleMethod == CYCLE_REPEAT)
585 sprintf(cycleCode, repeatCode, texCoordCalcCode);
586 }
587
588 // compose the final source code string from the various pieces
589 sprintf(finalSource, multiGradientShaderSource,
590 MAX_COLORS, maxFractions,
591 maskVars, paintVars, distCode,
592 cycleCode, colorSpaceCode, maskCode);
593
594 multiGradProgram = OGLContext_CreateFragmentProgram(finalSource);
595 if (multiGradProgram == 0) {
596 J2dRlsTraceLn(J2D_TRACE_ERROR,
597 "OGLPaints_CreateMultiGradProgram: error creating program");
598 return 0;
599 }
600
601 // "use" the program object temporarily so that we can set the uniforms
602 j2d_glUseProgramObjectARB(multiGradProgram);
603
604 // set the "uniform" texture unit bindings
605 if (IS_SET(MULTI_USE_MASK)) {
606 loc = j2d_glGetUniformLocationARB(multiGradProgram, "mask");
607 j2d_glUniform1iARB(loc, 0); // texture unit 0
608 loc = j2d_glGetUniformLocationARB(multiGradProgram, "colors");
609 j2d_glUniform1iARB(loc, 1); // texture unit 1
610 } else {
611 loc = j2d_glGetUniformLocationARB(multiGradProgram, "colors");
612 j2d_glUniform1iARB(loc, 0); // texture unit 0
613 }
614
615 // "unuse" the program object; it will be re-bound later as needed
616 j2d_glUseProgramObjectARB(0);
617
618 if (multiGradientTexID == 0) {
619 OGLPaints_InitMultiGradientTexture();
620 }
621
622 return multiGradProgram;
623 }
624
625 /**
626 * Called from the OGLPaints_SetLinear/RadialGradientPaint() methods
627 * in order to setup the fraction/color values that are common to both.
628 */
629 static void
OGLPaints_SetMultiGradientPaint(GLhandleARB multiGradProgram,jint numStops,void * pFractions,void * pPixels)630 OGLPaints_SetMultiGradientPaint(GLhandleARB multiGradProgram,
631 jint numStops,
632 void *pFractions, void *pPixels)
633 {
634 jint maxFractions = (numStops > MAX_FRACTIONS_SMALL) ?
635 MAX_FRACTIONS_LARGE : MAX_FRACTIONS_SMALL;
636 GLfloat scaleFactors[MAX_FRACTIONS-1];
637 GLfloat *fractions = (GLfloat *)pFractions;
638 GLint *pixels = (GLint *)pPixels;
639 GLint loc;
640 int i;
641
642 // enable the MultipleGradientPaint shader
643 j2d_glUseProgramObjectARB(multiGradProgram);
644
645 // update the "uniform" fraction values
646 loc = j2d_glGetUniformLocationARB(multiGradProgram, "fractions");
647 if (numStops < maxFractions) {
648 // fill the remainder of the fractions array with all zeros to
649 // prevent using garbage values from previous paints
650 GLfloat allZeros[MAX_FRACTIONS];
651 memset(allZeros, 0, sizeof(GLfloat)*MAX_FRACTIONS);
652 j2d_glUniform1fvARB(loc, maxFractions, allZeros);
653 }
654 j2d_glUniform1fvARB(loc, numStops, fractions);
655
656 // update the "uniform" scale values
657 loc = j2d_glGetUniformLocationARB(multiGradProgram, "scaleFactors");
658 for (i = 0; i < numStops-1; i++) {
659 // calculate a scale factor for each interval
660 scaleFactors[i] = 1.0f / (fractions[i+1] - fractions[i]);
661 }
662 for (; i < maxFractions-1; i++) {
663 // fill remaining scale factors with zero
664 scaleFactors[i] = 0.0f;
665 }
666 j2d_glUniform1fvARB(loc, maxFractions-1, scaleFactors);
667
668 // update the texture containing the gradient colors
669 j2d_glEnable(GL_TEXTURE_1D);
670 j2d_glBindTexture(GL_TEXTURE_1D, multiGradientTexID);
671 j2d_glTexSubImage1D(GL_TEXTURE_1D, 0,
672 0, numStops,
673 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
674 pixels);
675 if (numStops < MAX_COLORS) {
676 // when we don't have enough colors to fill the entire color gradient,
677 // we have to replicate the last color in the right-most texel for
678 // the NO_CYCLE case where the texcoord is sometimes forced to 1.0
679 j2d_glTexSubImage1D(GL_TEXTURE_1D, 0,
680 MAX_COLORS-1, 1,
681 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
682 pixels+(numStops-1));
683 }
684 }
685
686 /********************** LinearGradientPaint support *************************/
687
688 /**
689 * The handles to the LinearGradientPaint fragment program objects. The
690 * index to the array should be a bitwise-or'ing of the MULTI_* flags defined
691 * above. Note that most applications will likely need to initialize one
692 * or two of these elements, so the array is usually sparsely populated.
693 */
694 static GLhandleARB linearGradPrograms[MAX_PROGRAMS];
695
696 /**
697 * Compiles and links the LinearGradientPaint shader program. If successful,
698 * this function returns a handle to the newly created shader program;
699 * otherwise returns 0.
700 */
701 static GLhandleARB
OGLPaints_CreateLinearGradProgram(jint flags)702 OGLPaints_CreateLinearGradProgram(jint flags)
703 {
704 char *paintVars;
705 char *distCode;
706
707 J2dTraceLn1(J2D_TRACE_INFO,
708 "OGLPaints_CreateLinearGradProgram",
709 flags);
710
711 /*
712 * To simplify the code and to make it easier to upload a number of
713 * uniform values at once, we pack a bunch of scalar (float) values
714 * into vec3 values below. Here's how the values are related:
715 *
716 * params.x = p0
717 * params.y = p1
718 * params.z = p3
719 *
720 * yoff = dstOps->yOffset + dstOps->height
721 */
722 paintVars =
723 "uniform vec3 params;"
724 "uniform float yoff;";
725 distCode =
726 // note that gl_FragCoord is in window space relative to the
727 // lower-left corner, so we have to flip the y-coordinate here
728 "vec3 fragCoord = vec3(gl_FragCoord.x, yoff-gl_FragCoord.y, 1.0);"
729 "dist = dot(params, fragCoord);";
730
731 return OGLPaints_CreateMultiGradProgram(flags, paintVars, distCode);
732 }
733
734 void
OGLPaints_SetLinearGradientPaint(OGLContext * oglc,OGLSDOps * dstOps,jboolean useMask,jboolean linear,jint cycleMethod,jint numStops,jfloat p0,jfloat p1,jfloat p3,void * fractions,void * pixels)735 OGLPaints_SetLinearGradientPaint(OGLContext *oglc, OGLSDOps *dstOps,
736 jboolean useMask, jboolean linear,
737 jint cycleMethod, jint numStops,
738 jfloat p0, jfloat p1, jfloat p3,
739 void *fractions, void *pixels)
740 {
741 GLhandleARB linearGradProgram;
742 GLint loc;
743 jboolean large = (numStops > MAX_FRACTIONS_SMALL);
744 jint flags = 0;
745
746 J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_SetLinearGradientPaint");
747
748 RETURN_IF_NULL(oglc);
749 RETURN_IF_NULL(dstOps);
750 OGLPaints_ResetPaint(oglc);
751
752 COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear);
753
754 if (useMask) {
755 // set up the paint on texture unit 1 (instead of the usual unit 0)
756 j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
757 }
758 // no need to set GL_MODULATE here (it is ignored when shader is enabled)
759
760 // locate/initialize the shader program for the given flags
761 if (linearGradPrograms[flags] == 0) {
762 linearGradPrograms[flags] = OGLPaints_CreateLinearGradProgram(flags);
763 if (linearGradPrograms[flags] == 0) {
764 // shouldn't happen, but just in case...
765 return;
766 }
767 }
768 linearGradProgram = linearGradPrograms[flags];
769
770 // update the common "uniform" values (fractions and colors)
771 OGLPaints_SetMultiGradientPaint(linearGradProgram,
772 numStops, fractions, pixels);
773
774 // update the other "uniform" values
775 loc = j2d_glGetUniformLocationARB(linearGradProgram, "params");
776 j2d_glUniform3fARB(loc, p0, p1, p3);
777 loc = j2d_glGetUniformLocationARB(linearGradProgram, "yoff");
778 j2d_glUniform1fARB(loc, (GLfloat)(dstOps->yOffset + dstOps->height));
779
780 if (useMask) {
781 // restore control to texture unit 0
782 j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
783 }
784
785 // oglc->pixel has been set appropriately in OGLPaints_ResetPaint()
786 oglc->useMask = useMask;
787 oglc->paintState = sun_java2d_SunGraphics2D_PAINT_LIN_GRADIENT;
788 }
789
790 /********************** RadialGradientPaint support *************************/
791
792 /**
793 * The handles to the RadialGradientPaint fragment program objects. The
794 * index to the array should be a bitwise-or'ing of the MULTI_* flags defined
795 * above. Note that most applications will likely need to initialize one
796 * or two of these elements, so the array is usually sparsely populated.
797 */
798 static GLhandleARB radialGradPrograms[MAX_PROGRAMS];
799
800 /**
801 * Compiles and links the RadialGradientPaint shader program. If successful,
802 * this function returns a handle to the newly created shader program;
803 * otherwise returns 0.
804 */
805 static GLhandleARB
OGLPaints_CreateRadialGradProgram(jint flags)806 OGLPaints_CreateRadialGradProgram(jint flags)
807 {
808 char *paintVars;
809 char *distCode;
810
811 J2dTraceLn1(J2D_TRACE_INFO,
812 "OGLPaints_CreateRadialGradProgram",
813 flags);
814
815 /*
816 * To simplify the code and to make it easier to upload a number of
817 * uniform values at once, we pack a bunch of scalar (float) values
818 * into vec3 and vec4 values below. Here's how the values are related:
819 *
820 * m0.x = m00
821 * m0.y = m01
822 * m0.z = m02
823 *
824 * m1.x = m10
825 * m1.y = m11
826 * m1.z = m12
827 *
828 * precalc.x = focusX
829 * precalc.y = yoff = dstOps->yOffset + dstOps->height
830 * precalc.z = 1.0 - (focusX * focusX)
831 * precalc.w = 1.0 / precalc.z
832 */
833 paintVars =
834 "uniform vec3 m0;"
835 "uniform vec3 m1;"
836 "uniform vec4 precalc;";
837
838 /*
839 * The following code is derived from Daniel Rice's whitepaper on
840 * radial gradient performance (attached to the bug report for 6521533).
841 * Refer to that document as well as the setup code in the Java-level
842 * BufferedPaints.setRadialGradientPaint() method for more details.
843 */
844 distCode =
845 // note that gl_FragCoord is in window space relative to the
846 // lower-left corner, so we have to flip the y-coordinate here
847 "vec3 fragCoord ="
848 " vec3(gl_FragCoord.x, precalc.y - gl_FragCoord.y, 1.0);"
849 "float x = dot(fragCoord, m0);"
850 "float y = dot(fragCoord, m1);"
851 "float xfx = x - precalc.x;"
852 "dist = (precalc.x*xfx + sqrt(xfx*xfx + y*y*precalc.z))*precalc.w;";
853
854 return OGLPaints_CreateMultiGradProgram(flags, paintVars, distCode);
855 }
856
857 void
OGLPaints_SetRadialGradientPaint(OGLContext * oglc,OGLSDOps * dstOps,jboolean useMask,jboolean linear,jint cycleMethod,jint numStops,jfloat m00,jfloat m01,jfloat m02,jfloat m10,jfloat m11,jfloat m12,jfloat focusX,void * fractions,void * pixels)858 OGLPaints_SetRadialGradientPaint(OGLContext *oglc, OGLSDOps *dstOps,
859 jboolean useMask, jboolean linear,
860 jint cycleMethod, jint numStops,
861 jfloat m00, jfloat m01, jfloat m02,
862 jfloat m10, jfloat m11, jfloat m12,
863 jfloat focusX,
864 void *fractions, void *pixels)
865 {
866 GLhandleARB radialGradProgram;
867 GLint loc;
868 GLfloat yoff, denom, inv_denom;
869 jboolean large = (numStops > MAX_FRACTIONS_SMALL);
870 jint flags = 0;
871
872 J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_SetRadialGradientPaint");
873
874 RETURN_IF_NULL(oglc);
875 RETURN_IF_NULL(dstOps);
876 OGLPaints_ResetPaint(oglc);
877
878 COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear);
879
880 if (useMask) {
881 // set up the paint on texture unit 1 (instead of the usual unit 0)
882 j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
883 }
884 // no need to set GL_MODULATE here (it is ignored when shader is enabled)
885
886 // locate/initialize the shader program for the given flags
887 if (radialGradPrograms[flags] == 0) {
888 radialGradPrograms[flags] = OGLPaints_CreateRadialGradProgram(flags);
889 if (radialGradPrograms[flags] == 0) {
890 // shouldn't happen, but just in case...
891 return;
892 }
893 }
894 radialGradProgram = radialGradPrograms[flags];
895
896 // update the common "uniform" values (fractions and colors)
897 OGLPaints_SetMultiGradientPaint(radialGradProgram,
898 numStops, fractions, pixels);
899
900 // update the other "uniform" values
901 loc = j2d_glGetUniformLocationARB(radialGradProgram, "m0");
902 j2d_glUniform3fARB(loc, m00, m01, m02);
903 loc = j2d_glGetUniformLocationARB(radialGradProgram, "m1");
904 j2d_glUniform3fARB(loc, m10, m11, m12);
905
906 // pack a few unrelated, precalculated values into a single vec4
907 yoff = (GLfloat)(dstOps->yOffset + dstOps->height);
908 denom = 1.0f - (focusX * focusX);
909 inv_denom = 1.0f / denom;
910 loc = j2d_glGetUniformLocationARB(radialGradProgram, "precalc");
911 j2d_glUniform4fARB(loc, focusX, yoff, denom, inv_denom);
912
913 if (useMask) {
914 // restore control to texture unit 0
915 j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
916 }
917
918 // oglc->pixel has been set appropriately in OGLPaints_ResetPaint()
919 oglc->useMask = useMask;
920 oglc->paintState = sun_java2d_SunGraphics2D_PAINT_RAD_GRADIENT;
921 }
922
923 #endif /* !HEADLESS */
924