mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Start adding HLSL support to the GLSL shader generator.
This commit is contained in:
parent
200c25bcc9
commit
984a4d2641
5 changed files with 228 additions and 128 deletions
|
@ -119,12 +119,13 @@ void GLSLShaderCompat::SetupForVulkan() {
|
|||
vulkan = true;
|
||||
forceMatrix4x4 = false;
|
||||
coefsFromBuffers = true;
|
||||
inPrefix = "";
|
||||
}
|
||||
|
||||
|
||||
void GLSLShaderCompat::SetupForD3D11() {
|
||||
fragColor0 = "fragColor0";
|
||||
fragColor1 = "fragColor1";
|
||||
fragColor0 = "outfragment.target";
|
||||
fragColor1 = "outfragment.target1";
|
||||
varying_fs = "in";
|
||||
varying_vs = "out";
|
||||
attribute = "in";
|
||||
|
@ -139,4 +140,5 @@ void GLSLShaderCompat::SetupForD3D11() {
|
|||
d3d11 = true;
|
||||
forceMatrix4x4 = false;
|
||||
coefsFromBuffers = true;
|
||||
inPrefix = "In.";
|
||||
}
|
||||
|
|
|
@ -144,6 +144,8 @@ struct GLSLShaderCompat {
|
|||
int glslVersionNumber;
|
||||
bool gles;
|
||||
bool vulkan;
|
||||
bool d3d11;
|
||||
bool d3d9;
|
||||
const char *varying_fs;
|
||||
const char *varying_vs;
|
||||
const char *attribute;
|
||||
|
@ -153,11 +155,11 @@ struct GLSLShaderCompat {
|
|||
const char *texelFetch;
|
||||
const char *lastFragData;
|
||||
const char *framebufferFetchExtension;
|
||||
const char *inPrefix;
|
||||
bool glslES30;
|
||||
bool bitwiseOps;
|
||||
bool forceMatrix4x4;
|
||||
bool coefsFromBuffers;
|
||||
bool d3d11;
|
||||
|
||||
void SetupForVulkan();
|
||||
void SetupForD3D11();
|
||||
|
|
|
@ -29,6 +29,23 @@
|
|||
|
||||
// #define DEBUG_SHADER
|
||||
|
||||
const char *hlsl_preamble =
|
||||
"#define vec2 float2\n"
|
||||
"#define vec3 float3\n"
|
||||
"#define vec4 float4\n"
|
||||
"#define uvec3 uint\n"
|
||||
"#define ivec3 int3\n"
|
||||
"#define splat3(x) float3(x, x, x)\n";
|
||||
|
||||
const char *hlsl_d3d11_preamble =
|
||||
"#define DISCARD discard\n"
|
||||
"#define DISCARD_BELOW(x) clip(x);\n";
|
||||
const char *hlsl_d3d9_preamble =
|
||||
"#define DISCARD clip(-1)\n"
|
||||
"#define DISCARD_BELOW(x) clip(x)\n";
|
||||
|
||||
const char *hlsl_late_preamble = "";
|
||||
|
||||
// Missing: Z depth range
|
||||
// Also, logic ops etc, of course, as they are not supported in DX9.
|
||||
bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguage lang, std::string *errorString) {
|
||||
|
@ -66,26 +83,24 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag
|
|||
|
||||
StencilValueType replaceAlphaWithStencilType = (StencilValueType)id.Bits(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE, 4);
|
||||
|
||||
WRITE(p, "%s", hlsl_preamble);
|
||||
|
||||
// Output some compatibility defines
|
||||
switch (lang) {
|
||||
case ShaderLanguage::HLSL_DX9:
|
||||
WRITE(p, "#define DISCARD clip(-1)\n");
|
||||
WRITE(p, hlsl_d3d9_preamble);
|
||||
break;
|
||||
case ShaderLanguage::HLSL_D3D11:
|
||||
WRITE(p, "#define DISCARD discard\n");
|
||||
WRITE(p, hlsl_d3d11_preamble);
|
||||
break;
|
||||
}
|
||||
WRITE(p, "#define vec2 float2\n");
|
||||
WRITE(p, "#define vec3 float3\n");
|
||||
WRITE(p, "#define vec4 float4\n");
|
||||
WRITE(p, "#define splat3(x) float3(x, x, x)\n");
|
||||
|
||||
if (lang == HLSL_DX9) {
|
||||
if (doTexture)
|
||||
WRITE(p, "sampler tex : register(s0);\n");
|
||||
if (!isModeClear && replaceBlend > REPLACE_BLEND_STANDARD) {
|
||||
if (replaceBlend == REPLACE_BLEND_COPY_FBO) {
|
||||
WRITE(p, "float2 u_fbotexSize : register(c%i);\n", CONST_PS_FBOTEXSIZE);
|
||||
WRITE(p, "vec2 u_fbotexSize : register(c%i);\n", CONST_PS_FBOTEXSIZE);
|
||||
WRITE(p, "sampler fbotex : register(s1);\n");
|
||||
}
|
||||
if (replaceBlendFuncA >= GE_SRCBLEND_FIXA) {
|
||||
|
@ -96,15 +111,15 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag
|
|||
}
|
||||
}
|
||||
if (gstate_c.needShaderTexClamp && doTexture) {
|
||||
WRITE(p, "float4 u_texclamp : register(c%i);\n", CONST_PS_TEXCLAMP);
|
||||
WRITE(p, "vec4 u_texclamp : register(c%i);\n", CONST_PS_TEXCLAMP);
|
||||
if (textureAtOffset) {
|
||||
WRITE(p, "float2 u_texclampoff : register(c%i);\n", CONST_PS_TEXCLAMPOFF);
|
||||
WRITE(p, "vec2 u_texclampoff : register(c%i);\n", CONST_PS_TEXCLAMPOFF);
|
||||
}
|
||||
}
|
||||
|
||||
if (enableAlphaTest || enableColorTest) {
|
||||
WRITE(p, "float4 u_alphacolorref : register(c%i);\n", CONST_PS_ALPHACOLORREF);
|
||||
WRITE(p, "float4 u_alphacolormask : register(c%i);\n", CONST_PS_ALPHACOLORMASK);
|
||||
WRITE(p, "vec4 u_alphacolorref : register(c%i);\n", CONST_PS_ALPHACOLORREF);
|
||||
WRITE(p, "vec4 u_alphacolormask : register(c%i);\n", CONST_PS_ALPHACOLORMASK);
|
||||
}
|
||||
if (stencilToAlpha && replaceAlphaWithStencilType == STENCIL_VALUE_UNIFORM) {
|
||||
WRITE(p, "float u_stencilReplaceValue : register(c%i);\n", CONST_PS_STENCILREPLACE);
|
||||
|
@ -117,11 +132,11 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag
|
|||
}
|
||||
} else {
|
||||
WRITE(p, "SamplerState samp : register(s0);\n");
|
||||
WRITE(p, "Texture2D<float4> tex : register(t0);\n");
|
||||
WRITE(p, "Texture2D<vec4> tex : register(t0);\n");
|
||||
if (!isModeClear && replaceBlend > REPLACE_BLEND_STANDARD) {
|
||||
if (replaceBlend == REPLACE_BLEND_COPY_FBO) {
|
||||
// No sampler required, we Load
|
||||
WRITE(p, "Texture2D<float4> fboTex : register(t1);\n");
|
||||
WRITE(p, "Texture2D<vec4> fboTex : register(t1);\n");
|
||||
}
|
||||
}
|
||||
WRITE(p, "cbuffer base : register(b0) {\n%s};\n", cb_baseStr);
|
||||
|
@ -139,54 +154,56 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag
|
|||
if (lang == HLSL_D3D11) {
|
||||
WRITE(p, "uint3 roundAndScaleTo255iv(float3 x) { return uint3(floor(x * 255.0f + 0.5f)); }\n");
|
||||
} else {
|
||||
WRITE(p, "float3 roundAndScaleTo255v(float3 x) { return floor(x * 255.0f + 0.5f); }\n");
|
||||
WRITE(p, "vec3 roundAndScaleTo255v(float3 x) { return floor(x * 255.0f + 0.5f); }\n");
|
||||
}
|
||||
}
|
||||
|
||||
WRITE(p, "struct PS_IN {\n");
|
||||
if (doTexture) {
|
||||
WRITE(p, " float3 v_texcoord: TEXCOORD0;\n");
|
||||
WRITE(p, " vec3 v_texcoord: TEXCOORD0;\n");
|
||||
}
|
||||
const char *colorInterpolation = doFlatShading && lang == HLSL_D3D11 ? "nointerpolation " : "";
|
||||
WRITE(p, " %sfloat4 v_color0: COLOR0;\n", colorInterpolation);
|
||||
WRITE(p, " %svec4 v_color0: COLOR0;\n", colorInterpolation);
|
||||
if (lmode) {
|
||||
WRITE(p, " float3 v_color1: COLOR1;\n");
|
||||
WRITE(p, " vec3 v_color1: COLOR1;\n");
|
||||
}
|
||||
if (enableFog) {
|
||||
WRITE(p, " float v_fogdepth: TEXCOORD1;\n");
|
||||
}
|
||||
if (lang == HLSL_D3D11 && ((replaceBlend == REPLACE_BLEND_COPY_FBO) || gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT))) {
|
||||
WRITE(p, " float4 pixelPos : SV_POSITION;\n");
|
||||
WRITE(p, " vec4 pixelPos : SV_POSITION;\n");
|
||||
}
|
||||
WRITE(p, "};\n");
|
||||
|
||||
if (lang == HLSL_DX9) {
|
||||
WRITE(p, "float4 main( PS_IN In ) : COLOR {\n");
|
||||
WRITE(p, "%s", hlsl_late_preamble);
|
||||
WRITE(p, "vec4 main( PS_IN In ) : COLOR {\n");
|
||||
} else {
|
||||
WRITE(p, "struct PS_OUT {\n");
|
||||
if (stencilToAlpha == REPLACE_ALPHA_DUALSOURCE) {
|
||||
WRITE(p, " float4 target : SV_Target0;\n");
|
||||
WRITE(p, " float4 target1 : SV_Target1;\n");
|
||||
WRITE(p, " vec4 target : SV_Target0;\n");
|
||||
WRITE(p, " vec4 target1 : SV_Target1;\n");
|
||||
}
|
||||
else {
|
||||
WRITE(p, " float4 target : SV_Target;\n");
|
||||
WRITE(p, " vec4 target : SV_Target;\n");
|
||||
}
|
||||
if (gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) {
|
||||
WRITE(p, " float depth : SV_DEPTH;\n");
|
||||
}
|
||||
WRITE(p, "};\n");
|
||||
WRITE(p, "%s", hlsl_late_preamble);
|
||||
WRITE(p, "PS_OUT main( PS_IN In ) {\n");
|
||||
WRITE(p, " PS_OUT outfragment;\n");
|
||||
}
|
||||
|
||||
if (isModeClear) {
|
||||
// Clear mode does not allow any fancy shading.
|
||||
WRITE(p, " float4 v = In.v_color0;\n");
|
||||
WRITE(p, " vec4 v = In.v_color0;\n");
|
||||
} else {
|
||||
const char *secondary = "";
|
||||
// Secondary color for specular on top of texture
|
||||
if (lmode) {
|
||||
WRITE(p, " float4 s = float4(In.v_color1, 0);\n");
|
||||
WRITE(p, " vec4 s = vec4(In.v_color1, 0.0);\n");
|
||||
secondary = " + s";
|
||||
} else {
|
||||
secondary = "";
|
||||
|
@ -221,7 +238,7 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag
|
|||
vcoord = "(" + vcoord + " + u_texclampoff.y)";
|
||||
}
|
||||
|
||||
WRITE(p, " float2 fixedcoord = float2(%s, %s);\n", ucoord.c_str(), vcoord.c_str());
|
||||
WRITE(p, " vec2 fixedcoord = vec2(%s, %s);\n", ucoord.c_str(), vcoord.c_str());
|
||||
texcoord = "fixedcoord";
|
||||
// We already projected it.
|
||||
doTextureProjection = false;
|
||||
|
@ -229,55 +246,55 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag
|
|||
|
||||
if (lang == HLSL_D3D11) {
|
||||
if (doTextureProjection) {
|
||||
WRITE(p, " float4 t = tex.Sample(samp, In.v_texcoord.xy / In.v_texcoord.z)%s;\n", bgraTexture ? ".bgra" : "");
|
||||
WRITE(p, " vec4 t = tex.Sample(samp, In.v_texcoord.xy / In.v_texcoord.z)%s;\n", bgraTexture ? ".bgra" : "");
|
||||
} else {
|
||||
WRITE(p, " float4 t = tex.Sample(samp, %s.xy)%s;\n", texcoord, bgraTexture ? ".bgra" : "");
|
||||
WRITE(p, " vec4 t = tex.Sample(samp, %s.xy)%s;\n", texcoord, bgraTexture ? ".bgra" : "");
|
||||
}
|
||||
} else {
|
||||
if (doTextureProjection) {
|
||||
WRITE(p, " float4 t = tex2Dproj(tex, float4(In.v_texcoord.x, In.v_texcoord.y, 0, In.v_texcoord.z))%s;\n", bgraTexture ? ".bgra" : "");
|
||||
WRITE(p, " vec4 t = tex2Dproj(tex, vec4(v_texcoord.x, v_texcoord.y, 0, v_texcoord.z))%s;\n", bgraTexture ? ".bgra" : "");
|
||||
} else {
|
||||
WRITE(p, " float4 t = tex2D(tex, %s.xy)%s;\n", texcoord, bgraTexture ? ".bgra" : "");
|
||||
WRITE(p, " vec4 t = tex2D(tex, %s.xy)%s;\n", texcoord, bgraTexture ? ".bgra" : "");
|
||||
}
|
||||
}
|
||||
WRITE(p, " float4 p = In.v_color0;\n");
|
||||
WRITE(p, " vec4 p = In.v_color0;\n");
|
||||
|
||||
if (doTextureAlpha) { // texfmt == RGBA
|
||||
switch (texFunc) {
|
||||
case GE_TEXFUNC_MODULATE:
|
||||
WRITE(p, " float4 v = p * t%s;\n", secondary); break;
|
||||
WRITE(p, " vec4 v = p * t%s;\n", secondary); break;
|
||||
case GE_TEXFUNC_DECAL:
|
||||
WRITE(p, " float4 v = float4(lerp(p.rgb, t.rgb, t.a), p.a)%s;\n", secondary); break;
|
||||
WRITE(p, " vec4 v = vec4(lerp(p.rgb, t.rgb, t.a), p.a)%s;\n", secondary); break;
|
||||
case GE_TEXFUNC_BLEND:
|
||||
WRITE(p, " float4 v = float4(lerp(p.rgb, u_texenv.rgb, t.rgb), p.a * t.a)%s;\n", secondary); break;
|
||||
WRITE(p, " vec4 v = vec4(lerp(p.rgb, u_texenv.rgb, t.rgb), p.a * t.a)%s;\n", secondary); break;
|
||||
case GE_TEXFUNC_REPLACE:
|
||||
WRITE(p, " float4 v = t%s;\n", secondary); break;
|
||||
WRITE(p, " vec4 v = t%s;\n", secondary); break;
|
||||
case GE_TEXFUNC_ADD:
|
||||
case GE_TEXFUNC_UNKNOWN1:
|
||||
case GE_TEXFUNC_UNKNOWN2:
|
||||
case GE_TEXFUNC_UNKNOWN3:
|
||||
WRITE(p, " float4 v = float4(p.rgb + t.rgb, p.a * t.a)%s;\n", secondary); break;
|
||||
WRITE(p, " vec4 v = vec4(p.rgb + t.rgb, p.a * t.a)%s;\n", secondary); break;
|
||||
default:
|
||||
WRITE(p, " float4 v = p;\n"); break;
|
||||
WRITE(p, " vec4 v = p;\n"); break;
|
||||
}
|
||||
|
||||
} else { // texfmt == RGB
|
||||
switch (texFunc) {
|
||||
case GE_TEXFUNC_MODULATE:
|
||||
WRITE(p, " float4 v = float4(t.rgb * p.rgb, p.a)%s;\n", secondary); break;
|
||||
WRITE(p, " vec4 v = vec4(t.rgb * p.rgb, p.a)%s;\n", secondary); break;
|
||||
case GE_TEXFUNC_DECAL:
|
||||
WRITE(p, " float4 v = float4(t.rgb, p.a)%s;\n", secondary); break;
|
||||
WRITE(p, " vec4 v = vec4(t.rgb, p.a)%s;\n", secondary); break;
|
||||
case GE_TEXFUNC_BLEND:
|
||||
WRITE(p, " float4 v = float4(lerp(p.rgb, u_texenv.rgb, t.rgb), p.a)%s;\n", secondary); break;
|
||||
WRITE(p, " vec4 v = vec4(lerp(p.rgb, u_texenv.rgb, t.rgb), p.a)%s;\n", secondary); break;
|
||||
case GE_TEXFUNC_REPLACE:
|
||||
WRITE(p, " float4 v = float4(t.rgb, p.a)%s;\n", secondary); break;
|
||||
WRITE(p, " vec4 v = vec4(t.rgb, p.a)%s;\n", secondary); break;
|
||||
case GE_TEXFUNC_ADD:
|
||||
case GE_TEXFUNC_UNKNOWN1:
|
||||
case GE_TEXFUNC_UNKNOWN2:
|
||||
case GE_TEXFUNC_UNKNOWN3:
|
||||
WRITE(p, " float4 v = float4(p.rgb + t.rgb, p.a)%s;\n", secondary); break;
|
||||
WRITE(p, " vec4 v = vec4(p.rgb + t.rgb, p.a)%s;\n", secondary); break;
|
||||
default:
|
||||
WRITE(p, " float4 v = p;\n"); break;
|
||||
WRITE(p, " vec4 v = p;\n"); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -287,12 +304,12 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag
|
|||
}
|
||||
} else {
|
||||
// No texture mapping
|
||||
WRITE(p, " float4 v = In.v_color0 %s;\n", secondary);
|
||||
WRITE(p, " vec4 v = In.v_color0 %s;\n", secondary);
|
||||
}
|
||||
|
||||
if (enableFog) {
|
||||
WRITE(p, " float fogCoef = clamp(In.v_fogdepth, 0.0, 1.0);\n");
|
||||
WRITE(p, " v = lerp(float4(u_fogcolor, v.a), v, fogCoef);\n");
|
||||
WRITE(p, " v = lerp(vec4(u_fogcolor, v.a), v, fogCoef);\n");
|
||||
}
|
||||
|
||||
if (enableAlphaTest) {
|
||||
|
@ -352,7 +369,7 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag
|
|||
WRITE(p, " if (v_masked.r %s colorTestRef.r && v_masked.g %s colorTestRef.g && v_masked.b %s colorTestRef.b) DISCARD;\n", test, test, test);
|
||||
} else {
|
||||
// TODO: Use a texture to lookup bitwise ops instead?
|
||||
WRITE(p, " float3 colortest = roundAndScaleTo255v(v.rgb);\n");
|
||||
WRITE(p, " vec3 colortest = roundAndScaleTo255v(v.rgb);\n");
|
||||
WRITE(p, " if ((colortest.r %s u_alphacolorref.r) && (colortest.g %s u_alphacolorref.g) && (colortest.b %s u_alphacolorref.b)) DISCARD;\n", test, test, test);
|
||||
}
|
||||
}
|
||||
|
@ -393,7 +410,7 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag
|
|||
}
|
||||
|
||||
if (lang == HLSL_D3D11 && replaceBlend == REPLACE_BLEND_COPY_FBO) {
|
||||
WRITE(p, " float4 destColor = fboTex.Load(int3((int)In.pixelPos.x, (int)In.pixelPos.y, 0));\n");
|
||||
WRITE(p, " vec4 destColor = fboTex.Load(int3((int)In.pixelPos.x, (int)In.pixelPos.y, 0));\n");
|
||||
|
||||
const char *srcFactor = nullptr;
|
||||
const char *dstFactor = nullptr;
|
||||
|
@ -403,7 +420,7 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag
|
|||
case GE_SRCBLEND_INVDSTCOLOR: srcFactor = "(splat3(1.0) - destColor.rgb)"; break;
|
||||
case GE_SRCBLEND_SRCALPHA: srcFactor = "v.aaa"; break;
|
||||
case GE_SRCBLEND_INVSRCALPHA: srcFactor = "splat3(1.0) - v.aaa"; break;
|
||||
case GE_SRCBLEND_DSTALPHA: srcFactor = "float3(destColor.aaa)"; break;
|
||||
case GE_SRCBLEND_DSTALPHA: srcFactor = "destColor.aaa"; break;
|
||||
case GE_SRCBLEND_INVDSTALPHA: srcFactor = "splat3(1.0) - destColor.aaa"; break;
|
||||
case GE_SRCBLEND_DOUBLESRCALPHA: srcFactor = "v.aaa * 2.0"; break;
|
||||
case GE_SRCBLEND_DOUBLEINVSRCALPHA: srcFactor = "splat3(1.0) - v.aaa * 2.0"; break;
|
||||
|
@ -540,8 +557,8 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag
|
|||
|
||||
if (lang == HLSL_D3D11) {
|
||||
if (stencilToAlpha == REPLACE_ALPHA_DUALSOURCE) {
|
||||
WRITE(p, " outfragment.target = float4(v.rgb, %s);\n", replacedAlpha.c_str());
|
||||
WRITE(p, " outfragment.target1 = float4(0.0, 0.0, 0.0, v.a);\n");
|
||||
WRITE(p, " outfragment.target = vec4(v.rgb, %s);\n", replacedAlpha.c_str());
|
||||
WRITE(p, " outfragment.target1 = vec4(0.0, 0.0, 0.0, v.a);\n");
|
||||
WRITE(p, " return outfragment;\n");
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -40,7 +40,16 @@ static const char *vulkan_glsl_preamble =
|
|||
"#extension GL_ARB_shading_language_420pack : enable\n"
|
||||
"#extension GL_ARB_conservative_depth : enable\n"
|
||||
"#extension GL_ARB_shader_image_load_store : enable\n"
|
||||
"#define splat3(x) vec3(x)\n\n";
|
||||
"#define splat3(x) vec3(x)\n"
|
||||
"#define lowp\n"
|
||||
"#define mediump\n"
|
||||
"#define highp\n"
|
||||
"#define DISCARD discard\n"
|
||||
"\n";
|
||||
extern const char *hlsl_preamble;
|
||||
extern const char *hlsl_d3d9_preamble;
|
||||
extern const char *hlsl_d3d11_preamble;
|
||||
extern const char *hlsl_late_preamble;
|
||||
|
||||
bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, const GLSLShaderCompat &compat, uint64_t *uniformMask, std::string *errorString) {
|
||||
*uniformMask = 0;
|
||||
|
@ -62,11 +71,15 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, const GLSLSha
|
|||
|
||||
if (compat.vulkan) {
|
||||
WRITE(p, "%s", vulkan_glsl_preamble);
|
||||
WRITE(p, "#define lowp\n");
|
||||
WRITE(p, "#define mediump\n");
|
||||
WRITE(p, "#define highp\n");
|
||||
} else if (compat.d3d11) {
|
||||
WRITE(p, "%s", hlsl_preamble);
|
||||
WRITE(p, "%s", hlsl_d3d11_preamble);
|
||||
} else if (compat.d3d9) {
|
||||
WRITE(p, "%s", hlsl_preamble);
|
||||
WRITE(p, "%s", hlsl_d3d9_preamble);
|
||||
} else {
|
||||
WRITE(p, "#version %d%s\n", compat.glslVersionNumber, compat.gles ? " es" : "");
|
||||
WRITE(p, "#define DISCARD discard\n");
|
||||
|
||||
if (stencilToAlpha == REPLACE_ALPHA_DUALSOURCE && gl_extensions.EXT_blend_func_extended) {
|
||||
WRITE(p, "#extension GL_EXT_blend_func_extended : require\n");
|
||||
|
@ -102,6 +115,7 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, const GLSLSha
|
|||
bool doTextureAlpha = id.Bit(FS_BIT_TEXALPHA);
|
||||
bool doFlatShading = id.Bit(FS_BIT_FLATSHADE);
|
||||
bool shaderDepal = id.Bit(FS_BIT_SHADER_DEPAL);
|
||||
bool bgraTexture = id.Bit(FS_BIT_BGRA_TEXTURE);
|
||||
|
||||
GEComparison alphaTestFunc = (GEComparison)id.Bits(FS_BIT_ALPHA_TEST_FUNC, 3);
|
||||
GEComparison colorTestFunc = (GEComparison)id.Bits(FS_BIT_COLOR_TEST_FUNC, 2);
|
||||
|
@ -169,6 +183,52 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, const GLSLSha
|
|||
if (stencilToAlpha == REPLACE_ALPHA_DUALSOURCE) {
|
||||
WRITE(p, "layout (location = 0, index = 1) out vec4 fragColor1;\n");
|
||||
}
|
||||
} else if (compat.d3d11) {
|
||||
WRITE(p, "SamplerState samp : register(s0);\n");
|
||||
WRITE(p, "Texture2D<vec4> tex : register(t0);\n");
|
||||
if (!isModeClear && replaceBlend > REPLACE_BLEND_STANDARD) {
|
||||
if (replaceBlend == REPLACE_BLEND_COPY_FBO) {
|
||||
// No sampler required, we Load
|
||||
WRITE(p, "Texture2D<vec4> fboTex : register(t1);\n");
|
||||
}
|
||||
}
|
||||
WRITE(p, "cbuffer base : register(b0) {\n%s};\n", cb_baseStr);
|
||||
|
||||
if (enableAlphaTest) {
|
||||
WRITE(p, "int roundAndScaleTo255i(float x) { return int(floor(x * 255.0f + 0.5f)); }\n");
|
||||
}
|
||||
if (enableColorTest) {
|
||||
WRITE(p, "uvec3 roundAndScaleTo255iv(float3 x) { return uvec3(floor(x * 255.0f + 0.5f)); }\n");
|
||||
}
|
||||
|
||||
WRITE(p, "struct PS_IN {\n");
|
||||
if (doTexture) {
|
||||
WRITE(p, " vec3 v_texcoord: TEXCOORD0;\n");
|
||||
}
|
||||
const char *colorInterpolation = doFlatShading ? "nointerpolation " : "";
|
||||
WRITE(p, " %svec4 v_color0: COLOR0;\n", colorInterpolation);
|
||||
if (lmode) {
|
||||
WRITE(p, " vec3 v_color1: COLOR1;\n");
|
||||
}
|
||||
if (enableFog) {
|
||||
WRITE(p, " float v_fogdepth: TEXCOORD1;\n");
|
||||
}
|
||||
if ((replaceBlend == REPLACE_BLEND_COPY_FBO) || gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) {
|
||||
WRITE(p, " vec4 pixelPos : SV_POSITION;\n");
|
||||
}
|
||||
WRITE(p, "};\n");
|
||||
|
||||
WRITE(p, "struct PS_OUT {\n");
|
||||
if (stencilToAlpha == REPLACE_ALPHA_DUALSOURCE) {
|
||||
WRITE(p, " vec4 target : SV_Target0;\n");
|
||||
WRITE(p, " vec4 target1 : SV_Target1;\n");
|
||||
} else {
|
||||
WRITE(p, " vec4 target : SV_Target;\n");
|
||||
}
|
||||
if (gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) {
|
||||
WRITE(p, " float depth : SV_DEPTH;\n");
|
||||
}
|
||||
WRITE(p, "};\n");
|
||||
} else {
|
||||
if (shaderDepal && gl_extensions.IsGLES) {
|
||||
WRITE(p, "precision highp int;\n");
|
||||
|
@ -283,22 +343,28 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, const GLSLSha
|
|||
WRITE(p, "float mymod(float a, float b) { return a - b * floor(a / b); }\n");
|
||||
}
|
||||
|
||||
WRITE(p, "void main() {\n");
|
||||
if (compat.d3d11) {
|
||||
WRITE(p, "%s", hlsl_late_preamble);
|
||||
WRITE(p, "PS_OUT main( PS_IN In ) {\n");
|
||||
WRITE(p, " PS_OUT outfragment;\n");
|
||||
} else {
|
||||
WRITE(p, "void main() {\n");
|
||||
}
|
||||
if (isModeClear) {
|
||||
// Clear mode does not allow any fancy shading.
|
||||
WRITE(p, " vec4 v = v_color0;\n");
|
||||
WRITE(p, " vec4 v = %sv_color0;\n", compat.inPrefix);
|
||||
} else {
|
||||
const char *secondary = "";
|
||||
// Secondary color for specular on top of texture
|
||||
if (lmode) {
|
||||
WRITE(p, " vec4 s = vec4(v_color1, 0.0);\n");
|
||||
WRITE(p, " vec4 s = vec4(%sv_color1, 0.0);\n", compat.inPrefix);
|
||||
secondary = " + s";
|
||||
} else {
|
||||
secondary = "";
|
||||
}
|
||||
|
||||
if (doTexture) {
|
||||
const char *texcoord = "v_texcoord";
|
||||
std::string texcoord = std::string(compat.inPrefix) + "v_texcoord";
|
||||
// TODO: Not sure the right way to do this for projection.
|
||||
// This path destroys resolution on older PowerVR no matter what I do if projection is needed,
|
||||
// so we disable it on SGX 540 and lesser, and live with the consequences.
|
||||
|
@ -312,11 +378,11 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, const GLSLSha
|
|||
// We may be clamping inside a larger surface (tex = 64x64, buffer=480x272).
|
||||
// We may also be wrapping in such a surface, or either one in a too-small surface.
|
||||
// Obviously, clamping to a smaller surface won't work. But better to clamp to something.
|
||||
std::string ucoord = "v_texcoord.x";
|
||||
std::string vcoord = "v_texcoord.y";
|
||||
std::string ucoord = std::string(compat.inPrefix) + "v_texcoord.x";
|
||||
std::string vcoord = std::string(compat.inPrefix) + "v_texcoord.y";
|
||||
if (doTextureProjection) {
|
||||
ucoord = "(v_texcoord.x / v_texcoord.z)";
|
||||
vcoord = "(v_texcoord.y / v_texcoord.z)";
|
||||
ucoord = StringFromFormat("(%sv_texcoord.x / %sv_texcoord.z)", compat.inPrefix, compat.inPrefix);
|
||||
vcoord = StringFromFormat("(%sv_texcoord.y / %sv_texcoord.z)", compat.inPrefix, compat.inPrefix);
|
||||
}
|
||||
|
||||
std::string modulo = (gl_extensions.bugs & BUG_PVR_SHADER_PRECISION_BAD) ? "mymod" : "mod";
|
||||
|
@ -343,18 +409,26 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, const GLSLSha
|
|||
}
|
||||
|
||||
if (!shaderDepal) {
|
||||
if (doTextureProjection) {
|
||||
WRITE(p, " vec4 t = %sProj(tex, %s);\n", compat.texture, texcoord);
|
||||
if (compat.d3d11) {
|
||||
if (doTextureProjection) {
|
||||
WRITE(p, " vec4 t = tex.Sample(samp, v_texcoord.xy / v_texcoord.z)%s;\n", bgraTexture ? ".bgra" : "");
|
||||
} else {
|
||||
WRITE(p, " vec4 t = tex.Sample(samp, %s.xy)%s;\n", texcoord.c_str(), bgraTexture ? ".bgra" : "");
|
||||
}
|
||||
} else {
|
||||
WRITE(p, " vec4 t = %s(tex, %s.xy);\n", compat.texture, texcoord);
|
||||
if (doTextureProjection) {
|
||||
WRITE(p, " vec4 t = %sProj(tex, %s);\n", compat.texture, texcoord.c_str());
|
||||
} else {
|
||||
WRITE(p, " vec4 t = %s(tex, %s.xy);\n", compat.texture, texcoord.c_str());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (doTextureProjection) {
|
||||
// We don't use textureProj because we need better control and it's probably not much of a savings anyway.
|
||||
// However it is good for precision on older hardware like PowerVR.
|
||||
WRITE(p, " vec2 uv = %s.xy/%s.z;\n vec2 uv_round;\n", texcoord, texcoord);
|
||||
WRITE(p, " vec2 uv = %s.xy/%s.z;\n vec2 uv_round;\n", texcoord.c_str(), texcoord.c_str());
|
||||
} else {
|
||||
WRITE(p, " vec2 uv = %s.xy;\n vec2 uv_round;\n", texcoord);
|
||||
WRITE(p, " vec2 uv = %s.xy;\n vec2 uv_round;\n", texcoord.c_str());
|
||||
}
|
||||
WRITE(p, " vec2 tsize = vec2(textureSize(tex, 0));\n");
|
||||
WRITE(p, " vec2 fraction;\n");
|
||||
|
@ -441,7 +515,7 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, const GLSLSha
|
|||
}
|
||||
|
||||
if (texFunc != GE_TEXFUNC_REPLACE || !doTextureAlpha)
|
||||
WRITE(p, " vec4 p = v_color0;\n");
|
||||
WRITE(p, " vec4 p = %sv_color0;\n", compat.inPrefix);
|
||||
|
||||
if (doTextureAlpha) { // texfmt == RGBA
|
||||
switch (texFunc) {
|
||||
|
@ -504,11 +578,11 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, const GLSLSha
|
|||
}
|
||||
} else {
|
||||
// No texture mapping
|
||||
WRITE(p, " vec4 v = v_color0 %s;\n", secondary);
|
||||
WRITE(p, " vec4 v = %sv_color0 %s;\n", compat.inPrefix, secondary);
|
||||
}
|
||||
|
||||
if (enableFog) {
|
||||
WRITE(p, " float fogCoef = clamp(v_fogdepth, 0.0, 1.0);\n");
|
||||
WRITE(p, " float fogCoef = clamp(%sv_fogdepth, 0.0, 1.0);\n", compat.inPrefix);
|
||||
WRITE(p, " v = mix(vec4(u_fogcolor, v.a), v, fogCoef);\n");
|
||||
// WRITE(p, " v.x = v_depth;\n");
|
||||
}
|
||||
|
@ -527,7 +601,7 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, const GLSLSha
|
|||
}
|
||||
}
|
||||
|
||||
const char *discardStatement = testForceToZero ? "v.a = 0.0;" : "discard;";
|
||||
const char *discardStatement = testForceToZero ? "v.a = 0.0;" : "DISCARD;";
|
||||
if (enableAlphaTest) {
|
||||
if (alphaTestAgainstZero) {
|
||||
// When testing against 0 (extremely common), we can avoid some math.
|
||||
|
@ -814,6 +888,10 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, const GLSLSha
|
|||
WRITE(p, " gl_FragDepth = gl_FragCoord.z;\n");
|
||||
}
|
||||
|
||||
if (compat.d3d11) {
|
||||
WRITE(p, " return outfragment;\n");
|
||||
}
|
||||
|
||||
WRITE(p, "}\n");
|
||||
|
||||
return true;
|
||||
|
|
|
@ -43,7 +43,7 @@ bool GenerateFShader(FShaderID id, char *buffer, ShaderLanguage lang, std::strin
|
|||
case ShaderLanguage::HLSL_D3D11_TEST:
|
||||
{
|
||||
GLSLShaderCompat compat{};
|
||||
compat.SetupForVulkan();
|
||||
compat.SetupForD3D11();
|
||||
uint64_t uniformMask;
|
||||
return GenerateFragmentShaderGLSL(id, buffer, compat, &uniformMask, errorString);
|
||||
}
|
||||
|
@ -162,6 +162,60 @@ bool TestShaderGenerators() {
|
|||
int successes = 0;
|
||||
int count = 700;
|
||||
|
||||
// Generate a bunch of random fragment shader IDs, try to generate shader source.
|
||||
// Then compile it and check that it's ok.
|
||||
for (int i = 0; i < count; i++) {
|
||||
uint32_t bottom = rng.R32();
|
||||
uint32_t top = rng.R32();
|
||||
FShaderID id;
|
||||
id.d[0] = bottom;
|
||||
id.d[1] = top;
|
||||
|
||||
// bits we don't need to test because they are irrelevant on d3d11
|
||||
id.SetBit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL, false);
|
||||
|
||||
bool generateSuccess[numLanguages]{};
|
||||
std::string genErrorString[numLanguages];
|
||||
|
||||
for (int j = 0; j < numLanguages; j++) {
|
||||
generateSuccess[j] = GenerateFShader(id, buffer[j], languages[j], &genErrorString[j]);
|
||||
if (!genErrorString[j].empty()) {
|
||||
printf("%s\n", genErrorString[j].c_str());
|
||||
}
|
||||
// We ignore the contents of the error string here, not even gonna try to compile if it errors.
|
||||
}
|
||||
|
||||
// KEEPING FOR REUSE LATER: Defunct temporary test.
|
||||
if (generateSuccess[0] != generateSuccess[1]) {
|
||||
printf("mismatching success! %s %s\n", genErrorString[0].c_str(), genErrorString[1].c_str());
|
||||
printf("%s\n", buffer[0]);
|
||||
printf("%s\n", buffer[1]);
|
||||
return 1;
|
||||
}
|
||||
if (generateSuccess[0] && strcmp(buffer[0], buffer[1])) {
|
||||
printf("mismatching shaders! a=glsl b=hlsl\n");
|
||||
PrintDiff(buffer[0], buffer[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Now that we have the strings ready for easy comparison (buffer,4 in the watch window),
|
||||
// let's try to compile them.
|
||||
for (int j = 0; j < numLanguages; j++) {
|
||||
if (generateSuccess[j]) {
|
||||
if (!TestCompileShader(buffer[j], languages[j], false)) {
|
||||
printf("Error compiling fragment shader:\n\n%s\n\n", LineNumberString(buffer[j]).c_str());
|
||||
return false;
|
||||
}
|
||||
successes++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("%d/%d fragment shaders generated (it's normal that it's not all, there are invalid bit combos)\n", successes, count * numLanguages);
|
||||
|
||||
successes = 0;
|
||||
count = 200;
|
||||
|
||||
// Generate a bunch of random vertex shader IDs, try to generate shader source.
|
||||
// Then compile it and check that it's ok.
|
||||
for (int i = 0; i < count; i++) {
|
||||
|
@ -189,7 +243,7 @@ bool TestShaderGenerators() {
|
|||
return false;
|
||||
}
|
||||
if (generateSuccess[0] && strcmp(buffer[0], buffer[1])) {
|
||||
printf("mismatching shaders! a=glsl b=vulkan\n");
|
||||
printf("mismatching shaders!\n");
|
||||
PrintDiff(buffer[0], buffer[1]);
|
||||
return false;
|
||||
}
|
||||
|
@ -213,59 +267,6 @@ bool TestShaderGenerators() {
|
|||
successes = 0;
|
||||
count = 200;
|
||||
|
||||
// Generate a bunch of random fragment shader IDs, try to generate shader source.
|
||||
// Then compile it and check that it's ok.
|
||||
for (int i = 0; i < count; i++) {
|
||||
uint32_t bottom = rng.R32();
|
||||
uint32_t top = rng.R32();
|
||||
FShaderID id;
|
||||
id.d[0] = bottom;
|
||||
id.d[1] = top;
|
||||
|
||||
bool generateSuccess[numLanguages]{};
|
||||
std::string genErrorString[numLanguages];
|
||||
|
||||
for (int j = 0; j < numLanguages; j++) {
|
||||
generateSuccess[j] = GenerateFShader(id, buffer[j], languages[j], &genErrorString[j]);
|
||||
if (!genErrorString[j].empty()) {
|
||||
printf("%s\n", genErrorString[j].c_str());
|
||||
}
|
||||
// We ignore the contents of the error string here, not even gonna try to compile if it errors.
|
||||
}
|
||||
|
||||
/*
|
||||
// KEEPING FOR REUSE LATER: Defunct temporary test: Compare GLSL-in-Vulkan-mode vs Vulkan
|
||||
if (generateSuccess[0] != generateSuccess[1]) {
|
||||
printf("mismatching success! %s %s\n", genErrorString[0].c_str(), genErrorString[1].c_str());
|
||||
printf("%s\n", buffer[0]);
|
||||
printf("%s\n", buffer[1]);
|
||||
return 1;
|
||||
}
|
||||
if (generateSuccess[0] && strcmp(buffer[0], buffer[1])) {
|
||||
printf("mismatching shaders!\n");
|
||||
PrintDiff(buffer[0], buffer[1]);
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
|
||||
// Now that we have the strings ready for easy comparison (buffer,4 in the watch window),
|
||||
// let's try to compile them.
|
||||
for (int j = 0; j < numLanguages; j++) {
|
||||
if (generateSuccess[j]) {
|
||||
if (!TestCompileShader(buffer[j], languages[j], false)) {
|
||||
printf("Error compiling fragment shader:\n\n%s\n\n", LineNumberString(buffer[j]).c_str());
|
||||
return false;
|
||||
}
|
||||
successes++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("%d/%d fragment shaders generated (it's normal that it's not all, there are invalid bit combos)\n", successes, count * numLanguages);
|
||||
|
||||
successes = 0;
|
||||
count = 200;
|
||||
|
||||
for (int i = 0; i < numLanguages; i++) {
|
||||
delete[] buffer[i];
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue