| /* | |
| * 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 <stdio.h> | |
| #include <process.h> | |
| #include <Windows.h> | |
| 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]; | |
| snprintf(pargs, sizeof(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; | |
| snprintf(array, sizeof(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! | |
| snprintf(elem, sizeof(elem), " NULL,\n"); | |
| } else { | |
| snprintf(elem, sizeof(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 | |
| snprintf(finalSource, sizeof(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 | |
| snprintf(finalSource, sizeof(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 | |
| snprintf(finalSource, sizeof(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 | |
| snprintf(finalSource, sizeof(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) { | |
| snprintf(cycleCode, sizeof(cycleCode), noCycleCode, texCoordCalcCode); | |
| } else if (cycleMethod == CYCLE_REFLECT) { | |
| snprintf(cycleCode, sizeof(cycleCode), reflectCode, texCoordCalcCode); | |
| } else { // (cycleMethod == CYCLE_REPEAT) | |
| snprintf(cycleCode, sizeof(cycleCode), repeatCode, texCoordCalcCode); | |
| } | |
| // compose the final source code string from the various pieces | |
| snprintf(finalSource, sizeof(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(); | |
| // Generate 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; | |
| } |