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"
 516                 "}", texCoordCalcCode);
 517     } else if (cycleMethod == CYCLE_REFLECT) {
 518         sprintf(cycleCode,
 519     /** Code for REFLECT that gets plugged into the CycleMethod placeholder. */
 520             "dist = 1.0 - (abs(fract(dist * 0.5) - 0.5) * 2.0);"
 521             // (placeholder for texcoord calculation)
 522             "%s", texCoordCalcCode);
 523     } else { // (cycleMethod == CYCLE_REPEAT)
 524         sprintf(cycleCode,
 525     /** Code for REPEAT that gets plugged into the CycleMethod placeholder. */
 526             "dist = fract(dist);"
 527             // (placeholder for texcoord calculation)
 528             "%s", texCoordCalcCode);
 529     }
 530 
 531     // compose the final source code string from the various pieces
 532     sprintf(finalSource,
 533 /**
 534  * This is essentially a template of the shader source code that can be used
 535  * for either LinearGradientPaint or RadialGradientPaint.  It includes the
 536  * structure and some variables that are common to each; the remaining
 537  * code snippets (for CycleMethod, ColorSpaceType, and mask modulation)
 538  * are filled in prior to compiling the shader at runtime depending on the
 539  * paint parameters.  See OGLPaints_CreateMultiGradProgram() for more details.
 540  */
 541         // gradient texture size (in texels)
 542         "const int TEXTURE_SIZE = %d;"
 543         // maximum number of fractions/colors supported by this shader
 544         "const int MAX_FRACTIONS = %d;"
 545         // size of a single texel
 546         "const float FULL_TEXEL = (1.0 / float(TEXTURE_SIZE));"
 547         // size of half of a single texel
 548         "const float HALF_TEXEL = (FULL_TEXEL / 2.0);"
 549         // texture containing the gradient colors
 550         "uniform sampler1D colors;"
 551         // array of gradient stops/fractions
 552         "uniform float fractions[MAX_FRACTIONS];"
 553         // array of scale factors (one for each interval)
 554         "uniform float scaleFactors[MAX_FRACTIONS-1];"
 555         // (placeholder for mask variable)
 556         "%s"
 557         // (placeholder for Linear/RadialGP-specific variables)
 558         "%s"
 559         ""
 560         "void main(void)"
 561         "{"
 562         "    float dist;"
 563              // (placeholder for Linear/RadialGradientPaint-specific code)
 564         "    %s"
 565         ""
 566         "    float tc;"
 567              // (placeholder for CycleMethod-specific code)
 568         "    %s"
 569         ""
 570              // calculate interpolated color
 571         "    vec4 result = texture1D(colors, tc);"
 572         ""
 573              // (placeholder for ColorSpace conversion code)
 574         "    %s"
 575         ""
 576              // (placeholder for mask modulation code)
 577         "    %s"
 578         ""
 579              // modulate with gl_Color in order to apply extra alpha
 580         "    gl_FragColor = result * gl_Color;"
 581         "}", MAX_COLORS, maxFractions,
 582             maskVars, paintVars, distCode,
 583             cycleCode, colorSpaceCode, maskCode);
 584 
 585     multiGradProgram = OGLContext_CreateFragmentProgram(finalSource);
 586     if (multiGradProgram == 0) {
 587         J2dRlsTraceLn(J2D_TRACE_ERROR,
 588             "OGLPaints_CreateMultiGradProgram: error creating program");
 589         return 0;
 590     }
 591 
 592     // "use" the program object temporarily so that we can set the uniforms
 593     j2d_glUseProgramObjectARB(multiGradProgram);
 594 
 595     // set the "uniform" texture unit bindings
 596     if (IS_SET(MULTI_USE_MASK)) {
 597         loc = j2d_glGetUniformLocationARB(multiGradProgram, "mask");
 598         j2d_glUniform1iARB(loc, 0); // texture unit 0
 599         loc = j2d_glGetUniformLocationARB(multiGradProgram, "colors");
 600         j2d_glUniform1iARB(loc, 1); // texture unit 1
 601     } else {
 602         loc = j2d_glGetUniformLocationARB(multiGradProgram, "colors");
 603         j2d_glUniform1iARB(loc, 0); // texture unit 0
 604     }
 605 
 606     // "unuse" the program object; it will be re-bound later as needed
 607     j2d_glUseProgramObjectARB(0);
 608 
 609     if (multiGradientTexID == 0) {
 610         OGLPaints_InitMultiGradientTexture();
 611     }
 612 
 613     return multiGradProgram;
 614 }
 615 
 616 /**
 617  * Called from the OGLPaints_SetLinear/RadialGradientPaint() methods
 618  * in order to setup the fraction/color values that are common to both.
 619  */
 620 static void
 621 OGLPaints_SetMultiGradientPaint(GLhandleARB multiGradProgram,
 622                                 jint numStops,
 623                                 void *pFractions, void *pPixels)
 624 {
 625     jint maxFractions = (numStops > MAX_FRACTIONS_SMALL) ?
 626         MAX_FRACTIONS_LARGE : MAX_FRACTIONS_SMALL;
 627     GLfloat scaleFactors[MAX_FRACTIONS-1];
 628     GLfloat *fractions = (GLfloat *)pFractions;
 629     GLint *pixels = (GLint *)pPixels;
 630     GLint loc;
 631     int i;
 632 
 633     // enable the MultipleGradientPaint shader
 634     j2d_glUseProgramObjectARB(multiGradProgram);
 635 
 636     // update the "uniform" fraction values
 637     loc = j2d_glGetUniformLocationARB(multiGradProgram, "fractions");
 638     if (numStops < maxFractions) {
 639         // fill the remainder of the fractions array with all zeros to
 640         // prevent using garbage values from previous paints
 641         GLfloat allZeros[MAX_FRACTIONS];
 642         memset(allZeros, 0, sizeof(GLfloat)*MAX_FRACTIONS);
 643         j2d_glUniform1fvARB(loc, maxFractions, allZeros);
 644     }
 645     j2d_glUniform1fvARB(loc, numStops, fractions);
 646 
 647     // update the "uniform" scale values
 648     loc = j2d_glGetUniformLocationARB(multiGradProgram, "scaleFactors");
 649     for (i = 0; i < numStops-1; i++) {
 650         // calculate a scale factor for each interval
 651         scaleFactors[i] = 1.0f / (fractions[i+1] - fractions[i]);
 652     }
 653     for (; i < maxFractions-1; i++) {
 654         // fill remaining scale factors with zero
 655         scaleFactors[i] = 0.0f;
 656     }
 657     j2d_glUniform1fvARB(loc, maxFractions-1, scaleFactors);
 658 
 659     // update the texture containing the gradient colors
 660     j2d_glEnable(GL_TEXTURE_1D);
 661     j2d_glBindTexture(GL_TEXTURE_1D, multiGradientTexID);
 662     j2d_glTexSubImage1D(GL_TEXTURE_1D, 0,
 663                         0, numStops,
 664                         GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
 665                         pixels);
 666     if (numStops < MAX_COLORS) {
 667         // when we don't have enough colors to fill the entire color gradient,
 668         // we have to replicate the last color in the right-most texel for
 669         // the NO_CYCLE case where the texcoord is sometimes forced to 1.0
 670         j2d_glTexSubImage1D(GL_TEXTURE_1D, 0,
 671                             MAX_COLORS-1, 1,
 672                             GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
 673                             pixels+(numStops-1));
 674     }
 675 }
 676 
 677 /********************** LinearGradientPaint support *************************/
 678 
 679 /**
 680  * The handles to the LinearGradientPaint fragment program objects.  The
 681  * index to the array should be a bitwise-or'ing of the MULTI_* flags defined
 682  * above.  Note that most applications will likely need to initialize one
 683  * or two of these elements, so the array is usually sparsely populated.
 684  */
 685 static GLhandleARB linearGradPrograms[MAX_PROGRAMS];
 686 
 687 /**
 688  * Compiles and links the LinearGradientPaint shader program.  If successful,
 689  * this function returns a handle to the newly created shader program;
 690  * otherwise returns 0.
 691  */
 692 static GLhandleARB
 693 OGLPaints_CreateLinearGradProgram(jint flags)
 694 {
 695     char *paintVars;
 696     char *distCode;
 697 
 698     J2dTraceLn1(J2D_TRACE_INFO,
 699                 "OGLPaints_CreateLinearGradProgram",
 700                 flags);
 701 
 702     /*
 703      * To simplify the code and to make it easier to upload a number of
 704      * uniform values at once, we pack a bunch of scalar (float) values
 705      * into vec3 values below.  Here's how the values are related:
 706      *
 707      *   params.x = p0
 708      *   params.y = p1
 709      *   params.z = p3
 710      *
 711      *   yoff = dstOps->yOffset + dstOps->height
 712      */
 713     paintVars =
 714         "uniform vec3 params;"
 715         "uniform float yoff;";
 716     distCode =
 717         // note that gl_FragCoord is in window space relative to the
 718         // lower-left corner, so we have to flip the y-coordinate here
 719         "vec3 fragCoord = vec3(gl_FragCoord.x, yoff-gl_FragCoord.y, 1.0);"
 720         "dist = dot(params, fragCoord);";
 721 
 722     return OGLPaints_CreateMultiGradProgram(flags, paintVars, distCode);
 723 }
 724 
 725 void
 726 OGLPaints_SetLinearGradientPaint(OGLContext *oglc, OGLSDOps *dstOps,
 727                                  jboolean useMask, jboolean linear,
 728                                  jint cycleMethod, jint numStops,
 729                                  jfloat p0, jfloat p1, jfloat p3,
 730                                  void *fractions, void *pixels)
 731 {
 732     GLhandleARB linearGradProgram;
 733     GLint loc;
 734     jboolean large = (numStops > MAX_FRACTIONS_SMALL);
 735     jint flags = 0;
 736 
 737     J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_SetLinearGradientPaint");
 738 
 739     RETURN_IF_NULL(oglc);
 740     RETURN_IF_NULL(dstOps);
 741     OGLPaints_ResetPaint(oglc);
 742 
 743     COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear);
 744 
 745     if (useMask) {
 746         // set up the paint on texture unit 1 (instead of the usual unit 0)
 747         j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
 748     }
 749     // no need to set GL_MODULATE here (it is ignored when shader is enabled)
 750 
 751     // locate/initialize the shader program for the given flags
 752     if (linearGradPrograms[flags] == 0) {
 753         linearGradPrograms[flags] = OGLPaints_CreateLinearGradProgram(flags);
 754         if (linearGradPrograms[flags] == 0) {
 755             // shouldn't happen, but just in case...
 756             return;
 757         }
 758     }
 759     linearGradProgram = linearGradPrograms[flags];
 760 
 761     // update the common "uniform" values (fractions and colors)
 762     OGLPaints_SetMultiGradientPaint(linearGradProgram,
 763                                     numStops, fractions, pixels);
 764 
 765     // update the other "uniform" values
 766     loc = j2d_glGetUniformLocationARB(linearGradProgram, "params");
 767     j2d_glUniform3fARB(loc, p0, p1, p3);
 768     loc = j2d_glGetUniformLocationARB(linearGradProgram, "yoff");
 769     j2d_glUniform1fARB(loc, (GLfloat)(dstOps->yOffset + dstOps->height));
 770 
 771     if (useMask) {
 772         // restore control to texture unit 0
 773         j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
 774     }
 775 
 776     // oglc->pixel has been set appropriately in OGLPaints_ResetPaint()
 777     oglc->useMask = useMask;
 778     oglc->paintState = sun_java2d_SunGraphics2D_PAINT_LIN_GRADIENT;
 779 }
 780 
 781 /********************** RadialGradientPaint support *************************/
 782 
 783 /**
 784  * The handles to the RadialGradientPaint fragment program objects.  The
 785  * index to the array should be a bitwise-or'ing of the MULTI_* flags defined
 786  * above.  Note that most applications will likely need to initialize one
 787  * or two of these elements, so the array is usually sparsely populated.
 788  */
 789 static GLhandleARB radialGradPrograms[MAX_PROGRAMS];
 790 
 791 /**
 792  * Compiles and links the RadialGradientPaint shader program.  If successful,
 793  * this function returns a handle to the newly created shader program;
 794  * otherwise returns 0.
 795  */
 796 static GLhandleARB
 797 OGLPaints_CreateRadialGradProgram(jint flags)
 798 {
 799     char *paintVars;
 800     char *distCode;
 801 
 802     J2dTraceLn1(J2D_TRACE_INFO,
 803                 "OGLPaints_CreateRadialGradProgram",
 804                 flags);
 805 
 806     /*
 807      * To simplify the code and to make it easier to upload a number of
 808      * uniform values at once, we pack a bunch of scalar (float) values
 809      * into vec3 and vec4 values below.  Here's how the values are related:
 810      *
 811      *   m0.x = m00
 812      *   m0.y = m01
 813      *   m0.z = m02
 814      *
 815      *   m1.x = m10
 816      *   m1.y = m11
 817      *   m1.z = m12
 818      *
 819      *   precalc.x = focusX
 820      *   precalc.y = yoff = dstOps->yOffset + dstOps->height
 821      *   precalc.z = 1.0 - (focusX * focusX)
 822      *   precalc.w = 1.0 / precalc.z
 823      */
 824     paintVars =
 825         "uniform vec3 m0;"
 826         "uniform vec3 m1;"
 827         "uniform vec4 precalc;";
 828 
 829     /*
 830      * The following code is derived from Daniel Rice's whitepaper on
 831      * radial gradient performance (attached to the bug report for 6521533).
 832      * Refer to that document as well as the setup code in the Java-level
 833      * BufferedPaints.setRadialGradientPaint() method for more details.
 834      */
 835     distCode =
 836         // note that gl_FragCoord is in window space relative to the
 837         // lower-left corner, so we have to flip the y-coordinate here
 838         "vec3 fragCoord ="
 839         "    vec3(gl_FragCoord.x, precalc.y - gl_FragCoord.y, 1.0);"
 840         "float x = dot(fragCoord, m0);"
 841         "float y = dot(fragCoord, m1);"
 842         "float xfx = x - precalc.x;"
 843         "dist = (precalc.x*xfx + sqrt(xfx*xfx + y*y*precalc.z))*precalc.w;";
 844 
 845     return OGLPaints_CreateMultiGradProgram(flags, paintVars, distCode);
 846 }
 847 
 848 void
 849 OGLPaints_SetRadialGradientPaint(OGLContext *oglc, OGLSDOps *dstOps,
 850                                  jboolean useMask, jboolean linear,
 851                                  jint cycleMethod, jint numStops,
 852                                  jfloat m00, jfloat m01, jfloat m02,
 853                                  jfloat m10, jfloat m11, jfloat m12,
 854                                  jfloat focusX,
 855                                  void *fractions, void *pixels)
 856 {
 857     GLhandleARB radialGradProgram;
 858     GLint loc;
 859     GLfloat yoff, denom, inv_denom;
 860     jboolean large = (numStops > MAX_FRACTIONS_SMALL);
 861     jint flags = 0;
 862 
 863     J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_SetRadialGradientPaint");
 864 
 865     RETURN_IF_NULL(oglc);
 866     RETURN_IF_NULL(dstOps);
 867     OGLPaints_ResetPaint(oglc);
 868 
 869     COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear);
 870 
 871     if (useMask) {
 872         // set up the paint on texture unit 1 (instead of the usual unit 0)
 873         j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
 874     }
 875     // no need to set GL_MODULATE here (it is ignored when shader is enabled)
 876 
 877     // locate/initialize the shader program for the given flags
 878     if (radialGradPrograms[flags] == 0) {
 879         radialGradPrograms[flags] = OGLPaints_CreateRadialGradProgram(flags);
 880         if (radialGradPrograms[flags] == 0) {
 881             // shouldn't happen, but just in case...
 882             return;
 883         }
 884     }
 885     radialGradProgram = radialGradPrograms[flags];
 886 
 887     // update the common "uniform" values (fractions and colors)
 888     OGLPaints_SetMultiGradientPaint(radialGradProgram,
 889                                     numStops, fractions, pixels);
 890 
 891     // update the other "uniform" values
 892     loc = j2d_glGetUniformLocationARB(radialGradProgram, "m0");
 893     j2d_glUniform3fARB(loc, m00, m01, m02);
 894     loc = j2d_glGetUniformLocationARB(radialGradProgram, "m1");
 895     j2d_glUniform3fARB(loc, m10, m11, m12);
 896 
 897     // pack a few unrelated, precalculated values into a single vec4
 898     yoff = (GLfloat)(dstOps->yOffset + dstOps->height);
 899     denom = 1.0f - (focusX * focusX);
 900     inv_denom = 1.0f / denom;
 901     loc = j2d_glGetUniformLocationARB(radialGradProgram, "precalc");
 902     j2d_glUniform4fARB(loc, focusX, yoff, denom, inv_denom);
 903 
 904     if (useMask) {
 905         // restore control to texture unit 0
 906         j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
 907     }
 908 
 909     // oglc->pixel has been set appropriately in OGLPaints_ResetPaint()
 910     oglc->useMask = useMask;
 911     oglc->paintState = sun_java2d_SunGraphics2D_PAINT_RAD_GRADIENT;
 912 }
 913 
 914 #endif /* !HEADLESS */