@@ -59,7 +59,7 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,

out.Write("// Pixel UberShader for %u texgens%s%s\n", numTexgen,
early_depth ? ", early-depth" : "", per_pixel_depth ? ", per-pixel depth" : "");
WritePixelShaderCommonHeader(out, ApiType, numTexgen, per_pixel_lighting, bounding_box);
WritePixelShaderCommonHeader(out, ApiType, numTexgen, host_config, bounding_box);
WriteUberShaderCommonHeader(out, ApiType, host_config);
if (per_pixel_lighting)
WriteLightingFunction(out);
@@ -103,10 +103,10 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
if (per_pixel_depth)
out.Write("#define depth gl_FragDepth\n");

if (host_config.backend_geometry_shaders || ApiType == APIType::Vulkan)
if (host_config.backend_geometry_shaders)
{
out.Write("VARYING_LOCATION(0) in VertexData {\n");
GenerateVSOutputMembers(out, ApiType, numTexgen, per_pixel_lighting,
GenerateVSOutputMembers(out, ApiType, numTexgen, host_config,
GetInterpolationQualifier(msaa, ssaa, true, true));

if (stereo)
@@ -116,17 +116,26 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
}
else
{
out.Write("%s in float4 colors_0;\n", GetInterpolationQualifier(msaa, ssaa));
out.Write("%s in float4 colors_1;\n", GetInterpolationQualifier(msaa, ssaa));
// compute window position if needed because binding semantic WPOS is not widely supported
// Let's set up attributes
for (u32 i = 0; i < numTexgen; ++i)
out.Write("%s in float3 tex%d;\n", GetInterpolationQualifier(msaa, ssaa), i);
out.Write("%s in float4 clipPos;\n", GetInterpolationQualifier(msaa, ssaa));
u32 counter = 0;
out.Write("VARYING_LOCATION(%u) %s in float4 colors_0;\n", counter++,
GetInterpolationQualifier(msaa, ssaa));
out.Write("VARYING_LOCATION(%u) %s in float4 colors_1;\n", counter++,
GetInterpolationQualifier(msaa, ssaa));
for (unsigned int i = 0; i < numTexgen; ++i)
{
out.Write("VARYING_LOCATION(%u) %s in float3 tex%d;\n", counter++,
GetInterpolationQualifier(msaa, ssaa), i);
}
if (!host_config.fast_depth_calc)
out.Write("VARYING_LOCATION(%u) %s in float4 clipPos;\n", counter++,
GetInterpolationQualifier(msaa, ssaa));
if (per_pixel_lighting)
{
out.Write("%s in float3 Normal;\n", GetInterpolationQualifier(msaa, ssaa));
out.Write("%s in float3 WorldPos;\n", GetInterpolationQualifier(msaa, ssaa));
out.Write("VARYING_LOCATION(%u) %s in float3 Normal;\n", counter++,
GetInterpolationQualifier(msaa, ssaa));
out.Write("VARYING_LOCATION(%u) %s in float3 WorldPos;\n", counter++,
GetInterpolationQualifier(msaa, ssaa));
}
}
}
@@ -709,8 +718,11 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
for (u32 i = 0; i < numTexgen; ++i)
out.Write(",\n in %s float3 tex%u : TEXCOORD%u", GetInterpolationQualifier(msaa, ssaa), i,
i);
out.Write("\n,\n in %s float4 clipPos : TEXCOORD%u", GetInterpolationQualifier(msaa, ssaa),
numTexgen);
if (!host_config.fast_depth_calc)
{
out.Write("\n,\n in %s float4 clipPos : TEXCOORD%u", GetInterpolationQualifier(msaa, ssaa),
numTexgen);
}
if (per_pixel_lighting)
{
out.Write(",\n in %s float3 Normal : TEXCOORD%u", GetInterpolationQualifier(msaa, ssaa),
@@ -45,7 +45,7 @@ ShaderCode GenVertexShader(APIType ApiType, const ShaderHostConfig& host_config,
out.Write("};\n");

out.Write("struct VS_OUTPUT {\n");
GenerateVSOutputMembers(out, ApiType, numTexgen, per_pixel_lighting, "");
GenerateVSOutputMembers(out, ApiType, numTexgen, host_config, "");
out.Write("};\n\n");

WriteUberShaderCommonHeader(out, ApiType, host_config);
@@ -63,28 +63,38 @@ ShaderCode GenVertexShader(APIType ApiType, const ShaderHostConfig& host_config,
for (int i = 0; i < 8; ++i)
out.Write("ATTRIBUTE_LOCATION(%d) in float3 rawtex%d;\n", SHADER_TEXTURE0_ATTRIB + i, i);

// We need to always use output blocks for Vulkan, but geometry shaders are also optional.
if (host_config.backend_geometry_shaders || ApiType == APIType::Vulkan)
if (host_config.backend_geometry_shaders)
{
out.Write("VARYING_LOCATION(0) out VertexData {\n");
GenerateVSOutputMembers(out, ApiType, numTexgen, per_pixel_lighting,
GenerateVSOutputMembers(out, ApiType, numTexgen, host_config,
GetInterpolationQualifier(msaa, ssaa, true, false));
out.Write("} vs;\n");
}
else
{
// Let's set up attributes
u32 counter = 0;
out.Write("VARYING_LOCATION(%u) %s out float4 colors_0;\n", counter++,
GetInterpolationQualifier(msaa, ssaa));
out.Write("VARYING_LOCATION(%u) %s out float4 colors_1;\n", counter++,
GetInterpolationQualifier(msaa, ssaa));
for (u32 i = 0; i < numTexgen; ++i)
out.Write("%s out float3 tex%u;\n", GetInterpolationQualifier(msaa, ssaa), i);

out.Write("%s out float4 clipPos;\n", GetInterpolationQualifier(msaa, ssaa));
{
out.Write("VARYING_LOCATION(%u) %s out float3 tex%u;\n", counter++,
GetInterpolationQualifier(msaa, ssaa), i);
}
if (!host_config.fast_depth_calc)
{
out.Write("VARYING_LOCATION(%u) %s out float4 clipPos;\n", counter++,
GetInterpolationQualifier(msaa, ssaa));
}
if (per_pixel_lighting)
{
out.Write("%s out float3 Normal;\n", GetInterpolationQualifier(msaa, ssaa));
out.Write("%s out float3 WorldPos;\n", GetInterpolationQualifier(msaa, ssaa));
out.Write("VARYING_LOCATION(%u) %s out float3 Normal;\n", counter++,
GetInterpolationQualifier(msaa, ssaa));
out.Write("VARYING_LOCATION(%u) %s out float3 WorldPos;\n", counter++,
GetInterpolationQualifier(msaa, ssaa));
}
out.Write("%s out float4 colors_0;\n", GetInterpolationQualifier(msaa, ssaa));
out.Write("%s out float4 colors_1;\n", GetInterpolationQualifier(msaa, ssaa));
}

out.Write("void main()\n{\n");
@@ -184,8 +194,11 @@ ShaderCode GenVertexShader(APIType ApiType, const ShaderHostConfig& host_config,
out.Write(" o.colors_1 = float4(1.0, 1.0, 1.0, 1.0);\n");
out.Write("}\n");

// clipPos/w needs to be done in pixel shader, not here
out.Write("o.clipPos = o.pos;\n");
if (!host_config.fast_depth_calc)
{
// clipPos/w needs to be done in pixel shader, not here
out.Write("o.clipPos = o.pos;\n");
}

if (per_pixel_lighting)
{
@@ -207,8 +220,13 @@ ShaderCode GenVertexShader(APIType ApiType, const ShaderHostConfig& host_config,
// We adjust our depth value for clipping purposes to match the perspective projection in the
// software backend, which is a hack to fix Sonic Adventure and Unleashed games.
out.Write("float clipDepth = o.pos.z * (1.0 - 1e-7);\n");
out.Write("o.clipDist0 = clipDepth + o.pos.w;\n"); // Near: z < -w
out.Write("o.clipDist1 = -clipDepth;\n"); // Far: z > 0
out.Write("float clipDist0 = clipDepth + o.pos.w;\n"); // Near: z < -w
out.Write("float clipDist1 = -clipDepth;\n"); // Far: z > 0
if (host_config.backend_geometry_shaders)
{
out.Write("o.clipDist0 = clipDist0;\n");
out.Write("o.clipDist1 = clipDist1;\n");
}
}

// Write the true depth value. If the game uses depth textures, then the pixel shader will
@@ -267,17 +285,18 @@ ShaderCode GenVertexShader(APIType ApiType, const ShaderHostConfig& host_config,

if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
{
if (host_config.backend_geometry_shaders || ApiType == APIType::Vulkan)
if (host_config.backend_geometry_shaders)
{
AssignVSOutputMembers(out, "vs", "o", numTexgen, per_pixel_lighting);
AssignVSOutputMembers(out, "vs", "o", numTexgen, host_config);
}
else
{
// TODO: Pass interface blocks between shader stages even if geometry shaders
// are not supported, however that will require at least OpenGL 3.2 support.
for (u32 i = 0; i < numTexgen; ++i)
out.Write("tex%d.xyz = o.tex%d;\n", i, i);
out.Write("clipPos = o.clipPos;\n");
if (!host_config.fast_depth_calc)
out.Write("clipPos = o.clipPos;\n");
if (per_pixel_lighting)
{
out.Write("Normal = o.Normal;\n");
@@ -289,8 +308,8 @@ ShaderCode GenVertexShader(APIType ApiType, const ShaderHostConfig& host_config,

if (host_config.backend_depth_clamp)
{
out.Write("gl_ClipDistance[0] = o.clipDist0;\n");
out.Write("gl_ClipDistance[1] = o.clipDist1;\n");
out.Write("gl_ClipDistance[0] = clipDist0;\n");
out.Write("gl_ClipDistance[1] = clipDist1;\n");
}

// Vulkan NDC space has Y pointing down (right-handed NDC space).
@@ -477,4 +496,4 @@ void EnumerateVertexShaderUids(const std::function<void(const VertexShaderUid&)>
callback(uid);
}
}
}
} // namespace UberShader
@@ -98,7 +98,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho
out.Write("};\n");

out.Write("struct VS_OUTPUT {\n");
GenerateVSOutputMembers(out, api_type, uid_data->numTexGens, per_pixel_lighting, "");
GenerateVSOutputMembers(out, api_type, uid_data->numTexGens, host_config, "");
out.Write("};\n");

if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
@@ -128,32 +128,36 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho
}
}

// We need to always use output blocks for Vulkan, but geometry shaders are also optional.
if (host_config.backend_geometry_shaders || api_type == APIType::Vulkan)
if (host_config.backend_geometry_shaders)
{
out.Write("VARYING_LOCATION(0) out VertexData {\n");
GenerateVSOutputMembers(out, api_type, uid_data->numTexGens, per_pixel_lighting,
GenerateVSOutputMembers(out, api_type, uid_data->numTexGens, host_config,
GetInterpolationQualifier(msaa, ssaa, true, false));
out.Write("} vs;\n");
}
else
{
// Let's set up attributes
for (u32 i = 0; i < 8; ++i)
u32 counter = 0;
out.Write("VARYING_LOCATION(%u) %s out float4 colors_0;\n", counter++,
GetInterpolationQualifier(msaa, ssaa));
out.Write("VARYING_LOCATION(%u) %s out float4 colors_1;\n", counter++,
GetInterpolationQualifier(msaa, ssaa));
for (u32 i = 0; i < uid_data->numTexGens; ++i)
{
if (i < uid_data->numTexGens)
{
out.Write("%s out float3 tex%u;\n", GetInterpolationQualifier(msaa, ssaa), i);
}
out.Write("VARYING_LOCATION(%u) %s out float3 tex%u;\n", counter++,
GetInterpolationQualifier(msaa, ssaa), i);
}
out.Write("%s out float4 clipPos;\n", GetInterpolationQualifier(msaa, ssaa));
if (!host_config.fast_depth_calc)
out.Write("VARYING_LOCATION(%u) %s out float4 clipPos;\n", counter++,
GetInterpolationQualifier(msaa, ssaa));
if (per_pixel_lighting)
{
out.Write("%s out float3 Normal;\n", GetInterpolationQualifier(msaa, ssaa));
out.Write("%s out float3 WorldPos;\n", GetInterpolationQualifier(msaa, ssaa));
out.Write("VARYING_LOCATION(%u) %s out float3 Normal;\n", counter++,
GetInterpolationQualifier(msaa, ssaa));
out.Write("VARYING_LOCATION(%u) %s out float3 WorldPos;\n", counter++,
GetInterpolationQualifier(msaa, ssaa));
}
out.Write("%s out float4 colors_0;\n", GetInterpolationQualifier(msaa, ssaa));
out.Write("%s out float4 colors_1;\n", GetInterpolationQualifier(msaa, ssaa));
}

out.Write("void main()\n{\n");
@@ -398,7 +402,8 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho
}

// clipPos/w needs to be done in pixel shader, not here
out.Write("o.clipPos = o.pos;\n");
if (!host_config.fast_depth_calc)
out.Write("o.clipPos = o.pos;\n");

if (per_pixel_lighting)
{
@@ -422,8 +427,13 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho
// We adjust our depth value for clipping purposes to match the perspective projection in the
// software backend, which is a hack to fix Sonic Adventure and Unleashed games.
out.Write("float clipDepth = o.pos.z * (1.0 - 1e-7);\n");
out.Write("o.clipDist0 = clipDepth + o.pos.w;\n"); // Near: z < -w
out.Write("o.clipDist1 = -clipDepth;\n"); // Far: z > 0
out.Write("float clipDist0 = clipDepth + o.pos.w;\n"); // Near: z < -w
out.Write("float clipDist1 = -clipDepth;\n"); // Far: z > 0
if (host_config.backend_geometry_shaders)
{
out.Write("o.clipDist0 = clipDist0;\n");
out.Write("o.clipDist1 = clipDist1;\n");
}
}

// Write the true depth value. If the game uses depth textures, then the pixel shader will
@@ -485,17 +495,18 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho

if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
{
if (host_config.backend_geometry_shaders || api_type == APIType::Vulkan)
if (host_config.backend_geometry_shaders)
{
AssignVSOutputMembers(out, "vs", "o", uid_data->numTexGens, per_pixel_lighting);
AssignVSOutputMembers(out, "vs", "o", uid_data->numTexGens, host_config);
}
else
{
// TODO: Pass interface blocks between shader stages even if geometry shaders
// are not supported, however that will require at least OpenGL 3.2 support.
for (unsigned int i = 0; i < uid_data->numTexGens; ++i)
out.Write("tex%d.xyz = o.tex%d;\n", i, i);
out.Write("clipPos = o.clipPos;\n");
if (!host_config.fast_depth_calc)
out.Write("clipPos = o.clipPos;\n");
if (per_pixel_lighting)
{
out.Write("Normal = o.Normal;\n");
@@ -507,8 +518,8 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho

if (host_config.backend_depth_clamp)
{
out.Write("gl_ClipDistance[0] = o.clipDist0;\n");
out.Write("gl_ClipDistance[1] = o.clipDist1;\n");
out.Write("gl_ClipDistance[0] = clipDist0;\n");
out.Write("gl_ClipDistance[1] = clipDist1;\n");
}

// Vulkan NDC space has Y pointing down (right-handed NDC space).