Path: blob/master/src/java.desktop/share/native/common/java2d/opengl/OGLPaints.c
41159 views
/*1* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#ifndef HEADLESS2627#include <jlong.h>28#include <string.h>2930#include "sun_java2d_SunGraphics2D.h"31#include "sun_java2d_pipe_BufferedPaints.h"3233#include "OGLPaints.h"34#include "OGLContext.h"35#include "OGLRenderQueue.h"36#include "OGLSurfaceData.h"3738void39OGLPaints_ResetPaint(OGLContext *oglc)40{41jubyte ea;4243J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_ResetPaint");4445RETURN_IF_NULL(oglc);46J2dTraceLn1(J2D_TRACE_VERBOSE, " state=%d", oglc->paintState);47RESET_PREVIOUS_OP();4849if (oglc->useMask) {50// switch to texture unit 1, where paint state is currently enabled51j2d_glActiveTextureARB(GL_TEXTURE1_ARB);52}5354switch (oglc->paintState) {55case sun_java2d_SunGraphics2D_PAINT_GRADIENT:56j2d_glDisable(GL_TEXTURE_1D);57j2d_glDisable(GL_TEXTURE_GEN_S);58break;5960case sun_java2d_SunGraphics2D_PAINT_TEXTURE:61// Note: The texture object used in SetTexturePaint() will62// still be bound at this point, so it is safe to call the following.63OGLSD_RESET_TEXTURE_WRAP(GL_TEXTURE_2D);64j2d_glDisable(GL_TEXTURE_2D);65j2d_glDisable(GL_TEXTURE_GEN_S);66j2d_glDisable(GL_TEXTURE_GEN_T);67break;6869case sun_java2d_SunGraphics2D_PAINT_LIN_GRADIENT:70case sun_java2d_SunGraphics2D_PAINT_RAD_GRADIENT:71j2d_glUseProgramObjectARB(0);72j2d_glDisable(GL_TEXTURE_1D);73break;7475case sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR:76default:77break;78}7980if (oglc->useMask) {81// restore control to texture unit 082j2d_glActiveTextureARB(GL_TEXTURE0_ARB);83}8485// set each component of the current color state to the extra alpha86// value, which will effectively apply the extra alpha to each fragment87// in paint/texturing operations88ea = (jubyte)(oglc->extraAlpha * 0xff + 0.5f);89j2d_glColor4ub(ea, ea, ea, ea);90oglc->pixel = (ea << 24) | (ea << 16) | (ea << 8) | (ea << 0);91oglc->r = ea;92oglc->g = ea;93oglc->b = ea;94oglc->a = ea;95oglc->useMask = JNI_FALSE;96oglc->paintState = -1;97}9899void100OGLPaints_SetColor(OGLContext *oglc, jint pixel)101{102jubyte r, g, b, a;103104J2dTraceLn1(J2D_TRACE_INFO, "OGLPaints_SetColor: pixel=%08x", pixel);105106RETURN_IF_NULL(oglc);107108// glColor*() is allowed within glBegin()/glEnd() pairs, so109// no need to reset the current op state here unless the paint110// state really needs to be changed111if (oglc->paintState > sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR) {112OGLPaints_ResetPaint(oglc);113}114115// store the raw (unmodified) pixel value, which may be used for116// special operations later117oglc->pixel = pixel;118119if (oglc->compState != sun_java2d_SunGraphics2D_COMP_XOR) {120r = (jubyte)(pixel >> 16);121g = (jubyte)(pixel >> 8);122b = (jubyte)(pixel >> 0);123a = (jubyte)(pixel >> 24);124125J2dTraceLn4(J2D_TRACE_VERBOSE,126" updating color: r=%02x g=%02x b=%02x a=%02x",127r, g, b, a);128} else {129pixel ^= oglc->xorPixel;130131r = (jubyte)(pixel >> 16);132g = (jubyte)(pixel >> 8);133b = (jubyte)(pixel >> 0);134a = 0xff;135136J2dTraceLn4(J2D_TRACE_VERBOSE,137" updating xor color: r=%02x g=%02x b=%02x xorpixel=%08x",138r, g, b, oglc->xorPixel);139}140141j2d_glColor4ub(r, g, b, a);142oglc->r = r;143oglc->g = g;144oglc->b = b;145oglc->a = a;146oglc->useMask = JNI_FALSE;147oglc->paintState = sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR;148}149150/************************* GradientPaint support ****************************/151152static GLuint gradientTexID = 0;153154static void155OGLPaints_InitGradientTexture()156{157GLclampf priority = 1.0f;158159J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_InitGradientTexture");160161j2d_glGenTextures(1, &gradientTexID);162j2d_glBindTexture(GL_TEXTURE_1D, gradientTexID);163j2d_glPrioritizeTextures(1, &gradientTexID, &priority);164j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);165j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);166j2d_glTexImage1D(GL_TEXTURE_1D, 0,167GL_RGBA8, 2, 0,168GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);169}170171void172OGLPaints_SetGradientPaint(OGLContext *oglc,173jboolean useMask, jboolean cyclic,174jdouble p0, jdouble p1, jdouble p3,175jint pixel1, jint pixel2)176{177GLdouble texParams[4];178GLuint pixels[2];179180J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_SetGradientPaint");181182RETURN_IF_NULL(oglc);183OGLPaints_ResetPaint(oglc);184185texParams[0] = p0;186texParams[1] = p1;187texParams[2] = 0.0;188texParams[3] = p3;189190pixels[0] = pixel1;191pixels[1] = pixel2;192193if (useMask) {194// set up the paint on texture unit 1 (instead of the usual unit 0)195j2d_glActiveTextureARB(GL_TEXTURE1_ARB);196j2d_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);197} else {198// texture unit 0 is already active; we can use the helper macro here199OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE);200}201202if (gradientTexID == 0) {203OGLPaints_InitGradientTexture();204}205206j2d_glEnable(GL_TEXTURE_1D);207j2d_glEnable(GL_TEXTURE_GEN_S);208j2d_glBindTexture(GL_TEXTURE_1D, gradientTexID);209j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S,210cyclic ? GL_REPEAT : GL_CLAMP_TO_EDGE);211j2d_glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);212j2d_glTexGendv(GL_S, GL_OBJECT_PLANE, texParams);213214j2d_glTexSubImage1D(GL_TEXTURE_1D, 0,2150, 2, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixels);216217if (useMask) {218// restore control to texture unit 0219j2d_glActiveTextureARB(GL_TEXTURE0_ARB);220}221222// oglc->pixel has been set appropriately in OGLPaints_ResetPaint()223oglc->useMask = useMask;224oglc->paintState = sun_java2d_SunGraphics2D_PAINT_GRADIENT;225}226227/************************** TexturePaint support ****************************/228229void230OGLPaints_SetTexturePaint(OGLContext *oglc,231jboolean useMask,232jlong pSrcOps, jboolean filter,233jdouble xp0, jdouble xp1, jdouble xp3,234jdouble yp0, jdouble yp1, jdouble yp3)235{236OGLSDOps *srcOps = (OGLSDOps *)jlong_to_ptr(pSrcOps);237GLdouble xParams[4];238GLdouble yParams[4];239GLint hint = (filter ? GL_LINEAR : GL_NEAREST);240241J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_SetTexturePaint");242243RETURN_IF_NULL(srcOps);244RETURN_IF_NULL(oglc);245OGLPaints_ResetPaint(oglc);246247xParams[0] = xp0;248xParams[1] = xp1;249xParams[2] = 0.0;250xParams[3] = xp3;251252yParams[0] = yp0;253yParams[1] = yp1;254yParams[2] = 0.0;255yParams[3] = yp3;256257/*258* Note that we explicitly use GL_TEXTURE_2D below rather than using259* srcOps->textureTarget. This is because the texture wrap mode employed260* here (GL_REPEAT) is not available for GL_TEXTURE_RECTANGLE_ARB targets.261* The setup code in OGLPaints.Texture.isPaintValid() and in262* OGLSurfaceData.initTexture() ensures that we only get here for263* GL_TEXTURE_2D targets.264*/265266if (useMask) {267// set up the paint on texture unit 1 (instead of the usual unit 0)268j2d_glActiveTextureARB(GL_TEXTURE1_ARB);269j2d_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);270} else {271// texture unit 0 is already active; we can use the helper macro here272OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE);273}274275j2d_glEnable(GL_TEXTURE_2D);276j2d_glEnable(GL_TEXTURE_GEN_S);277j2d_glEnable(GL_TEXTURE_GEN_T);278j2d_glBindTexture(GL_TEXTURE_2D, srcOps->textureID);279OGLSD_UPDATE_TEXTURE_FILTER(srcOps, hint);280OGLSD_UPDATE_TEXTURE_WRAP(GL_TEXTURE_2D, GL_REPEAT);281j2d_glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);282j2d_glTexGendv(GL_S, GL_OBJECT_PLANE, xParams);283j2d_glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);284j2d_glTexGendv(GL_T, GL_OBJECT_PLANE, yParams);285286if (useMask) {287// restore control to texture unit 0288j2d_glActiveTextureARB(GL_TEXTURE0_ARB);289}290291// oglc->pixel has been set appropriately in OGLPaints_ResetPaint()292oglc->useMask = useMask;293oglc->paintState = sun_java2d_SunGraphics2D_PAINT_TEXTURE;294}295296/****************** Shared MultipleGradientPaint support ********************/297298/**299* These constants are identical to those defined in the300* MultipleGradientPaint.CycleMethod enum; they are copied here for301* convenience (ideally we would pull them directly from the Java level,302* but that entails more hassle than it is worth).303*/304#define CYCLE_NONE 0305#define CYCLE_REFLECT 1306#define CYCLE_REPEAT 2307308/**309* The following constants are flags that can be bitwise-or'ed together310* to control how the MultipleGradientPaint shader source code is generated:311*312* MULTI_CYCLE_METHOD313* Placeholder for the CycleMethod enum constant.314*315* MULTI_LARGE316* If set, use the (slower) shader that supports a larger number of317* gradient colors; otherwise, use the optimized codepath. See318* the MAX_FRACTIONS_SMALL/LARGE constants below for more details.319*320* MULTI_USE_MASK321* If set, apply the alpha mask value from texture unit 0 to the322* final color result (only used in the MaskFill case).323*324* MULTI_LINEAR_RGB325* If set, convert the linear RGB result back into the sRGB color space.326*/327#define MULTI_CYCLE_METHOD (3 << 0)328#define MULTI_LARGE (1 << 2)329#define MULTI_USE_MASK (1 << 3)330#define MULTI_LINEAR_RGB (1 << 4)331332/**333* This value determines the size of the array of programs for each334* MultipleGradientPaint type. This value reflects the maximum value that335* can be represented by performing a bitwise-or of all the MULTI_*336* constants defined above.337*/338#define MAX_PROGRAMS 32339340/** Evaluates to true if the given bit is set on the local flags variable. */341#define IS_SET(flagbit) \342(((flags) & (flagbit)) != 0)343344/** Composes the given parameters as flags into the given flags variable.*/345#define COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear) \346do { \347flags |= ((cycleMethod) & MULTI_CYCLE_METHOD); \348if (large) flags |= MULTI_LARGE; \349if (useMask) flags |= MULTI_USE_MASK; \350if (linear) flags |= MULTI_LINEAR_RGB; \351} while (0)352353/** Extracts the CycleMethod enum value from the given flags variable. */354#define EXTRACT_CYCLE_METHOD(flags) \355((flags) & MULTI_CYCLE_METHOD)356357/**358* The maximum number of gradient "stops" supported by the fragment shader359* and related code. When the MULTI_LARGE flag is set, we will use360* MAX_FRACTIONS_LARGE; otherwise, we use MAX_FRACTIONS_SMALL. By having361* two separate values, we can have one highly optimized shader (SMALL) that362* supports only a few fractions/colors, and then another, less optimal363* shader that supports more stops.364*/365#define MAX_FRACTIONS sun_java2d_pipe_BufferedPaints_MULTI_MAX_FRACTIONS366#define MAX_FRACTIONS_LARGE MAX_FRACTIONS367#define MAX_FRACTIONS_SMALL 4368369/**370* The maximum number of gradient colors supported by all of the gradient371* fragment shaders. Note that this value must be a power of two, as it372* determines the size of the 1D texture created below. It also must be373* greater than or equal to MAX_FRACTIONS (there is no strict requirement374* that the two values be equal).375*/376#define MAX_COLORS 16377378/**379* The handle to the gradient color table texture object used by the shaders.380*/381static GLuint multiGradientTexID = 0;382383/**384* This is essentially a template of the shader source code that can be used385* for either LinearGradientPaint or RadialGradientPaint. It includes the386* structure and some variables that are common to each; the remaining387* code snippets (for CycleMethod, ColorSpaceType, and mask modulation)388* are filled in prior to compiling the shader at runtime depending on the389* paint parameters. See OGLPaints_CreateMultiGradProgram() for more details.390*/391static const char *multiGradientShaderSource =392// gradient texture size (in texels)393"const int TEXTURE_SIZE = %d;"394// maximum number of fractions/colors supported by this shader395"const int MAX_FRACTIONS = %d;"396// size of a single texel397"const float FULL_TEXEL = (1.0 / float(TEXTURE_SIZE));"398// size of half of a single texel399"const float HALF_TEXEL = (FULL_TEXEL / 2.0);"400// texture containing the gradient colors401"uniform sampler1D colors;"402// array of gradient stops/fractions403"uniform float fractions[MAX_FRACTIONS];"404// array of scale factors (one for each interval)405"uniform float scaleFactors[MAX_FRACTIONS-1];"406// (placeholder for mask variable)407"%s"408// (placeholder for Linear/RadialGP-specific variables)409"%s"410""411"void main(void)"412"{"413" float dist;"414// (placeholder for Linear/RadialGradientPaint-specific code)415" %s"416""417" float tc;"418// (placeholder for CycleMethod-specific code)419" %s"420""421// calculate interpolated color422" vec4 result = texture1D(colors, tc);"423""424// (placeholder for ColorSpace conversion code)425" %s"426""427// (placeholder for mask modulation code)428" %s"429""430// modulate with gl_Color in order to apply extra alpha431" gl_FragColor = result * gl_Color;"432"}";433434/**435* This code takes a "dist" value as input (as calculated earlier by the436* LGP/RGP-specific code) in the range [0,1] and produces a texture437* coordinate value "tc" that represents the position of the chosen color438* in the one-dimensional gradient texture (also in the range [0,1]).439*440* One naive way to implement this would be to iterate through the fractions441* to figure out in which interval "dist" falls, and then compute the442* relative distance between the two nearest stops. This approach would443* require an "if" check on every iteration, and it is best to avoid444* conditionals in fragment shaders for performance reasons. Also, one might445* be tempted to use a break statement to jump out of the loop once the446* interval was found, but break statements (and non-constant loop bounds)447* are not natively available on most graphics hardware today, so that is448* a non-starter.449*450* The more optimal approach used here avoids these issues entirely by using451* an accumulation function that is equivalent to the process described above.452* The scaleFactors array is pre-initialized at enable time as follows:453* scaleFactors[i] = 1.0 / (fractions[i+1] - fractions[i]);454*455* For each iteration, we subtract fractions[i] from dist and then multiply456* that value by scaleFactors[i]. If we are within the target interval,457* this value will be a fraction in the range [0,1] indicating the relative458* distance between fraction[i] and fraction[i+1]. If we are below the459* target interval, this value will be negative, so we clamp it to zero460* to avoid accumulating any value. If we are above the target interval,461* the value will be greater than one, so we clamp it to one. Upon exiting462* the loop, we will have accumulated zero or more 1.0's and a single463* fractional value. This accumulated value tells us the position of the464* fragment color in the one-dimensional gradient texture, i.e., the465* texcoord called "tc".466*/467static const char *texCoordCalcCode =468"int i;"469"float relFraction = 0.0;"470"for (i = 0; i < MAX_FRACTIONS-1; i++) {"471" relFraction +="472" clamp((dist - fractions[i]) * scaleFactors[i], 0.0, 1.0);"473"}"474// we offset by half a texel so that we find the linearly interpolated475// color between the two texel centers of interest476"tc = HALF_TEXEL + (FULL_TEXEL * relFraction);";477478/** Code for NO_CYCLE that gets plugged into the CycleMethod placeholder. */479static const char *noCycleCode =480"if (dist <= 0.0) {"481" tc = 0.0;"482"} else if (dist >= 1.0) {"483" tc = 1.0;"484"} else {"485// (placeholder for texcoord calculation)486" %s"487"}";488489/** Code for REFLECT that gets plugged into the CycleMethod placeholder. */490static const char *reflectCode =491"dist = 1.0 - (abs(fract(dist * 0.5) - 0.5) * 2.0);"492// (placeholder for texcoord calculation)493"%s";494495/** Code for REPEAT that gets plugged into the CycleMethod placeholder. */496static const char *repeatCode =497"dist = fract(dist);"498// (placeholder for texcoord calculation)499"%s";500501static void502OGLPaints_InitMultiGradientTexture()503{504GLclampf priority = 1.0f;505506J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_InitMultiGradientTexture");507508j2d_glGenTextures(1, &multiGradientTexID);509j2d_glBindTexture(GL_TEXTURE_1D, multiGradientTexID);510j2d_glPrioritizeTextures(1, &multiGradientTexID, &priority);511j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);512j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);513j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);514j2d_glTexImage1D(GL_TEXTURE_1D, 0,515GL_RGBA8, MAX_COLORS, 0,516GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);517}518519/**520* Compiles and links the MultipleGradientPaint shader program. If521* successful, this function returns a handle to the newly created522* shader program; otherwise returns 0.523*/524static GLhandleARB525OGLPaints_CreateMultiGradProgram(jint flags,526char *paintVars, char *distCode)527{528GLhandleARB multiGradProgram;529GLint loc;530char *maskVars = "";531char *maskCode = "";532char *colorSpaceCode = "";533char cycleCode[1500];534char finalSource[3000];535jint cycleMethod = EXTRACT_CYCLE_METHOD(flags);536jint maxFractions = IS_SET(MULTI_LARGE) ?537MAX_FRACTIONS_LARGE : MAX_FRACTIONS_SMALL;538539J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_CreateMultiGradProgram");540541if (IS_SET(MULTI_USE_MASK)) {542/*543* This code modulates the calculated result color with the544* corresponding alpha value from the alpha mask texture active545* on texture unit 0. Only needed when useMask is true (i.e., only546* for MaskFill operations).547*/548maskVars = "uniform sampler2D mask;";549maskCode = "result *= texture2D(mask, gl_TexCoord[0].st);";550} else {551/*552* REMIND: This is really wacky, but the gradient shaders will553* produce completely incorrect results on ATI hardware (at least554* on first-gen (R300-based) boards) if the shader program does not555* try to access texture coordinates by using a gl_TexCoord[*]556* variable. This problem really should be addressed by ATI, but557* in the meantime it seems we can workaround the issue by inserting558* a benign operation that accesses gl_TexCoord[0]. Note that we559* only need to do this for ATI boards and only in the !useMask case,560* because the useMask case already does access gl_TexCoord[1] and561* is therefore not affected by this driver bug.562*/563const char *vendor = (const char *)j2d_glGetString(GL_VENDOR);564if (vendor != NULL && strncmp(vendor, "ATI", 3) == 0) {565maskCode = "dist = gl_TexCoord[0].s;";566}567}568569if (IS_SET(MULTI_LINEAR_RGB)) {570/*571* This code converts a single pixel in linear RGB space back572* into sRGB (note: this code was adapted from the573* MultipleGradientPaintContext.convertLinearRGBtoSRGB() method).574*/575colorSpaceCode =576"result.rgb = 1.055 * pow(result.rgb, vec3(0.416667)) - 0.055;";577}578579if (cycleMethod == CYCLE_NONE) {580sprintf(cycleCode, noCycleCode, texCoordCalcCode);581} else if (cycleMethod == CYCLE_REFLECT) {582sprintf(cycleCode, reflectCode, texCoordCalcCode);583} else { // (cycleMethod == CYCLE_REPEAT)584sprintf(cycleCode, repeatCode, texCoordCalcCode);585}586587// compose the final source code string from the various pieces588sprintf(finalSource, multiGradientShaderSource,589MAX_COLORS, maxFractions,590maskVars, paintVars, distCode,591cycleCode, colorSpaceCode, maskCode);592593multiGradProgram = OGLContext_CreateFragmentProgram(finalSource);594if (multiGradProgram == 0) {595J2dRlsTraceLn(J2D_TRACE_ERROR,596"OGLPaints_CreateMultiGradProgram: error creating program");597return 0;598}599600// "use" the program object temporarily so that we can set the uniforms601j2d_glUseProgramObjectARB(multiGradProgram);602603// set the "uniform" texture unit bindings604if (IS_SET(MULTI_USE_MASK)) {605loc = j2d_glGetUniformLocationARB(multiGradProgram, "mask");606j2d_glUniform1iARB(loc, 0); // texture unit 0607loc = j2d_glGetUniformLocationARB(multiGradProgram, "colors");608j2d_glUniform1iARB(loc, 1); // texture unit 1609} else {610loc = j2d_glGetUniformLocationARB(multiGradProgram, "colors");611j2d_glUniform1iARB(loc, 0); // texture unit 0612}613614// "unuse" the program object; it will be re-bound later as needed615j2d_glUseProgramObjectARB(0);616617if (multiGradientTexID == 0) {618OGLPaints_InitMultiGradientTexture();619}620621return multiGradProgram;622}623624/**625* Called from the OGLPaints_SetLinear/RadialGradientPaint() methods626* in order to setup the fraction/color values that are common to both.627*/628static void629OGLPaints_SetMultiGradientPaint(GLhandleARB multiGradProgram,630jint numStops,631void *pFractions, void *pPixels)632{633jint maxFractions = (numStops > MAX_FRACTIONS_SMALL) ?634MAX_FRACTIONS_LARGE : MAX_FRACTIONS_SMALL;635GLfloat scaleFactors[MAX_FRACTIONS-1];636GLfloat *fractions = (GLfloat *)pFractions;637GLint *pixels = (GLint *)pPixels;638GLint loc;639int i;640641// enable the MultipleGradientPaint shader642j2d_glUseProgramObjectARB(multiGradProgram);643644// update the "uniform" fraction values645loc = j2d_glGetUniformLocationARB(multiGradProgram, "fractions");646if (numStops < maxFractions) {647// fill the remainder of the fractions array with all zeros to648// prevent using garbage values from previous paints649GLfloat allZeros[MAX_FRACTIONS];650memset(allZeros, 0, sizeof(GLfloat)*MAX_FRACTIONS);651j2d_glUniform1fvARB(loc, maxFractions, allZeros);652}653j2d_glUniform1fvARB(loc, numStops, fractions);654655// update the "uniform" scale values656loc = j2d_glGetUniformLocationARB(multiGradProgram, "scaleFactors");657for (i = 0; i < numStops-1; i++) {658// calculate a scale factor for each interval659scaleFactors[i] = 1.0f / (fractions[i+1] - fractions[i]);660}661for (; i < maxFractions-1; i++) {662// fill remaining scale factors with zero663scaleFactors[i] = 0.0f;664}665j2d_glUniform1fvARB(loc, maxFractions-1, scaleFactors);666667// update the texture containing the gradient colors668j2d_glEnable(GL_TEXTURE_1D);669j2d_glBindTexture(GL_TEXTURE_1D, multiGradientTexID);670j2d_glTexSubImage1D(GL_TEXTURE_1D, 0,6710, numStops,672GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,673pixels);674if (numStops < MAX_COLORS) {675// when we don't have enough colors to fill the entire color gradient,676// we have to replicate the last color in the right-most texel for677// the NO_CYCLE case where the texcoord is sometimes forced to 1.0678j2d_glTexSubImage1D(GL_TEXTURE_1D, 0,679MAX_COLORS-1, 1,680GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,681pixels+(numStops-1));682}683}684685/********************** LinearGradientPaint support *************************/686687/**688* The handles to the LinearGradientPaint fragment program objects. The689* index to the array should be a bitwise-or'ing of the MULTI_* flags defined690* above. Note that most applications will likely need to initialize one691* or two of these elements, so the array is usually sparsely populated.692*/693static GLhandleARB linearGradPrograms[MAX_PROGRAMS];694695/**696* Compiles and links the LinearGradientPaint shader program. If successful,697* this function returns a handle to the newly created shader program;698* otherwise returns 0.699*/700static GLhandleARB701OGLPaints_CreateLinearGradProgram(jint flags)702{703char *paintVars;704char *distCode;705706J2dTraceLn1(J2D_TRACE_INFO,707"OGLPaints_CreateLinearGradProgram",708flags);709710/*711* To simplify the code and to make it easier to upload a number of712* uniform values at once, we pack a bunch of scalar (float) values713* into vec3 values below. Here's how the values are related:714*715* params.x = p0716* params.y = p1717* params.z = p3718*719* yoff = dstOps->yOffset + dstOps->height720*/721paintVars =722"uniform vec3 params;"723"uniform float yoff;";724distCode =725// note that gl_FragCoord is in window space relative to the726// lower-left corner, so we have to flip the y-coordinate here727"vec3 fragCoord = vec3(gl_FragCoord.x, yoff-gl_FragCoord.y, 1.0);"728"dist = dot(params, fragCoord);";729730return OGLPaints_CreateMultiGradProgram(flags, paintVars, distCode);731}732733void734OGLPaints_SetLinearGradientPaint(OGLContext *oglc, OGLSDOps *dstOps,735jboolean useMask, jboolean linear,736jint cycleMethod, jint numStops,737jfloat p0, jfloat p1, jfloat p3,738void *fractions, void *pixels)739{740GLhandleARB linearGradProgram;741GLint loc;742jboolean large = (numStops > MAX_FRACTIONS_SMALL);743jint flags = 0;744745J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_SetLinearGradientPaint");746747RETURN_IF_NULL(oglc);748RETURN_IF_NULL(dstOps);749OGLPaints_ResetPaint(oglc);750751COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear);752753if (useMask) {754// set up the paint on texture unit 1 (instead of the usual unit 0)755j2d_glActiveTextureARB(GL_TEXTURE1_ARB);756}757// no need to set GL_MODULATE here (it is ignored when shader is enabled)758759// locate/initialize the shader program for the given flags760if (linearGradPrograms[flags] == 0) {761linearGradPrograms[flags] = OGLPaints_CreateLinearGradProgram(flags);762if (linearGradPrograms[flags] == 0) {763// shouldn't happen, but just in case...764return;765}766}767linearGradProgram = linearGradPrograms[flags];768769// update the common "uniform" values (fractions and colors)770OGLPaints_SetMultiGradientPaint(linearGradProgram,771numStops, fractions, pixels);772773// update the other "uniform" values774loc = j2d_glGetUniformLocationARB(linearGradProgram, "params");775j2d_glUniform3fARB(loc, p0, p1, p3);776loc = j2d_glGetUniformLocationARB(linearGradProgram, "yoff");777j2d_glUniform1fARB(loc, (GLfloat)(dstOps->yOffset + dstOps->height));778779if (useMask) {780// restore control to texture unit 0781j2d_glActiveTextureARB(GL_TEXTURE0_ARB);782}783784// oglc->pixel has been set appropriately in OGLPaints_ResetPaint()785oglc->useMask = useMask;786oglc->paintState = sun_java2d_SunGraphics2D_PAINT_LIN_GRADIENT;787}788789/********************** RadialGradientPaint support *************************/790791/**792* The handles to the RadialGradientPaint fragment program objects. The793* index to the array should be a bitwise-or'ing of the MULTI_* flags defined794* above. Note that most applications will likely need to initialize one795* or two of these elements, so the array is usually sparsely populated.796*/797static GLhandleARB radialGradPrograms[MAX_PROGRAMS];798799/**800* Compiles and links the RadialGradientPaint shader program. If successful,801* this function returns a handle to the newly created shader program;802* otherwise returns 0.803*/804static GLhandleARB805OGLPaints_CreateRadialGradProgram(jint flags)806{807char *paintVars;808char *distCode;809810J2dTraceLn1(J2D_TRACE_INFO,811"OGLPaints_CreateRadialGradProgram",812flags);813814/*815* To simplify the code and to make it easier to upload a number of816* uniform values at once, we pack a bunch of scalar (float) values817* into vec3 and vec4 values below. Here's how the values are related:818*819* m0.x = m00820* m0.y = m01821* m0.z = m02822*823* m1.x = m10824* m1.y = m11825* m1.z = m12826*827* precalc.x = focusX828* precalc.y = yoff = dstOps->yOffset + dstOps->height829* precalc.z = 1.0 - (focusX * focusX)830* precalc.w = 1.0 / precalc.z831*/832paintVars =833"uniform vec3 m0;"834"uniform vec3 m1;"835"uniform vec4 precalc;";836837/*838* The following code is derived from Daniel Rice's whitepaper on839* radial gradient performance (attached to the bug report for 6521533).840* Refer to that document as well as the setup code in the Java-level841* BufferedPaints.setRadialGradientPaint() method for more details.842*/843distCode =844// note that gl_FragCoord is in window space relative to the845// lower-left corner, so we have to flip the y-coordinate here846"vec3 fragCoord ="847" vec3(gl_FragCoord.x, precalc.y - gl_FragCoord.y, 1.0);"848"float x = dot(fragCoord, m0);"849"float y = dot(fragCoord, m1);"850"float xfx = x - precalc.x;"851"dist = (precalc.x*xfx + sqrt(xfx*xfx + y*y*precalc.z))*precalc.w;";852853return OGLPaints_CreateMultiGradProgram(flags, paintVars, distCode);854}855856void857OGLPaints_SetRadialGradientPaint(OGLContext *oglc, OGLSDOps *dstOps,858jboolean useMask, jboolean linear,859jint cycleMethod, jint numStops,860jfloat m00, jfloat m01, jfloat m02,861jfloat m10, jfloat m11, jfloat m12,862jfloat focusX,863void *fractions, void *pixels)864{865GLhandleARB radialGradProgram;866GLint loc;867GLfloat yoff, denom, inv_denom;868jboolean large = (numStops > MAX_FRACTIONS_SMALL);869jint flags = 0;870871J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_SetRadialGradientPaint");872873RETURN_IF_NULL(oglc);874RETURN_IF_NULL(dstOps);875OGLPaints_ResetPaint(oglc);876877COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear);878879if (useMask) {880// set up the paint on texture unit 1 (instead of the usual unit 0)881j2d_glActiveTextureARB(GL_TEXTURE1_ARB);882}883// no need to set GL_MODULATE here (it is ignored when shader is enabled)884885// locate/initialize the shader program for the given flags886if (radialGradPrograms[flags] == 0) {887radialGradPrograms[flags] = OGLPaints_CreateRadialGradProgram(flags);888if (radialGradPrograms[flags] == 0) {889// shouldn't happen, but just in case...890return;891}892}893radialGradProgram = radialGradPrograms[flags];894895// update the common "uniform" values (fractions and colors)896OGLPaints_SetMultiGradientPaint(radialGradProgram,897numStops, fractions, pixels);898899// update the other "uniform" values900loc = j2d_glGetUniformLocationARB(radialGradProgram, "m0");901j2d_glUniform3fARB(loc, m00, m01, m02);902loc = j2d_glGetUniformLocationARB(radialGradProgram, "m1");903j2d_glUniform3fARB(loc, m10, m11, m12);904905// pack a few unrelated, precalculated values into a single vec4906yoff = (GLfloat)(dstOps->yOffset + dstOps->height);907denom = 1.0f - (focusX * focusX);908inv_denom = 1.0f / denom;909loc = j2d_glGetUniformLocationARB(radialGradProgram, "precalc");910j2d_glUniform4fARB(loc, focusX, yoff, denom, inv_denom);911912if (useMask) {913// restore control to texture unit 0914j2d_glActiveTextureARB(GL_TEXTURE0_ARB);915}916917// oglc->pixel has been set appropriately in OGLPaints_ResetPaint()918oglc->useMask = useMask;919oglc->paintState = sun_java2d_SunGraphics2D_PAINT_RAD_GRADIENT;920}921922#endif /* !HEADLESS */923924925