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 */