/* * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /** * This file contains a standalone program that is used to generate the * D3DShaders.h file. The program invokes the fxc (D3D Shader Compiler) * utility, which is part of the DirectX 9/10 SDK. Since most JDK * developers (other than some Java 2D engineers) do not have the full DXSDK * installed, and since we do not want to make the JDK build process * dependent on the full DXSDK installation, we have chosen not to make * this shader compilation step part of the build process. Instead, it is * only necessary to compile and run this program when changes need to be * made to the shader code contained within. Typically, this only happens * on an as-needed basis by someone familiar with the D3D pipeline. Running * this program is fairly straightforward: * * % rm D3DShaders.h * % cl D3DShaderGen.c * % D3DShaderGen.exe * * (And don't forget to putback the updated D3DShaders.h file!) */ #include #include #include static FILE *fpHeader = NULL; static char *strHeaderFile = "D3DShaders.h"; /** Evaluates to true if the given bit is set on the local flags variable. */ #define IS_SET(flagbit) \ (((flags) & (flagbit)) != 0) // REMIND //#define J2dTraceLn(a, b) fprintf(stderr, "%s\n", b); //#define J2dTraceLn1(a, b, c) fprintf(stderr, b, c); #define J2dTraceLn(a, b) #define J2dTraceLn1(a, b, c) /************************* General shader support ***************************/ static void D3DShaderGen_WriteShader(char *source, char *target, char *name, int flags) { FILE *fpTmp; char varname[50]; char *args[8]; int val; // write source to tmp.hlsl fpTmp = fopen("tmp.hlsl", "w"); fprintf(fpTmp, "%s\n", source); fclose(fpTmp); { PROCESS_INFORMATION pi; STARTUPINFO si; char pargs[300]; sprintf(pargs, "c:\\progra~1\\mi5889~1\\utilit~1\\bin\\x86\\fxc.exe " "/T %s /Vn %s%d /Fh tmp.h tmp.hlsl", // uncomment the following line to generate debug // info in the shader header file (may be useful // for testing/debuggging purposes, but it nearly // doubles the size of the header file and compiled // shader programs - off for production builds) //"/Zi /T %s /Vn %s%d /Fh tmp.h tmp.hlsl", target, name, flags); fprintf(stderr, "%s\n", pargs); memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.dwFlags = STARTF_USESTDHANDLES; //si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); //fprintf(stderr, "%s\n", pargs); val = CreateProcess(0, pargs, 0, 0, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi); { DWORD code; do { GetExitCodeProcess(pi.hProcess, &code); //fprintf(stderr, "waiting..."); Sleep(100); } while (code == STILL_ACTIVE); if (code != 0) { fprintf(stderr, "fxc failed for %s%d\n", name, flags); } } CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } // append tmp.h to D3DShaders.h { int ch; fpTmp = fopen("tmp.h", "r"); while ((ch = fgetc(fpTmp)) != EOF) { fputc(ch, fpHeader); } fclose(fpTmp); } } static void D3DShaderGen_WritePixelShader(char *source, char *name, int flags) { D3DShaderGen_WriteShader(source, "ps_2_0", name, flags); } #define MULTI_GRAD_CYCLE_METHOD (3 << 0) /** Extracts the CycleMethod enum value from the given flags variable. */ #define EXTRACT_CYCLE_METHOD(flags) \ ((flags) & MULTI_GRAD_CYCLE_METHOD) static void D3DShaderGen_WriteShaderArray(char *name, int num) { char array[5000]; char elem[30]; int i; sprintf(array, "const DWORD *%sShaders[] =\n{\n", name); for (i = 0; i < num; i++) { if (num == 32 && EXTRACT_CYCLE_METHOD(i) == 3) { // REMIND: what a hack! sprintf(elem, " NULL,\n"); } else { sprintf(elem, " %s%d,\n", name, i); } strcat(array, elem); } strcat(array, "};\n"); // append to D3DShaders.h fprintf(fpHeader, "%s\n", array); } /**************************** ConvolveOp support ****************************/ static const char *convolveShaderSource = // image to be convolved "sampler2D baseImage : register(s0);" // image edge limits: // imgEdge.xy = imgMin.xy (anything < will be treated as edge case) // imgEdge.zw = imgMax.xy (anything > will be treated as edge case) "float4 imgEdge : register(c0);" // value for each location in the convolution kernel: // kernelVals[i].x = offsetX[i] // kernelVals[i].y = offsetY[i] // kernelVals[i].z = kernel[i] "float3 kernelVals[%d] : register(c1);" "" "void main(in float2 tc : TEXCOORD0," " inout float4 color : COLOR0)" "{" " float4 sum = imgEdge - tc.xyxy;" "" " if (sum.x > 0 || sum.y > 0 || sum.z < 0 || sum.w < 0) {" // (placeholder for edge condition code) " color = %s;" " } else {" " int i;" " sum = float4(0, 0, 0, 0);" " for (i = 0; i < %d; i++) {" " sum +=" " kernelVals[i].z *" " tex2D(baseImage, tc + kernelVals[i].xy);" " }" // modulate with current color in order to apply extra alpha " color *= sum;" " }" "" "}"; /** * Flags that can be bitwise-or'ed together to control how the shader * source code is generated. */ #define CONVOLVE_EDGE_ZERO_FILL (1 << 0) #define CONVOLVE_5X5 (1 << 1) #define MAX_CONVOLVE (1 << 2) static void D3DShaderGen_GenerateConvolveShader(int flags) { int kernelMax = IS_SET(CONVOLVE_5X5) ? 25 : 9; char *edge; char finalSource[2000]; J2dTraceLn1(J2D_TRACE_INFO, "D3DShaderGen_GenerateConvolveShader: flags=%d", flags); if (IS_SET(CONVOLVE_EDGE_ZERO_FILL)) { // EDGE_ZERO_FILL: fill in zero at the edges edge = "float4(0, 0, 0, 0)"; } else { // EDGE_NO_OP: use the source pixel color at the edges edge = "tex2D(baseImage, tc)"; } // compose the final source code string from the various pieces sprintf(finalSource, convolveShaderSource, kernelMax, edge, kernelMax); D3DShaderGen_WritePixelShader(finalSource, "convolve", flags); } /**************************** RescaleOp support *****************************/ static const char *rescaleShaderSource = // image to be rescaled "sampler2D baseImage : register(s0);" // vector containing scale factors "float4 scaleFactors : register(c0);" // vector containing offsets "float4 offsets : register(c1);" "" "void main(in float2 tc : TEXCOORD0," " inout float4 color : COLOR0)" "{" " float4 srcColor = tex2D(baseImage, tc);" "" // (placeholder for un-premult code) " %s" "" // rescale source value " float4 result = (srcColor * scaleFactors) + offsets;" "" // (placeholder for re-premult code) " %s" "" // modulate with current color in order to apply extra alpha " color *= result;" "}"; /** * Flags that can be bitwise-or'ed together to control how the shader * source code is generated. */ #define RESCALE_NON_PREMULT (1 << 0) #define MAX_RESCALE (1 << 1) static void D3DShaderGen_GenerateRescaleShader(int flags) { char *preRescale = ""; char *postRescale = ""; char finalSource[2000]; J2dTraceLn1(J2D_TRACE_INFO, "D3DShaderGen_GenerateRescaleShader: flags=%d", flags); if (IS_SET(RESCALE_NON_PREMULT)) { preRescale = "srcColor.rgb /= srcColor.a;"; postRescale = "result.rgb *= result.a;"; } // compose the final source code string from the various pieces sprintf(finalSource, rescaleShaderSource, preRescale, postRescale); D3DShaderGen_WritePixelShader(finalSource, "rescale", flags); } /**************************** LookupOp support ******************************/ static const char *lookupShaderSource = // source image (bound to texture unit 0) "sampler2D baseImage : register(s0);" // lookup table (bound to texture unit 1) "sampler2D lookupTable : register(s1);" // offset subtracted from source index prior to lookup step "float4 offset : register(c0);" "" "void main(in float2 tc : TEXCOORD0," " inout float4 color : COLOR0)" "{" " float4 srcColor = tex2D(baseImage, tc);" // (placeholder for un-premult code) " %s" // subtract offset from original index " float4 srcIndex = srcColor - offset;" // use source value as input to lookup table (note that // "v" texcoords are hardcoded to hit texel centers of // each row/band in texture) " float4 result;" " result.r = tex2D(lookupTable, float2(srcIndex.r, 0.125)).r;" " result.g = tex2D(lookupTable, float2(srcIndex.g, 0.375)).r;" " result.b = tex2D(lookupTable, float2(srcIndex.b, 0.625)).r;" // (placeholder for alpha store code) " %s" // (placeholder for re-premult code) " %s" // modulate with current color in order to apply extra alpha " color *= result;" "}"; /** * Flags that can be bitwise-or'ed together to control how the shader * source code is generated. */ #define LOOKUP_USE_SRC_ALPHA (1 << 0) #define LOOKUP_NON_PREMULT (1 << 1) #define MAX_LOOKUP (1 << 2) static void D3DShaderGen_GenerateLookupShader(int flags) { char *alpha; char *preLookup = ""; char *postLookup = ""; char finalSource[2000]; J2dTraceLn1(J2D_TRACE_INFO, "D3DShaderGen_GenerateLookupShader: flags=%d", flags); if (IS_SET(LOOKUP_USE_SRC_ALPHA)) { // when numComps is 1 or 3, the alpha is not looked up in the table; // just keep the alpha from the source fragment alpha = "result.a = srcColor.a;"; } else { // when numComps is 4, the alpha is looked up in the table, just // like the other color components from the source fragment alpha = "result.a = tex2D(lookupTable, float2(srcIndex.a, 0.875)).r;"; } if (IS_SET(LOOKUP_NON_PREMULT)) { preLookup = "srcColor.rgb /= srcColor.a;"; postLookup = "result.rgb *= result.a;"; } // compose the final source code string from the various pieces sprintf(finalSource, lookupShaderSource, preLookup, alpha, postLookup); D3DShaderGen_WritePixelShader(finalSource, "lookup", flags); } /************************* GradientPaint support ****************************/ /* * To simplify the code and to make it easier to upload a number of * uniform values at once, we pack a bunch of scalar (float) values * into a single float3 below. Here's how the values are related: * * params.x = p0 * params.y = p1 * params.z = p3 */ static const char *basicGradientShaderSource = "float3 params : register (c0);" "float4 color1 : register (c1);" "float4 color2 : register (c2);" // (placeholder for mask variable) "%s" "" // (placeholder for mask texcoord input) "void main(%s" " in float4 winCoord : TEXCOORD%d," " inout float4 color : COLOR0)" "{" " float3 fragCoord = float3(winCoord.x, winCoord.y, 1.0);" " float dist = dot(params.xyz, fragCoord);" "" // the setup code for p0/p1/p3 translates/scales to hit texel // centers (at 0.25 and 0.75) because it is needed for the // original/fast texture-based implementation, but it is not // desirable for this shader-based implementation, so we // re-transform the value here... " dist = (dist - 0.25) * 2.0;" "" " float fraction;" // (placeholder for cycle code) " %s" "" " float4 result = lerp(color1, color2, fraction);" "" // (placeholder for mask modulation code) " %s" "" // modulate with current color in order to apply extra alpha " color *= result;" "}"; /** * Flags that can be bitwise-or'ed together to control how the shader * source code is generated. */ #define BASIC_GRAD_IS_CYCLIC (1 << 0) #define BASIC_GRAD_USE_MASK (1 << 1) #define MAX_BASIC_GRAD (1 << 2) static void D3DShaderGen_GenerateBasicGradShader(int flags) { int colorSampler = IS_SET(BASIC_GRAD_USE_MASK) ? 1 : 0; char *cycleCode; char *maskVars = ""; char *maskInput = ""; char *maskCode = ""; char finalSource[3000]; J2dTraceLn1(J2D_TRACE_INFO, "D3DShaderGen_GenerateBasicGradShader", flags); if (IS_SET(BASIC_GRAD_IS_CYCLIC)) { cycleCode = "fraction = 1.0 - (abs(frac(dist * 0.5) - 0.5) * 2.0);"; } else { cycleCode = "fraction = clamp(dist, 0.0, 1.0);"; } if (IS_SET(BASIC_GRAD_USE_MASK)) { /* * This code modulates the calculated result color with the * corresponding alpha value from the alpha mask texture active * on texture unit 0. Only needed when useMask is true (i.e., only * for MaskFill operations). */ maskVars = "sampler2D mask : register(s0);"; maskInput = "in float4 maskCoord : TEXCOORD0,"; maskCode = "result *= tex2D(mask, maskCoord.xy).a;"; } // compose the final source code string from the various pieces sprintf(finalSource, basicGradientShaderSource, maskVars, maskInput, colorSampler, cycleCode, maskCode); D3DShaderGen_WritePixelShader(finalSource, "grad", flags); } /****************** Shared MultipleGradientPaint support ********************/ /** * These constants are identical to those defined in the * MultipleGradientPaint.CycleMethod enum; they are copied here for * convenience (ideally we would pull them directly from the Java level, * but that entails more hassle than it is worth). */ #define CYCLE_NONE 0 #define CYCLE_REFLECT 1 #define CYCLE_REPEAT 2 /** * The following constants are flags that can be bitwise-or'ed together * to control how the MultipleGradientPaint shader source code is generated: * * MULTI_GRAD_CYCLE_METHOD * Placeholder for the CycleMethod enum constant. * * MULTI_GRAD_LARGE * If set, use the (slower) shader that supports a larger number of * gradient colors; otherwise, use the optimized codepath. See * the MAX_FRACTIONS_SMALL/LARGE constants below for more details. * * MULTI_GRAD_USE_MASK * If set, apply the alpha mask value from texture unit 1 to the * final color result (only used in the MaskFill case). * * MULTI_GRAD_LINEAR_RGB * If set, convert the linear RGB result back into the sRGB color space. */ //#define MULTI_GRAD_CYCLE_METHOD (3 << 0) #define MULTI_GRAD_LARGE (1 << 2) #define MULTI_GRAD_USE_MASK (1 << 3) #define MULTI_GRAD_LINEAR_RGB (1 << 4) // REMIND #define MAX_MULTI_GRAD (1 << 5) /** Extracts the CycleMethod enum value from the given flags variable. */ //#define EXTRACT_CYCLE_METHOD(flags) \ // ((flags) & MULTI_GRAD_CYCLE_METHOD) /** * The maximum number of gradient "stops" supported by the fragment shader * and related code. When the MULTI_GRAD_LARGE flag is set, we will use * MAX_FRACTIONS_LARGE; otherwise, we use MAX_FRACTIONS_SMALL. By having * two separate values, we can have one highly optimized shader (SMALL) that * supports only a few fractions/colors, and then another, less optimal * shader that supports more stops. */ #define MAX_FRACTIONS 8 #define MAX_FRACTIONS_LARGE MAX_FRACTIONS #define MAX_FRACTIONS_SMALL 4 /** * The maximum number of gradient colors supported by all of the gradient * fragment shaders. Note that this value must be a power of two, as it * determines the size of the 1D texture created below. It also must be * greater than or equal to MAX_FRACTIONS (there is no strict requirement * that the two values be equal). */ #define MAX_COLORS 16 static const char *multiGradientShaderSource = // gradient texture size (in texels) "#define TEXTURE_SIZE %d\n" // maximum number of fractions/colors supported by this shader "#define MAX_FRACTIONS %d\n" // size of a single texel "#define FULL_TEXEL (1.0 / float(TEXTURE_SIZE))\n" // size of half of a single texel "#define HALF_TEXEL (FULL_TEXEL / 2.0)\n" // texture containing the gradient colors "sampler2D colors : register (s%d);" // array of gradient stops/fractions and corresponding scale factors // fractions[i].x = gradientStop[i] // fractions[i].y = scaleFactor[i] "float2 fractions[MAX_FRACTIONS] : register (c0);" // (placeholder for mask variable) "%s" // (placeholder for Linear/RadialGP-specific variables) "%s" "" // (placeholder for mask texcoord input) "void main(%s" " in float4 winCoord : TEXCOORD%d," " inout float4 color : COLOR0)" "{" " float dist;" // (placeholder for Linear/RadialGradientPaint-specific code) " %s" "" " float4 result;" // (placeholder for CycleMethod-specific code) " %s" "" // (placeholder for ColorSpace conversion code) " %s" "" // (placeholder for mask modulation code) " %s" "" // modulate with current color in order to apply extra alpha " color *= result;" "}"; /* * Note: An earlier version of this code would simply calculate a single * texcoord: * "tc = HALF_TEXEL + (FULL_TEXEL * relFraction);" * and then use that value to do a single texture lookup, taking advantage * of the LINEAR texture filtering mode which in theory will do the * appropriate linear interpolation between adjacent texels, like this: * "float4 result = tex2D(colors, float2(tc, 0.5));" * * The problem with that approach is that on certain hardware (from ATI, * notably) the LINEAR texture fetch unit has low precision, and would * for instance only produce 64 distinct grayscales between white and black, * instead of the expected 256. The visual banding caused by this issue * is severe enough to likely cause complaints from developers, so we have * devised a new approach below that instead manually fetches the two * relevant neighboring texels and then performs the linear interpolation * using the lerp() instruction (which does not suffer from the precision * issues of the fixed-function texture filtering unit). This new approach * requires a few more instructions and is therefore slightly slower than * the old approach (not more than 10% or so). */ static const char *texCoordCalcCode = "int i;" "float relFraction = 0.0;" "for (i = 0; i < MAX_FRACTIONS-1; i++) {" " relFraction +=" " clamp((dist - fractions[i].x) * fractions[i].y, 0.0, 1.0);" "}" // we offset by half a texel so that we find the linearly interpolated // color between the two texel centers of interest "float intPart = floor(relFraction);" "float tc1 = HALF_TEXEL + (FULL_TEXEL * intPart);" "float tc2 = HALF_TEXEL + (FULL_TEXEL * (intPart + 1.0));" "float4 clr1 = tex2D(colors, float2(tc1, 0.5));" "float4 clr2 = tex2D(colors, float2(tc2, 0.5));" "result = lerp(clr1, clr2, frac(relFraction));"; /** Code for NO_CYCLE that gets plugged into the CycleMethod placeholder. */ static const char *noCycleCode = "if (dist <= 0.0) {" " result = tex2D(colors, float2(0.0, 0.5));" "} else if (dist >= 1.0) {" " result = tex2D(colors, float2(1.0, 0.5));" "} else {" // (placeholder for texcoord calculation) " %s" "}"; /** Code for REFLECT that gets plugged into the CycleMethod placeholder. */ static const char *reflectCode = "dist = 1.0 - (abs(frac(dist * 0.5) - 0.5) * 2.0);" // (placeholder for texcoord calculation) "%s"; /** Code for REPEAT that gets plugged into the CycleMethod placeholder. */ static const char *repeatCode = "dist = frac(dist);" // (placeholder for texcoord calculation) "%s"; static void D3DShaderGen_GenerateMultiGradShader(int flags, char *name, char *paintVars, char *distCode) { char *maskVars = ""; char *maskInput = ""; char *maskCode = ""; char *colorSpaceCode = ""; char cycleCode[1500]; char finalSource[3000]; int colorSampler = IS_SET(MULTI_GRAD_USE_MASK) ? 1 : 0; int cycleMethod = EXTRACT_CYCLE_METHOD(flags); int maxFractions = IS_SET(MULTI_GRAD_LARGE) ? MAX_FRACTIONS_LARGE : MAX_FRACTIONS_SMALL; J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_CreateMultiGradProgram"); if (IS_SET(MULTI_GRAD_USE_MASK)) { /* * This code modulates the calculated result color with the * corresponding alpha value from the alpha mask texture active * on texture unit 0. Only needed when useMask is true (i.e., only * for MaskFill operations). */ maskVars = "sampler2D mask : register(s0);"; maskInput = "in float4 maskCoord : TEXCOORD0,"; maskCode = "result *= tex2D(mask, maskCoord.xy).a;"; } if (IS_SET(MULTI_GRAD_LINEAR_RGB)) { /* * This code converts a single pixel in linear RGB space back * into sRGB (note: this code was adapted from the * MultipleGradientPaintContext.convertLinearRGBtoSRGB() method). */ colorSpaceCode = "result.rgb = 1.055 * pow(result.rgb, 0.416667) - 0.055;"; } if (cycleMethod == CYCLE_NONE) { sprintf(cycleCode, noCycleCode, texCoordCalcCode); } else if (cycleMethod == CYCLE_REFLECT) { sprintf(cycleCode, reflectCode, texCoordCalcCode); } else { // (cycleMethod == CYCLE_REPEAT) sprintf(cycleCode, repeatCode, texCoordCalcCode); } // compose the final source code string from the various pieces sprintf(finalSource, multiGradientShaderSource, MAX_COLORS, maxFractions, colorSampler, maskVars, paintVars, maskInput, colorSampler, distCode, cycleCode, colorSpaceCode, maskCode); D3DShaderGen_WritePixelShader(finalSource, name, flags); } /********************** LinearGradientPaint support *************************/ static void D3DShaderGen_GenerateLinearGradShader(int flags) { char *paintVars; char *distCode; J2dTraceLn1(J2D_TRACE_INFO, "D3DShaderGen_GenerateLinearGradShader", flags); /* * To simplify the code and to make it easier to upload a number of * uniform values at once, we pack a bunch of scalar (float) values * into a single float3 below. Here's how the values are related: * * params.x = p0 * params.y = p1 * params.z = p3 */ paintVars = "float3 params : register(c16);"; distCode = "float3 fragCoord = float3(winCoord.x, winCoord.y, 1.0);" "dist = dot(params.xyz, fragCoord);"; D3DShaderGen_GenerateMultiGradShader(flags, "linear", paintVars, distCode); } /********************** RadialGradientPaint support *************************/ static void D3DShaderGen_GenerateRadialGradShader(int flags) { char *paintVars; char *distCode; J2dTraceLn1(J2D_TRACE_INFO, "D3DShaderGen_GenerateRadialGradShader", flags); /* * To simplify the code and to make it easier to upload a number of * uniform values at once, we pack a bunch of scalar (float) values * into float3 values below. Here's how the values are related: * * m0.x = m00 * m0.y = m01 * m0.z = m02 * * m1.x = m10 * m1.y = m11 * m1.z = m12 * * precalc.x = focusX * precalc.y = 1.0 - (focusX * focusX) * precalc.z = 1.0 / precalc.z */ paintVars = "float3 m0 : register(c16);" "float3 m1 : register(c17);" "float3 precalc : register(c18);"; /* * The following code is derived from Daniel Rice's whitepaper on * radial gradient performance (attached to the bug report for 6521533). * Refer to that document as well as the setup code in the Java-level * BufferedPaints.setRadialGradientPaint() method for more details. */ distCode = "float3 fragCoord = float3(winCoord.x, winCoord.y, 1.0);" "float x = dot(fragCoord, m0);" "float y = dot(fragCoord, m1);" "float xfx = x - precalc.x;" "dist = (precalc.x*xfx + sqrt(xfx*xfx + y*y*precalc.y))*precalc.z;"; D3DShaderGen_GenerateMultiGradShader(flags, "radial", paintVars, distCode); } /*************************** LCD text support *******************************/ // REMIND: Shader uses texture addressing operations in a dependency chain // that is too complex for the target shader model (ps_2_0) to handle // (ugh, I guess we can either require ps_3_0 or just use // the slower pow intrinsic) #define POW_LUT 0 static const char *lcdTextShaderSource = "float3 srcAdj : register(c0);" "sampler2D glyphTex : register(s0);" "sampler2D dstTex : register(s1);" #if POW_LUT "sampler3D invgammaTex : register(s2);" "sampler3D gammaTex : register(s3);" #else "float3 invgamma : register(c1);" "float3 gamma : register(c2);" #endif "" "void main(in float2 tc0 : TEXCOORD0," " in float2 tc1 : TEXCOORD1," " inout float4 color : COLOR0)" "{" // load the RGB value from the glyph image at the current texcoord " float3 glyphClr = tex2D(glyphTex, tc0).rgb;" " if (!any(glyphClr)) {" // zero coverage, so skip this fragment " discard;" " }" // load the RGB value from the corresponding destination pixel " float3 dstClr = tex2D(dstTex, tc1).rgb;" // gamma adjust the dest color using the invgamma LUT #if POW_LUT " float3 dstAdj = tex3D(invgammaTex, dstClr).rgb;" #else " float3 dstAdj = pow(dstClr, invgamma);" #endif // linearly interpolate the three color values " float3 result = lerp(dstAdj, srcAdj, glyphClr);" // gamma re-adjust the resulting color (alpha is always set to 1.0) #if POW_LUT " color = float4(tex3D(gammaTex, result).rgb, 1.0);" #else " color = float4(pow(result, gamma), 1.0);" #endif "}"; static void D3DShaderGen_GenerateLCDTextShader() { J2dTraceLn(J2D_TRACE_INFO, "D3DShaderGen_GenerateLCDTextShader"); D3DShaderGen_WritePixelShader((char *)lcdTextShaderSource, "lcdtext", 0); } /*************************** AA support *******************************/ /* * This shader fills the space between an outer and inner parallelogram. * It can be used to draw an outline by specifying both inner and outer * values. It fills pixels by estimating what portion falls inside the * outer shape, and subtracting an estimate of what portion falls inside * the inner shape. Specifying both inner and outer values produces a * standard "wide outline". Specifying an inner shape that falls far * outside the outer shape allows the same shader to fill the outer * shape entirely since pixels that fall within the outer shape are never * inside the inner shape and so they are filled based solely on their * coverage of the outer shape. * * The setup code renders this shader over the bounds of the outer * shape (or the only shape in the case of a fill operation) and * sets the texture 0 coordinates so that 0,0=>0,1=>1,1=>1,0 in those * texture coordinates map to the four corners of the parallelogram. * Similarly the texture 1 coordinates map the inner shape to the * unit square as well, but in a different coordinate system. * * When viewed in the texture coordinate systems the parallelograms * we are filling are unit squares, but the pixels have then become * tiny parallelograms themselves. Both of the texture coordinate * systems are affine transforms so the rate of change in X and Y * of the texture coordinates are essentially constants and happen * to correspond to the size and direction of the slanted sides of * the distorted pixels relative to the "square mapped" boundary * of the parallelograms. * * The shader uses the ddx() and ddy() functions to measure the "rate * of change" of these texture coordinates and thus gets an accurate * measure of the size and shape of a pixel relative to the two * parallelograms. It then uses the bounds of the size and shape * of a pixel to intersect with the unit square to estimate the * coverage of the pixel. Unfortunately, without a lot more work * to calculate the exact area of intersection between a unit * square (the original parallelogram) and a parallelogram (the * distorted pixel), this shader only approximates the pixel * coverage, but emperically the estimate is very useful and * produces visually pleasing results, if not theoretically accurate. */ static const char *aaShaderSource = "void main(in float2 tco : TEXCOORD0," " in float2 tci : TEXCOORD1," " inout float4 color : COLOR0)" "{" // Calculate the vectors for the "legs" of the pixel parallelogram // for the outer parallelogram. " float2 oleg1 = ddx(tco);" " float2 oleg2 = ddy(tco);" // Calculate the bounds of the distorted pixel parallelogram. " float2 omin = min(tco, tco+oleg1);" " omin = min(omin, tco+oleg2);" " omin = min(omin, tco+oleg1+oleg2);" " float2 omax = max(tco, tco+oleg1);" " omax = max(omax, tco+oleg2);" " omax = max(omax, tco+oleg1+oleg2);" // Calculate the vectors for the "legs" of the pixel parallelogram // for the inner parallelogram. " float2 ileg1 = ddx(tci);" " float2 ileg2 = ddy(tci);" // Calculate the bounds of the distorted pixel parallelogram. " float2 imin = min(tci, tci+ileg1);" " imin = min(imin, tci+ileg2);" " imin = min(imin, tci+ileg1+ileg2);" " float2 imax = max(tci, tci+ileg1);" " imax = max(imax, tci+ileg2);" " imax = max(imax, tci+ileg1+ileg2);" // Clamp the bounds of the parallelograms to the unit square to // estimate the intersection of the pixel parallelogram with // the unit square. The ratio of the 2 rectangle areas is a // reasonable estimate of the proportion of coverage. " float2 o1 = clamp(omin, 0.0, 1.0);" " float2 o2 = clamp(omax, 0.0, 1.0);" " float oint = (o2.y-o1.y)*(o2.x-o1.x);" " float oarea = (omax.y-omin.y)*(omax.x-omin.x);" " float2 i1 = clamp(imin, 0.0, 1.0);" " float2 i2 = clamp(imax, 0.0, 1.0);" " float iint = (i2.y-i1.y)*(i2.x-i1.x);" " float iarea = (imax.y-imin.y)*(imax.x-imin.x);" // Proportion of pixel in outer shape minus the proportion // of pixel in the inner shape == the coverage of the pixel // in the area between the two. " float coverage = oint/oarea - iint / iarea;" " color *= coverage;" "}"; static void D3DShaderGen_GenerateAAParallelogramShader() { J2dTraceLn(J2D_TRACE_INFO, "D3DShaderGen_GenerateAAParallelogramShader"); D3DShaderGen_WriteShader((char *)aaShaderSource, "ps_2_a", "aapgram", 0); } /**************************** Main entrypoint *******************************/ static void D3DShaderGen_GenerateAllShaders() { int i; #if 1 // Generate BufferedImageOp shaders for (i = 0; i < MAX_RESCALE; i++) { D3DShaderGen_GenerateRescaleShader(i); } D3DShaderGen_WriteShaderArray("rescale", MAX_RESCALE); for (i = 0; i < MAX_CONVOLVE; i++) { D3DShaderGen_GenerateConvolveShader(i); } D3DShaderGen_WriteShaderArray("convolve", MAX_CONVOLVE); for (i = 0; i < MAX_LOOKUP; i++) { D3DShaderGen_GenerateLookupShader(i); } D3DShaderGen_WriteShaderArray("lookup", MAX_LOOKUP); // Generate Paint shaders for (i = 0; i < MAX_BASIC_GRAD; i++) { D3DShaderGen_GenerateBasicGradShader(i); } D3DShaderGen_WriteShaderArray("grad", MAX_BASIC_GRAD); for (i = 0; i < MAX_MULTI_GRAD; i++) { if (EXTRACT_CYCLE_METHOD(i) == 3) continue; // REMIND D3DShaderGen_GenerateLinearGradShader(i); } D3DShaderGen_WriteShaderArray("linear", MAX_MULTI_GRAD); for (i = 0; i < MAX_MULTI_GRAD; i++) { if (EXTRACT_CYCLE_METHOD(i) == 3) continue; // REMIND D3DShaderGen_GenerateRadialGradShader(i); } D3DShaderGen_WriteShaderArray("radial", MAX_MULTI_GRAD); // Generate LCD text shader D3DShaderGen_GenerateLCDTextShader(); // Genereate Shader to fill Antialiased parallelograms D3DShaderGen_GenerateAAParallelogramShader(); #else /* for (i = 0; i < MAX_RESCALE; i++) { D3DShaderGen_GenerateRescaleShader(i); } D3DShaderGen_WriteShaderArray("rescale", MAX_RESCALE); */ //D3DShaderGen_GenerateConvolveShader(2); //D3DShaderGen_GenerateLCDTextShader(); //D3DShaderGen_GenerateLinearGradShader(16); D3DShaderGen_GenerateBasicGradShader(0); #endif } int main(int argc, char **argv) { fpHeader = fopen(strHeaderFile, "a"); D3DShaderGen_GenerateAllShaders(); fclose(fpHeader); return 0; }