Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/native/common/java2d/opengl/OGLPaints.c
41159 views
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
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
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
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
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
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
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
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
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
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
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
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
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
925