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 code takes a "dist" value as input (as calculated earlier by the
 386  * LGP/RGP-specific code) in the range [0,1] and produces a texture
 387  * coordinate value "tc" that represents the position of the chosen color
 388  * in the one-dimensional gradient texture (also in the range [0,1]).
 389  *
 390  * One naive way to implement this would be to iterate through the fractions
 391  * to figure out in which interval "dist" falls, and then compute the
 392  * relative distance between the two nearest stops.  This approach would
 393  * require an "if" check on every iteration, and it is best to avoid
 394  * conditionals in fragment shaders for performance reasons.  Also, one might
 395  * be tempted to use a break statement to jump out of the loop once the
 396  * interval was found, but break statements (and non-constant loop bounds)
 397  * are not natively available on most graphics hardware today, so that is
 398  * a non-starter.
 399  *
 400  * The more optimal approach used here avoids these issues entirely by using
 401  * an accumulation function that is equivalent to the process described above.
 402  * The scaleFactors array is pre-initialized at enable time as follows:
 403  *     scaleFactors[i] = 1.0 / (fractions[i+1] - fractions[i]);
 404  *
 405  * For each iteration, we subtract fractions[i] from dist and then multiply
 406  * that value by scaleFactors[i].  If we are within the target interval,
 407  * this value will be a fraction in the range [0,1] indicating the relative
 408  * distance between fraction[i] and fraction[i+1].  If we are below the
 409  * target interval, this value will be negative, so we clamp it to zero
 410  * to avoid accumulating any value.  If we are above the target interval,
 411  * the value will be greater than one, so we clamp it to one.  Upon exiting
 412  * the loop, we will have accumulated zero or more 1.0's and a single
 413  * fractional value.  This accumulated value tells us the position of the
 414  * fragment color in the one-dimensional gradient texture, i.e., the
 415  * texcoord called "tc".
 416  */
 417 static const char *texCoordCalcCode =
 418     "int i;"
 419     "float relFraction = 0.0;"
 420     "for (i = 0; i < MAX_FRACTIONS-1; i++) {"
 421     "    relFraction +="
 422     "        clamp((dist - fractions[i]) * scaleFactors[i], 0.0, 1.0);"
 423     "}"
 424     // we offset by half a texel so that we find the linearly interpolated
 425     // color between the two texel centers of interest
 426     "tc = HALF_TEXEL + (FULL_TEXEL * relFraction);";
 427 
 428 static void
 429 OGLPaints_InitMultiGradientTexture()
 430 {
 431     GLclampf priority = 1.0f;
 432 
 433     J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_InitMultiGradientTexture");
 434 
 435     j2d_glGenTextures(1, &multiGradientTexID);
 436     j2d_glBindTexture(GL_TEXTURE_1D, multiGradientTexID);
 437     j2d_glPrioritizeTextures(1, &multiGradientTexID, &priority);
 438     j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 439     j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 440     j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 441     j2d_glTexImage1D(GL_TEXTURE_1D, 0,
 442                      GL_RGBA8, MAX_COLORS, 0,
 443                      GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
 444 }
 445 
 446 /**
 447  * Compiles and links the MultipleGradientPaint shader program.  If
 448  * successful, this function returns a handle to the newly created
 449  * shader program; otherwise returns 0.
 450  */
 451 static GLhandleARB
 452 OGLPaints_CreateMultiGradProgram(jint flags,
 453                                  char *paintVars, char *distCode)
 454 {
 455     GLhandleARB multiGradProgram;
 456     GLint loc;
 457     char *maskVars = "";
 458     char *maskCode = "";
 459     char *colorSpaceCode = "";
 460     char cycleCode[1500];
 461     char finalSource[3000];
 462     jint cycleMethod = EXTRACT_CYCLE_METHOD(flags);
 463     jint maxFractions = IS_SET(MULTI_LARGE) ?
 464         MAX_FRACTIONS_LARGE : MAX_FRACTIONS_SMALL;
 465 
 466     J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_CreateMultiGradProgram");
 467 
 468     if (IS_SET(MULTI_USE_MASK)) {
 469         /*
 470          * This code modulates the calculated result color with the
 471          * corresponding alpha value from the alpha mask texture active
 472          * on texture unit 0.  Only needed when useMask is true (i.e., only
 473          * for MaskFill operations).
 474          */
 475         maskVars = "uniform sampler2D mask;";
 476         maskCode = "result *= texture2D(mask, gl_TexCoord[0].st);";
 477     } else {
 478         /*
 479          * REMIND: This is really wacky, but the gradient shaders will
 480          * produce completely incorrect results on ATI hardware (at least
 481          * on first-gen (R300-based) boards) if the shader program does not
 482          * try to access texture coordinates by using a gl_TexCoord[*]
 483          * variable.  This problem really should be addressed by ATI, but
 484          * in the meantime it seems we can workaround the issue by inserting
 485          * a benign operation that accesses gl_TexCoord[0].  Note that we
 486          * only need to do this for ATI boards and only in the !useMask case,
 487          * because the useMask case already does access gl_TexCoord[1] and
 488          * is therefore not affected by this driver bug.
 489          */
 490         const char *vendor = (const char *)j2d_glGetString(GL_VENDOR);
 491         if (vendor != NULL && strncmp(vendor, "ATI", 3) == 0) {
 492             maskCode = "dist = gl_TexCoord[0].s;";
 493         }
 494     }
 495 
 496     if (IS_SET(MULTI_LINEAR_RGB)) {
 497         /*
 498          * This code converts a single pixel in linear RGB space back
 499          * into sRGB (note: this code was adapted from the
 500          * MultipleGradientPaintContext.convertLinearRGBtoSRGB() method).
 501          */
 502         colorSpaceCode =
 503             "result.rgb = 1.055 * pow(result.rgb, vec3(0.416667)) - 0.055;";
 504     }
 505 
 506     if (cycleMethod == CYCLE_NONE) {
 507         sprintf(cycleCode,
 508     /** Code for NO_CYCLE that gets plugged into the CycleMethod placeholder. */
 509             "if (dist <= 0.0) {"
 510                 "    tc = 0.0;"
 511                 "} else if (dist >= 1.0) {"
 512                 "    tc = 1.0;"
 513                 "} else {"
 514                      // (placeholder for texcoord calculation)
 515                 "    %s", texCoordCalcCode);
 516     } else if (cycleMethod == CYCLE_REFLECT) {
 517         sprintf(cycleCode,
 518     /** Code for REFLECT that gets plugged into the CycleMethod placeholder. */
 519             "dist = 1.0 - (abs(fract(dist * 0.5) - 0.5) * 2.0);"
 520             // (placeholder for texcoord calculation)
 521             "%s", texCoordCalcCode);
 522     } else { // (cycleMethod == CYCLE_REPEAT)
 523         sprintf(cycleCode,
 524     /** Code for REPEAT that gets plugged into the CycleMethod placeholder. */
 525             "dist = fract(dist);"
 526             // (placeholder for texcoord calculation)
 527             "%s", texCoordCalcCode);
 528     }
 529 
 530     // compose the final source code string from the various pieces
 531     sprintf(finalSource,
 532 /**
 533  * This is essentially a template of the shader source code that can be used
 534  * for either LinearGradientPaint or RadialGradientPaint.  It includes the
 535  * structure and some variables that are common to each; the remaining
 536  * code snippets (for CycleMethod, ColorSpaceType, and mask modulation)
 537  * are filled in prior to compiling the shader at runtime depending on the
 538  * paint parameters.  See OGLPaints_CreateMultiGradProgram() for more details.
 539  */
 540         // gradient texture size (in texels)
 541         "const int TEXTURE_SIZE = %d;"
 542         // maximum number of fractions/colors supported by this shader
 543         "const int MAX_FRACTIONS = %d;"
 544         // size of a single texel
 545         "const float FULL_TEXEL = (1.0 / float(TEXTURE_SIZE));"
 546         // size of half of a single texel
 547         "const float HALF_TEXEL = (FULL_TEXEL / 2.0);"
 548         // texture containing the gradient colors
 549         "uniform sampler1D colors;"
 550         // array of gradient stops/fractions
 551         "uniform float fractions[MAX_FRACTIONS];"
 552         // array of scale factors (one for each interval)
 553         "uniform float scaleFactors[MAX_FRACTIONS-1];"
 554         // (placeholder for mask variable)
 555         "%s"
 556         // (placeholder for Linear/RadialGP-specific variables)
 557         "%s"
 558         ""
 559         "void main(void)"
 560         "{"
 561         "    float dist;"
 562              // (placeholder for Linear/RadialGradientPaint-specific code)
 563         "    %s"
 564         ""
 565         "    float tc;"
 566              // (placeholder for CycleMethod-specific code)
 567         "    %s"
 568         ""
 569              // calculate interpolated color
 570         "    vec4 result = texture1D(colors, tc);"
 571         ""
 572              // (placeholder for ColorSpace conversion code)
 573         "    %s"
 574         ""
 575              // (placeholder for mask modulation code)
 576         "    %s"
 577         ""
 578              // modulate with gl_Color in order to apply extra alpha
 579         "    gl_FragColor = result * gl_Color;"
 580         "}", MAX_COLORS, maxFractions,
 581             maskVars, paintVars, distCode,
 582             cycleCode, colorSpaceCode, maskCode);
 583 
 584     multiGradProgram = OGLContext_CreateFragmentProgram(finalSource);
 585     if (multiGradProgram == 0) {
 586         J2dRlsTraceLn(J2D_TRACE_ERROR,
 587             "OGLPaints_CreateMultiGradProgram: error creating program");
 588         return 0;
 589     }
 590 
 591     // "use" the program object temporarily so that we can set the uniforms
 592     j2d_glUseProgramObjectARB(multiGradProgram);
 593 
 594     // set the "uniform" texture unit bindings
 595     if (IS_SET(MULTI_USE_MASK)) {
 596         loc = j2d_glGetUniformLocationARB(multiGradProgram, "mask");
 597         j2d_glUniform1iARB(loc, 0); // texture unit 0
 598         loc = j2d_glGetUniformLocationARB(multiGradProgram, "colors");
 599         j2d_glUniform1iARB(loc, 1); // texture unit 1
 600     } else {
 601         loc = j2d_glGetUniformLocationARB(multiGradProgram, "colors");
 602         j2d_glUniform1iARB(loc, 0); // texture unit 0
 603     }
 604 
 605     // "unuse" the program object; it will be re-bound later as needed
 606     j2d_glUseProgramObjectARB(0);
 607 
 608     if (multiGradientTexID == 0) {
 609         OGLPaints_InitMultiGradientTexture();
 610     }
 611 
 612     return multiGradProgram;
 613 }
 614 
 615 /**
 616  * Called from the OGLPaints_SetLinear/RadialGradientPaint() methods
 617  * in order to setup the fraction/color values that are common to both.
 618  */
 619 static void
 620 OGLPaints_SetMultiGradientPaint(GLhandleARB multiGradProgram,
 621                                 jint numStops,
 622                                 void *pFractions, void *pPixels)
 623 {
 624     jint maxFractions = (numStops > MAX_FRACTIONS_SMALL) ?
 625         MAX_FRACTIONS_LARGE : MAX_FRACTIONS_SMALL;
 626     GLfloat scaleFactors[MAX_FRACTIONS-1];
 627     GLfloat *fractions = (GLfloat *)pFractions;
 628     GLint *pixels = (GLint *)pPixels;
 629     GLint loc;
 630     int i;
 631 
 632     // enable the MultipleGradientPaint shader
 633     j2d_glUseProgramObjectARB(multiGradProgram);
 634 
 635     // update the "uniform" fraction values
 636     loc = j2d_glGetUniformLocationARB(multiGradProgram, "fractions");
 637     if (numStops < maxFractions) {
 638         // fill the remainder of the fractions array with all zeros to
 639         // prevent using garbage values from previous paints
 640         GLfloat allZeros[MAX_FRACTIONS];
 641         memset(allZeros, 0, sizeof(GLfloat)*MAX_FRACTIONS);
 642         j2d_glUniform1fvARB(loc, maxFractions, allZeros);
 643     }
 644     j2d_glUniform1fvARB(loc, numStops, fractions);
 645 
 646     // update the "uniform" scale values
 647     loc = j2d_glGetUniformLocationARB(multiGradProgram, "scaleFactors");
 648     for (i = 0; i < numStops-1; i++) {
 649         // calculate a scale factor for each interval
 650         scaleFactors[i] = 1.0f / (fractions[i+1] - fractions[i]);
 651     }
 652     for (; i < maxFractions-1; i++) {
 653         // fill remaining scale factors with zero
 654         scaleFactors[i] = 0.0f;
 655     }
 656     j2d_glUniform1fvARB(loc, maxFractions-1, scaleFactors);
 657 
 658     // update the texture containing the gradient colors
 659     j2d_glEnable(GL_TEXTURE_1D);
 660     j2d_glBindTexture(GL_TEXTURE_1D, multiGradientTexID);
 661     j2d_glTexSubImage1D(GL_TEXTURE_1D, 0,
 662                         0, numStops,
 663                         GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
 664                         pixels);
 665     if (numStops < MAX_COLORS) {
 666         // when we don't have enough colors to fill the entire color gradient,
 667         // we have to replicate the last color in the right-most texel for
 668         // the NO_CYCLE case where the texcoord is sometimes forced to 1.0
 669         j2d_glTexSubImage1D(GL_TEXTURE_1D, 0,
 670                             MAX_COLORS-1, 1,
 671                             GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
 672                             pixels+(numStops-1));
 673     }
 674 }
 675 
 676 /********************** LinearGradientPaint support *************************/
 677 
 678 /**
 679  * The handles to the LinearGradientPaint fragment program objects.  The
 680  * index to the array should be a bitwise-or'ing of the MULTI_* flags defined
 681  * above.  Note that most applications will likely need to initialize one
 682  * or two of these elements, so the array is usually sparsely populated.
 683  */
 684 static GLhandleARB linearGradPrograms[MAX_PROGRAMS];
 685 
 686 /**
 687  * Compiles and links the LinearGradientPaint shader program.  If successful,
 688  * this function returns a handle to the newly created shader program;
 689  * otherwise returns 0.
 690  */
 691 static GLhandleARB
 692 OGLPaints_CreateLinearGradProgram(jint flags)
 693 {
 694     char *paintVars;
 695     char *distCode;
 696 
 697     J2dTraceLn1(J2D_TRACE_INFO,
 698                 "OGLPaints_CreateLinearGradProgram",
 699                 flags);
 700 
 701     /*
 702      * To simplify the code and to make it easier to upload a number of
 703      * uniform values at once, we pack a bunch of scalar (float) values
 704      * into vec3 values below.  Here's how the values are related:
 705      *
 706      *   params.x = p0
 707      *   params.y = p1
 708      *   params.z = p3
 709      *
 710      *   yoff = dstOps->yOffset + dstOps->height
 711      */
 712     paintVars =
 713         "uniform vec3 params;"
 714         "uniform float yoff;";
 715     distCode =
 716         // note that gl_FragCoord is in window space relative to the
 717         // lower-left corner, so we have to flip the y-coordinate here
 718         "vec3 fragCoord = vec3(gl_FragCoord.x, yoff-gl_FragCoord.y, 1.0);"
 719         "dist = dot(params, fragCoord);";
 720 
 721     return OGLPaints_CreateMultiGradProgram(flags, paintVars, distCode);
 722 }
 723 
 724 void
 725 OGLPaints_SetLinearGradientPaint(OGLContext *oglc, OGLSDOps *dstOps,
 726                                  jboolean useMask, jboolean linear,
 727                                  jint cycleMethod, jint numStops,
 728                                  jfloat p0, jfloat p1, jfloat p3,
 729                                  void *fractions, void *pixels)
 730 {
 731     GLhandleARB linearGradProgram;
 732     GLint loc;
 733     jboolean large = (numStops > MAX_FRACTIONS_SMALL);
 734     jint flags = 0;
 735 
 736     J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_SetLinearGradientPaint");
 737 
 738     RETURN_IF_NULL(oglc);
 739     RETURN_IF_NULL(dstOps);
 740     OGLPaints_ResetPaint(oglc);
 741 
 742     COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear);
 743 
 744     if (useMask) {
 745         // set up the paint on texture unit 1 (instead of the usual unit 0)
 746         j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
 747     }
 748     // no need to set GL_MODULATE here (it is ignored when shader is enabled)
 749 
 750     // locate/initialize the shader program for the given flags
 751     if (linearGradPrograms[flags] == 0) {
 752         linearGradPrograms[flags] = OGLPaints_CreateLinearGradProgram(flags);
 753         if (linearGradPrograms[flags] == 0) {
 754             // shouldn't happen, but just in case...
 755             return;
 756         }
 757     }
 758     linearGradProgram = linearGradPrograms[flags];
 759 
 760     // update the common "uniform" values (fractions and colors)
 761     OGLPaints_SetMultiGradientPaint(linearGradProgram,
 762                                     numStops, fractions, pixels);
 763 
 764     // update the other "uniform" values
 765     loc = j2d_glGetUniformLocationARB(linearGradProgram, "params");
 766     j2d_glUniform3fARB(loc, p0, p1, p3);
 767     loc = j2d_glGetUniformLocationARB(linearGradProgram, "yoff");
 768     j2d_glUniform1fARB(loc, (GLfloat)(dstOps->yOffset + dstOps->height));
 769 
 770     if (useMask) {
 771         // restore control to texture unit 0
 772         j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
 773     }
 774 
 775     // oglc->pixel has been set appropriately in OGLPaints_ResetPaint()
 776     oglc->useMask = useMask;
 777     oglc->paintState = sun_java2d_SunGraphics2D_PAINT_LIN_GRADIENT;
 778 }
 779 
 780 /********************** RadialGradientPaint support *************************/
 781 
 782 /**
 783  * The handles to the RadialGradientPaint fragment program objects.  The
 784  * index to the array should be a bitwise-or'ing of the MULTI_* flags defined
 785  * above.  Note that most applications will likely need to initialize one
 786  * or two of these elements, so the array is usually sparsely populated.
 787  */
 788 static GLhandleARB radialGradPrograms[MAX_PROGRAMS];
 789 
 790 /**
 791  * Compiles and links the RadialGradientPaint shader program.  If successful,
 792  * this function returns a handle to the newly created shader program;
 793  * otherwise returns 0.
 794  */
 795 static GLhandleARB
 796 OGLPaints_CreateRadialGradProgram(jint flags)
 797 {
 798     char *paintVars;
 799     char *distCode;
 800 
 801     J2dTraceLn1(J2D_TRACE_INFO,
 802                 "OGLPaints_CreateRadialGradProgram",
 803                 flags);
 804 
 805     /*
 806      * To simplify the code and to make it easier to upload a number of
 807      * uniform values at once, we pack a bunch of scalar (float) values
 808      * into vec3 and vec4 values below.  Here's how the values are related:
 809      *
 810      *   m0.x = m00
 811      *   m0.y = m01
 812      *   m0.z = m02
 813      *
 814      *   m1.x = m10
 815      *   m1.y = m11
 816      *   m1.z = m12
 817      *
 818      *   precalc.x = focusX
 819      *   precalc.y = yoff = dstOps->yOffset + dstOps->height
 820      *   precalc.z = 1.0 - (focusX * focusX)
 821      *   precalc.w = 1.0 / precalc.z
 822      */
 823     paintVars =
 824         "uniform vec3 m0;"
 825         "uniform vec3 m1;"
 826         "uniform vec4 precalc;";
 827 
 828     /*
 829      * The following code is derived from Daniel Rice's whitepaper on
 830      * radial gradient performance (attached to the bug report for 6521533).
 831      * Refer to that document as well as the setup code in the Java-level
 832      * BufferedPaints.setRadialGradientPaint() method for more details.
 833      */
 834     distCode =
 835         // note that gl_FragCoord is in window space relative to the
 836         // lower-left corner, so we have to flip the y-coordinate here
 837         "vec3 fragCoord ="
 838         "    vec3(gl_FragCoord.x, precalc.y - gl_FragCoord.y, 1.0);"
 839         "float x = dot(fragCoord, m0);"
 840         "float y = dot(fragCoord, m1);"
 841         "float xfx = x - precalc.x;"
 842         "dist = (precalc.x*xfx + sqrt(xfx*xfx + y*y*precalc.z))*precalc.w;";
 843 
 844     return OGLPaints_CreateMultiGradProgram(flags, paintVars, distCode);
 845 }
 846 
 847 void
 848 OGLPaints_SetRadialGradientPaint(OGLContext *oglc, OGLSDOps *dstOps,
 849                                  jboolean useMask, jboolean linear,
 850                                  jint cycleMethod, jint numStops,
 851                                  jfloat m00, jfloat m01, jfloat m02,
 852                                  jfloat m10, jfloat m11, jfloat m12,
 853                                  jfloat focusX,
 854                                  void *fractions, void *pixels)
 855 {
 856     GLhandleARB radialGradProgram;
 857     GLint loc;
 858     GLfloat yoff, denom, inv_denom;
 859     jboolean large = (numStops > MAX_FRACTIONS_SMALL);
 860     jint flags = 0;
 861 
 862     J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_SetRadialGradientPaint");
 863 
 864     RETURN_IF_NULL(oglc);
 865     RETURN_IF_NULL(dstOps);
 866     OGLPaints_ResetPaint(oglc);
 867 
 868     COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear);
 869 
 870     if (useMask) {
 871         // set up the paint on texture unit 1 (instead of the usual unit 0)
 872         j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
 873     }
 874     // no need to set GL_MODULATE here (it is ignored when shader is enabled)
 875 
 876     // locate/initialize the shader program for the given flags
 877     if (radialGradPrograms[flags] == 0) {
 878         radialGradPrograms[flags] = OGLPaints_CreateRadialGradProgram(flags);
 879         if (radialGradPrograms[flags] == 0) {
 880             // shouldn't happen, but just in case...
 881             return;
 882         }
 883     }
 884     radialGradProgram = radialGradPrograms[flags];
 885 
 886     // update the common "uniform" values (fractions and colors)
 887     OGLPaints_SetMultiGradientPaint(radialGradProgram,
 888                                     numStops, fractions, pixels);
 889 
 890     // update the other "uniform" values
 891     loc = j2d_glGetUniformLocationARB(radialGradProgram, "m0");
 892     j2d_glUniform3fARB(loc, m00, m01, m02);
 893     loc = j2d_glGetUniformLocationARB(radialGradProgram, "m1");
 894     j2d_glUniform3fARB(loc, m10, m11, m12);
 895 
 896     // pack a few unrelated, precalculated values into a single vec4
 897     yoff = (GLfloat)(dstOps->yOffset + dstOps->height);
 898     denom = 1.0f - (focusX * focusX);
 899     inv_denom = 1.0f / denom;
 900     loc = j2d_glGetUniformLocationARB(radialGradProgram, "precalc");
 901     j2d_glUniform4fARB(loc, focusX, yoff, denom, inv_denom);
 902 
 903     if (useMask) {
 904         // restore control to texture unit 0
 905         j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
 906     }
 907 
 908     // oglc->pixel has been set appropriately in OGLPaints_ResetPaint()
 909     oglc->useMask = useMask;
 910     oglc->paintState = sun_java2d_SunGraphics2D_PAINT_RAD_GRADIENT;
 911 }
 912 
 913 #endif /* !HEADLESS */