diff options
| author | TellowKrinkle <tellowkrinkle@gmail.com> | 2022-07-23 00:47:04 -0500 |
|---|---|---|
| committer | TellowKrinkle <tellowkrinkle@gmail.com> | 2022-10-22 20:13:24 -0500 |
| commit | 68f49df0f8a845eecd1e65c4d75dfbee3bdc989e (patch) | |
| tree | 95fd1e84279cba083fa8e776ba439b59ad7503a7 /Source/Core/VideoCommon/VertexShaderGen.cpp | |
| parent | 804e42150e03532e63ecc5a7f6f6eed751a132af (diff) | |
VideoCommon: Add vertex shader point and line expansion
Diffstat (limited to 'Source/Core/VideoCommon/VertexShaderGen.cpp')
| -rw-r--r-- | Source/Core/VideoCommon/VertexShaderGen.cpp | 236 |
1 files changed, 216 insertions, 20 deletions
diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index 2eb5a53a97..948dc3ad34 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -6,6 +6,7 @@ #include "Common/Assert.h" #include "Common/CommonTypes.h" #include "VideoCommon/BPMemory.h" +#include "VideoCommon/ConstantManager.h" #include "VideoCommon/LightingShaderGen.h" #include "VideoCommon/NativeVertexFormat.h" #include "VideoCommon/VertexLoaderManager.h" @@ -83,6 +84,8 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho const bool ssaa = host_config.ssaa; const bool vertex_rounding = host_config.vertex_rounding; + ShaderCode input_extract; + out.Write("{}", s_lighting_struct); // uniforms @@ -91,6 +94,21 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho out.Write("{}", s_shader_uniforms); out.Write("}};\n"); + if (uid_data->vs_expand != VSExpand::None) + { + out.Write("UBO_BINDING(std140, 3) uniform GSBlock {{\n"); + out.Write("{}", s_geometry_shader_uniforms); + out.Write("}};\n"); + + if (api_type == APIType::D3D) + { + // D3D doesn't include the base vertex in SV_VertexID + out.Write("UBO_BINDING(std140, 4) uniform DX_Constants {{\n" + " uint base_vertex;\n" + "}};\n\n"); + } + } + out.Write("struct VS_OUTPUT {{\n"); GenerateVSOutputMembers(out, api_type, uid_data->numTexGens, host_config, "", ShaderStage::Vertex); @@ -98,30 +116,113 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho WriteIsNanHeader(out, api_type); - out.Write("ATTRIBUTE_LOCATION({}) in float4 rawpos;\n", SHADER_POSITION_ATTRIB); - if ((uid_data->components & VB_HAS_POSMTXIDX) != 0) - out.Write("ATTRIBUTE_LOCATION({}) in uint4 posmtx;\n", SHADER_POSMTX_ATTRIB); - if ((uid_data->components & VB_HAS_NORMAL) != 0) - out.Write("ATTRIBUTE_LOCATION({}) in float3 rawnormal;\n", SHADER_NORMAL_ATTRIB); - if ((uid_data->components & VB_HAS_TANGENT) != 0) - out.Write("ATTRIBUTE_LOCATION({}) in float3 rawtangent;\n", SHADER_TANGENT_ATTRIB); - if ((uid_data->components & VB_HAS_BINORMAL) != 0) - out.Write("ATTRIBUTE_LOCATION({}) in float3 rawbinormal;\n", SHADER_BINORMAL_ATTRIB); - - if ((uid_data->components & VB_HAS_COL0) != 0) - out.Write("ATTRIBUTE_LOCATION({}) in float4 rawcolor0;\n", SHADER_COLOR0_ATTRIB); - if ((uid_data->components & VB_HAS_COL1) != 0) - out.Write("ATTRIBUTE_LOCATION({}) in float4 rawcolor1;\n", SHADER_COLOR1_ATTRIB); - - for (u32 i = 0; i < 8; ++i) + if (uid_data->vs_expand == VSExpand::None) { - const u32 has_texmtx = (uid_data->components & (VB_HAS_TEXMTXIDX0 << i)); + out.Write("ATTRIBUTE_LOCATION({}) in float4 rawpos;\n", SHADER_POSITION_ATTRIB); + if ((uid_data->components & VB_HAS_POSMTXIDX) != 0) + out.Write("ATTRIBUTE_LOCATION({}) in uint4 posmtx;\n", SHADER_POSMTX_ATTRIB); + if ((uid_data->components & VB_HAS_NORMAL) != 0) + out.Write("ATTRIBUTE_LOCATION({}) in float3 rawnormal;\n", SHADER_NORMAL_ATTRIB); + if ((uid_data->components & VB_HAS_TANGENT) != 0) + out.Write("ATTRIBUTE_LOCATION({}) in float3 rawtangent;\n", SHADER_TANGENT_ATTRIB); + if ((uid_data->components & VB_HAS_BINORMAL) != 0) + out.Write("ATTRIBUTE_LOCATION({}) in float3 rawbinormal;\n", SHADER_BINORMAL_ATTRIB); + + if ((uid_data->components & VB_HAS_COL0) != 0) + out.Write("ATTRIBUTE_LOCATION({}) in float4 rawcolor0;\n", SHADER_COLOR0_ATTRIB); + if ((uid_data->components & VB_HAS_COL1) != 0) + out.Write("ATTRIBUTE_LOCATION({}) in float4 rawcolor1;\n", SHADER_COLOR1_ATTRIB); + + for (u32 i = 0; i < 8; ++i) + { + const u32 has_texmtx = (uid_data->components & (VB_HAS_TEXMTXIDX0 << i)); - if ((uid_data->components & (VB_HAS_UV0 << i)) != 0 || has_texmtx != 0) + if ((uid_data->components & (VB_HAS_UV0 << i)) != 0 || has_texmtx != 0) + { + out.Write("ATTRIBUTE_LOCATION({}) in float{} rawtex{};\n", SHADER_TEXTURE0_ATTRIB + i, + has_texmtx != 0 ? 3 : 2, i); + } + } + } + else + { + // Can't use float3, etc because we want 4-byte alignment + out.Write( + "uint4 unpack_ubyte4(uint value) {{\n" + " return uint4(value & 0xff, (value >> 8) & 0xff, (value >> 16) & 0xff, value >> 24);\n" + "}}\n\n" + "struct InputData {{\n"); + if (uid_data->components & VB_HAS_POSMTXIDX) { - out.Write("ATTRIBUTE_LOCATION({}) in float{} rawtex{};\n", SHADER_TEXTURE0_ATTRIB + i, - has_texmtx != 0 ? 3 : 2, i); + out.Write(" uint posmtx;\n"); + input_extract.Write("uint4 posmtx = unpack_ubyte4(i.posmtx);\n"); + } + if (uid_data->position_has_3_elems) + { + out.Write(" float pos0;\n" + " float pos1;\n" + " float pos2;\n"); + input_extract.Write("float4 rawpos = float4(i.pos0, i.pos1, i.pos2, 1.0f);\n"); + } + else + { + out.Write(" float pos0;\n" + " float pos1;\n"); + input_extract.Write("float4 rawpos = float4(i.pos0, i.pos1, 0.0f, 1.0f);\n"); + } + std::array<std::string_view, 3> names = {"normal", "binormal", "tangent"}; + for (int i = 0; i < 3; i++) + { + if (uid_data->components & (VB_HAS_NORMAL << i)) + { + out.Write(" float {0}0;\n" + " float {0}1;\n" + " float {0}2;\n", + names[i]); + input_extract.Write("float3 raw{0} = float3(i.{0}0, i.{0}1, i.{0}2);\n", names[i]); + } + } + for (int i = 0; i < 2; i++) + { + if (uid_data->components & (VB_HAS_COL0 << i)) + { + out.Write(" uint color{};\n", i); + input_extract.Write("float4 rawcolor{0} = float4(unpack_ubyte4(i.color{0})) / 255.0f;\n", + i); + } + } + for (int i = 0; i < 8; i++) + { + if (uid_data->components & (VB_HAS_UV0 << i)) + { + u32 ncomponents = (uid_data->texcoord_elem_count >> (2 * i)) & 3; + if (ncomponents < 2) + { + out.Write(" float tex{};\n", i); + input_extract.Write("float3 rawtex{0} = float3(i.tex{0}, 0.0f, 0.0f);\n", i); + } + else if (ncomponents == 2) + { + out.Write(" float tex{0}_0;\n" + " float tex{0}_1;\n", + i); + input_extract.Write("float3 rawtex{0} = float3(i.tex{0}_0, i.tex{0}_1, 0.0f);\n", i); + } + else + { + out.Write(" float tex{0}_0;\n" + " float tex{0}_1;\n" + " float tex{0}_2;\n", + i); + input_extract.Write("float3 rawtex{0} = float3(i.tex{0}_0, i.tex{0}_1, i.tex{0}_2);\n", + i); + } + } } + out.Write("}};\n\n" + "SSBO_BINDING(1) readonly restrict buffer InputBuffer {{\n" + " InputData input_buffer[];\n" + "}};\n\n"); } if (host_config.backend_geometry_shaders) @@ -161,6 +262,21 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho out.Write("void main()\n{{\n"); + if (uid_data->vs_expand != VSExpand::None) + { + out.Write("bool is_bottom = (gl_VertexID & 2) != 0;\n" + "bool is_right = (gl_VertexID & 1) != 0;\n"); + // D3D doesn't include the base vertex in SV_VertexID + // See comment in UberShaderVertex for details + if (api_type == APIType::D3D) + out.Write("uint vertex_id = (gl_VertexID >> 2) + base_vertex;\n"); + else + out.Write("uint vertex_id = gl_VertexID >> 2;\n"); + out.Write("InputData i = input_buffer[vertex_id];\n" + "{}", + input_extract.GetBuffer()); + } + out.Write("VS_OUTPUT o;\n"); // xfmem.numColorChans controls the number of color channels available to TEV, but we still need @@ -403,6 +519,86 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho out.Write("}}\n"); } + if (uid_data->vs_expand == VSExpand::Line) + { + out.Write("// Line expansion\n" + "uint other_id = vertex_id;\n" + "if (is_bottom) {{\n" + " other_id -= 1;\n" + "}} else {{\n" + " other_id += 1;\n" + "}}\n" + "InputData other = input_buffer[other_id];\n"); + if (uid_data->position_has_3_elems) + out.Write("float4 other_pos = float4(other.pos0, other.pos1, other.pos2, 1.0f);\n"); + else + out.Write("float4 other_pos = float4(other.pos0, other.pos1, 0.0f, 1.0f);\n"); + if (uid_data->components & VB_HAS_POSMTXIDX) + { + out.Write("uint other_posidx = other.posmtx & 0xff;\n" + "float4 other_p0 = " I_TRANSFORMMATRICES "[other_posidx];\n" + "float4 other_p1 = " I_TRANSFORMMATRICES "[other_posidx + 1];\n" + "float4 other_p2 = " I_TRANSFORMMATRICES "[other_posidx + 2];\n" + "other_pos = float4(dot(other_p0, other_pos), dot(other_p1, other_pos), " + "dot(other_p2, other_pos), 1.0f);\n"); + } + else + { + out.Write("other_pos = float4(dot(P0, other_pos), dot(P1, other_pos), dot(P2, other_pos), " + "1.0f);\n"); + } + out.Write("other_pos = float4(dot(" I_PROJECTION "[0], other_pos), dot(" I_PROJECTION + "[1], other_pos), dot(" I_PROJECTION "[2], other_pos), dot(" I_PROJECTION + "[3], other_pos));\n" + "float expand_sign = is_right ? 1.0f : -1.0f;\n" + "float2 offset;\n" + "float2 to = abs(o.pos.xy / o.pos.w - other_pos.xy / other_pos.w);\n" + // FIXME: What does real hardware do when line is at a 45-degree angle? + // FIXME: Lines aren't drawn at the correct width. See Twilight Princess map. + "if (" I_LINEPTPARAMS ".y * to.y > " I_LINEPTPARAMS ".x * to.x) {{\n" + // Line is more tall. Extend geometry left and right. + // Lerp LineWidth/2 from [0..VpWidth] to [-1..1] + " offset = float2(expand_sign * " I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".x, 0);\n" + "}} else {{\n" + // Line is more wide. Extend geometry up and down. + // Lerp LineWidth/2 from [0..VpHeight] to [1..-1] + " offset = float2(0, expand_sign * " I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".y);\n" + "}}\n" + "\n" + "o.pos.xy += offset * o.pos.w;\n"); + if (uid_data->numTexGens > 0) + { + out.Write("if ((" I_TEXOFFSET "[2] != 0) && is_right) {{\n" + " float texOffset = 1.0 / float(" I_TEXOFFSET "[2]);\n"); + for (u32 i = 0; i < uid_data->numTexGens; i++) + { + out.Write(" if (((" I_TEXOFFSET "[0] >> {}) & 0x1) != 0)\n", i); + out.Write(" o.tex{}.x += texOffset;\n", i); + } + out.Write("}}\n"); + } + } + else if (uid_data->vs_expand == VSExpand::Point) + { + out.Write("// Point expansion\n" + "float2 expand_sign = float2(is_right ? 1.0f : -1.0f, is_bottom ? 1.0f : -1.0f);\n" + "float2 offset = expand_sign * " I_LINEPTPARAMS ".ww / " I_LINEPTPARAMS ".xy;\n" + "o.pos.xy += offset * o.pos.w;\n"); + if (uid_data->numTexGens > 0) + { + out.Write("if (" I_TEXOFFSET "[3] != 0) {{\n" + " float texOffsetMagnitude = 1.0f / float(" I_TEXOFFSET "[3]);\n" + " float2 texOffset = float2(is_right ? texOffsetMagnitude : 0.0f, " + "is_bottom ? texOffsetMagnitude : 0.0f);"); + for (u32 i = 0; i < uid_data->numTexGens; i++) + { + out.Write(" if (((" I_TEXOFFSET "[1] >> {}) & 0x1) != 0)\n", i); + out.Write(" o.tex{}.xy += texOffset;\n", i); + } + out.Write("}}\n"); + } + } + if (per_pixel_lighting) { // When per-pixel lighting is enabled, the vertex colors are passed through |
