mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 06:09:50 -06:00
D3D / VideoCommon: generate HLSL from SPIRV
This commit is contained in:
@ -72,93 +72,89 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||
if (per_pixel_lighting)
|
||||
WriteLightingFunction(out);
|
||||
|
||||
// Shader inputs/outputs in GLSL (HLSL is in main).
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
// Framebuffer fetch is only supported by Metal, so ensure that we're running Vulkan (MoltenVK)
|
||||
// if we want to use it.
|
||||
if (api_type == APIType::Vulkan)
|
||||
// Framebuffer fetch is only supported by Metal, so ensure that we're running Vulkan (MoltenVK)
|
||||
// if we want to use it.
|
||||
if (api_type == APIType::Vulkan)
|
||||
{
|
||||
if (use_dual_source)
|
||||
{
|
||||
if (use_dual_source)
|
||||
{
|
||||
out.Write("FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 0) out vec4 {};\n"
|
||||
"FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 1) out vec4 ocol1;\n",
|
||||
use_framebuffer_fetch ? "real_ocol0" : "ocol0");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Metal doesn't support a single unified variable for both input and output,
|
||||
// so when using framebuffer fetch, we declare the input separately below.
|
||||
out.Write("FRAGMENT_OUTPUT_LOCATION(0) out vec4 {};\n",
|
||||
use_framebuffer_fetch ? "real_ocol0" : "ocol0");
|
||||
}
|
||||
|
||||
if (use_framebuffer_fetch)
|
||||
{
|
||||
// Subpass inputs will be converted to framebuffer fetch by SPIRV-Cross.
|
||||
out.Write("INPUT_ATTACHMENT_BINDING(0, 0, 0) uniform subpassInput in_ocol0;\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
bool has_broken_decoration =
|
||||
DriverDetails::HasBug(DriverDetails::BUG_BROKEN_FRAGMENT_SHADER_INDEX_DECORATION);
|
||||
|
||||
out.Write("{} {} vec4 {};\n",
|
||||
has_broken_decoration ? "FRAGMENT_OUTPUT_LOCATION(0)" :
|
||||
"FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 0)",
|
||||
use_framebuffer_fetch ? "FRAGMENT_INOUT" : "out",
|
||||
out.Write("FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 0) out vec4 {};\n"
|
||||
"FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 1) out vec4 ocol1;\n",
|
||||
use_framebuffer_fetch ? "real_ocol0" : "ocol0");
|
||||
|
||||
if (use_dual_source)
|
||||
{
|
||||
out.Write("{} out vec4 ocol1;\n", has_broken_decoration ?
|
||||
"FRAGMENT_OUTPUT_LOCATION(1)" :
|
||||
"FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 1)");
|
||||
}
|
||||
}
|
||||
|
||||
if (per_pixel_depth)
|
||||
out.Write("#define depth gl_FragDepth\n");
|
||||
|
||||
if (host_config.backend_geometry_shaders)
|
||||
{
|
||||
out.Write("VARYING_LOCATION(0) in VertexData {{\n");
|
||||
GenerateVSOutputMembers(out, api_type, numTexgen, host_config,
|
||||
GetInterpolationQualifier(msaa, ssaa, true, true));
|
||||
|
||||
if (stereo)
|
||||
out.Write(" flat int layer;\n");
|
||||
|
||||
out.Write("}};\n\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Let's set up attributes
|
||||
u32 counter = 0;
|
||||
out.Write("VARYING_LOCATION({}) {} in float4 colors_0;\n", counter++,
|
||||
// Metal doesn't support a single unified variable for both input and output,
|
||||
// so when using framebuffer fetch, we declare the input separately below.
|
||||
out.Write("FRAGMENT_OUTPUT_LOCATION(0) out vec4 {};\n",
|
||||
use_framebuffer_fetch ? "real_ocol0" : "ocol0");
|
||||
}
|
||||
|
||||
if (use_framebuffer_fetch)
|
||||
{
|
||||
// Subpass inputs will be converted to framebuffer fetch by SPIRV-Cross.
|
||||
out.Write("INPUT_ATTACHMENT_BINDING(0, 0, 0) uniform subpassInput in_ocol0;\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
bool has_broken_decoration =
|
||||
DriverDetails::HasBug(DriverDetails::BUG_BROKEN_FRAGMENT_SHADER_INDEX_DECORATION);
|
||||
|
||||
out.Write("{} {} vec4 {};\n",
|
||||
has_broken_decoration ? "FRAGMENT_OUTPUT_LOCATION(0)" :
|
||||
"FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 0)",
|
||||
use_framebuffer_fetch ? "FRAGMENT_INOUT" : "out",
|
||||
use_framebuffer_fetch ? "real_ocol0" : "ocol0");
|
||||
|
||||
if (use_dual_source)
|
||||
{
|
||||
out.Write("{} out vec4 ocol1;\n", has_broken_decoration ?
|
||||
"FRAGMENT_OUTPUT_LOCATION(1)" :
|
||||
"FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 1)");
|
||||
}
|
||||
}
|
||||
|
||||
if (per_pixel_depth)
|
||||
out.Write("#define depth gl_FragDepth\n");
|
||||
|
||||
if (host_config.backend_geometry_shaders)
|
||||
{
|
||||
out.Write("VARYING_LOCATION(0) in VertexData {{\n");
|
||||
GenerateVSOutputMembers(out, api_type, numTexgen, host_config,
|
||||
GetInterpolationQualifier(msaa, ssaa, true, true), ShaderStage::Pixel);
|
||||
|
||||
if (stereo)
|
||||
out.Write(" flat int layer;\n");
|
||||
|
||||
out.Write("}};\n\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Let's set up attributes
|
||||
u32 counter = 0;
|
||||
out.Write("VARYING_LOCATION({}) {} in float4 colors_0;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write("VARYING_LOCATION({}) {} in float4 colors_1;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
for (u32 i = 0; i < numTexgen; ++i)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} in float3 tex{};\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa), i);
|
||||
}
|
||||
if (!host_config.fast_depth_calc)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} in float4 clipPos;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write("VARYING_LOCATION({}) {} in float4 colors_1;\n", counter++,
|
||||
}
|
||||
if (per_pixel_lighting)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} in float3 Normal;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write("VARYING_LOCATION({}) {} in float3 WorldPos;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
for (u32 i = 0; i < numTexgen; ++i)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} in float3 tex{};\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa), i);
|
||||
}
|
||||
if (!host_config.fast_depth_calc)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} in float4 clipPos;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
}
|
||||
if (per_pixel_lighting)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} in float3 Normal;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write("VARYING_LOCATION({}) {} in float3 WorldPos;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -243,10 +239,7 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||
// Doesn't look like DirectX supports this. Oh well the code path is here just in case it
|
||||
// supports this in the future.
|
||||
out.Write("int4 sampleTextureWrapper(uint texmap, int2 uv, int layer) {{\n");
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
out.Write(" return sampleTexture(texmap, samp[texmap], uv, layer);\n");
|
||||
else if (api_type == APIType::D3D)
|
||||
out.Write(" return sampleTexture(texmap, tex[texmap], samp[texmap], uv, layer);\n");
|
||||
out.Write(" return sampleTexture(texmap, samp[texmap], uv, layer);\n");
|
||||
out.Write("}}\n\n");
|
||||
}
|
||||
else
|
||||
@ -259,15 +252,7 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||
" switch(sampler_num) {{\n");
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
{
|
||||
out.Write(" case {0}u: return sampleTexture({0}u, samp[{0}u], uv, layer);\n", i);
|
||||
}
|
||||
else if (api_type == APIType::D3D)
|
||||
{
|
||||
out.Write(" case {0}u: return sampleTexture({0}u, tex[{0}u], samp[{0}u], uv, layer);\n",
|
||||
i);
|
||||
}
|
||||
out.Write(" case {0}u: return sampleTexture({0}u, samp[{0}u], uv, layer);\n", i);
|
||||
}
|
||||
out.Write(" }}\n"
|
||||
"}}\n\n");
|
||||
@ -522,82 +507,34 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||
out.Write(")\n\n");
|
||||
}
|
||||
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
if (early_depth && host_config.backend_early_z)
|
||||
out.Write("FORCE_EARLY_Z;\n");
|
||||
|
||||
out.Write("void main()\n{{\n");
|
||||
out.Write(" float4 rawpos = gl_FragCoord;\n");
|
||||
|
||||
if (use_framebuffer_fetch)
|
||||
{
|
||||
if (early_depth && host_config.backend_early_z)
|
||||
out.Write("FORCE_EARLY_Z;\n");
|
||||
// Store off a copy of the initial framebuffer value.
|
||||
//
|
||||
// If FB_FETCH_VALUE isn't defined (i.e. no special keyword for fetching from the
|
||||
// framebuffer), we read from real_ocol0.
|
||||
out.Write("#ifdef FB_FETCH_VALUE\n"
|
||||
" float4 initial_ocol0 = FB_FETCH_VALUE;\n"
|
||||
"#else\n"
|
||||
" float4 initial_ocol0 = real_ocol0;\n"
|
||||
"#endif\n");
|
||||
|
||||
out.Write("void main()\n{{\n");
|
||||
out.Write(" float4 rawpos = gl_FragCoord;\n");
|
||||
|
||||
if (use_framebuffer_fetch)
|
||||
{
|
||||
// Store off a copy of the initial framebuffer value.
|
||||
//
|
||||
// If FB_FETCH_VALUE isn't defined (i.e. no special keyword for fetching from the
|
||||
// framebuffer), we read from real_ocol0.
|
||||
out.Write("#ifdef FB_FETCH_VALUE\n"
|
||||
" float4 initial_ocol0 = FB_FETCH_VALUE;\n"
|
||||
"#else\n"
|
||||
" float4 initial_ocol0 = real_ocol0;\n"
|
||||
"#endif\n");
|
||||
|
||||
// QComm's Adreno driver doesn't seem to like using the framebuffer_fetch value as an
|
||||
// intermediate value with multiple reads & modifications, so we pull out the "real" output
|
||||
// value above and use a temporary for calculations, then set the output value once at the
|
||||
// end of the shader.
|
||||
out.Write(" float4 ocol0;\n");
|
||||
}
|
||||
|
||||
if (use_shader_blend)
|
||||
{
|
||||
out.Write(" float4 ocol1;\n");
|
||||
}
|
||||
// QComm's Adreno driver doesn't seem to like using the framebuffer_fetch value as an
|
||||
// intermediate value with multiple reads & modifications, so we pull out the "real" output
|
||||
// value above and use a temporary for calculations, then set the output value once at the
|
||||
// end of the shader.
|
||||
out.Write(" float4 ocol0;\n");
|
||||
}
|
||||
else // D3D
|
||||
|
||||
if (use_shader_blend)
|
||||
{
|
||||
if (early_depth && host_config.backend_early_z)
|
||||
out.Write("[earlydepthstencil]\n");
|
||||
|
||||
out.Write("void main(\n");
|
||||
if (uid_data->uint_output)
|
||||
{
|
||||
out.Write(" out uint4 ocol0 : SV_Target,\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
out.Write(" out float4 ocol0 : SV_Target0,\n"
|
||||
" out float4 ocol1 : SV_Target1,\n");
|
||||
}
|
||||
if (per_pixel_depth)
|
||||
out.Write(" out float depth : SV_Depth,\n");
|
||||
out.Write(" in float4 rawpos : SV_Position,\n");
|
||||
out.Write(" in {} float4 colors_0 : COLOR0,\n", GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write(" in {} float4 colors_1 : COLOR1", GetInterpolationQualifier(msaa, ssaa));
|
||||
|
||||
// compute window position if needed because binding semantic WPOS is not widely supported
|
||||
for (u32 i = 0; i < numTexgen; ++i)
|
||||
{
|
||||
out.Write(",\n in {} float3 tex{} : TEXCOORD{}", GetInterpolationQualifier(msaa, ssaa), i,
|
||||
i);
|
||||
}
|
||||
if (!host_config.fast_depth_calc)
|
||||
{
|
||||
out.Write("\n,\n in {} float4 clipPos : TEXCOORD{}", GetInterpolationQualifier(msaa, ssaa),
|
||||
numTexgen);
|
||||
}
|
||||
if (per_pixel_lighting)
|
||||
{
|
||||
out.Write(",\n in {} float3 Normal : TEXCOORD{}", GetInterpolationQualifier(msaa, ssaa),
|
||||
numTexgen + 1);
|
||||
out.Write(",\n in {} float3 WorldPos : TEXCOORD{}", GetInterpolationQualifier(msaa, ssaa),
|
||||
numTexgen + 2);
|
||||
}
|
||||
out.Write(",\n in float clipDist0 : SV_ClipDistance0\n"
|
||||
",\n in float clipDist1 : SV_ClipDistance1\n");
|
||||
if (stereo)
|
||||
out.Write(",\n in uint layer : SV_RenderTargetArrayIndex\n");
|
||||
out.Write("\n ) {{\n");
|
||||
out.Write(" float4 ocol1;\n");
|
||||
}
|
||||
if (!stereo)
|
||||
out.Write(" int layer = 0;\n");
|
||||
@ -634,11 +571,6 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||
BitfieldExtract<&GenMode::numtevstages>("bpmem_genmode"));
|
||||
|
||||
out.Write(" // Main tev loop\n");
|
||||
if (api_type == APIType::D3D)
|
||||
{
|
||||
// Tell DirectX we don't want this loop unrolled (it crashes if it tries to)
|
||||
out.Write(" [loop]\n");
|
||||
}
|
||||
|
||||
out.Write(" for(uint stage = 0u; stage <= num_stages; stage++)\n"
|
||||
" {{\n"
|
||||
|
Reference in New Issue
Block a user