diff --git a/Source/Core/VideoCommon/GeometryShaderGen.cpp b/Source/Core/VideoCommon/GeometryShaderGen.cpp index 04d0062982..2db201c636 100644 --- a/Source/Core/VideoCommon/GeometryShaderGen.cpp +++ b/Source/Core/VideoCommon/GeometryShaderGen.cpp @@ -169,22 +169,7 @@ ShaderCode GenerateGeometryShaderCode(APIType api_type, const ShaderHostConfig& "\tVS_OUTPUT end = o[1];\n"); } - // GameCube/Wii's line drawing algorithm is a little quirky. It does not - // use the correct line caps. Instead, the line caps are vertical or - // horizontal depending the slope of the line. - out.Write("\tfloat2 offset;\n" - "\tfloat2 to = abs(end.pos.xy / end.pos.w - start.pos.xy / start.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. - "\tif (" 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] - "\t\toffset = float2(" I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".x, 0);\n" - "\t}} else {{\n" - // Line is more wide. Extend geometry up and down. - // Lerp LineWidth/2 from [0..VpHeight] to [1..-1] - "\t\toffset = float2(0, -" I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".y);\n" - "\t}}\n"); + GenerateLineOffset(out, "\t", "\t\t", "end.pos", "start.pos", ""); } else if (primitive_type == PrimitiveType::Points) { diff --git a/Source/Core/VideoCommon/ShaderGenCommon.cpp b/Source/Core/VideoCommon/ShaderGenCommon.cpp index 85757b64c5..8d880d5479 100644 --- a/Source/Core/VideoCommon/ShaderGenCommon.cpp +++ b/Source/Core/VideoCommon/ShaderGenCommon.cpp @@ -254,6 +254,78 @@ void AssignVSOutputMembers(ShaderCode& object, std::string_view a, std::string_v } } +void GenerateLineOffset(ShaderCode& object, std::string_view indent0, std::string_view indent1, + std::string_view pos_a, std::string_view pos_b, std::string_view sign) +{ + // GameCube/Wii's line drawing algorithm is a little quirky. It does not + // use the correct line caps. Instead, the line caps are vertical or + // horizontal depending the slope of the line. + object.Write("{indent0}float2 offset;\n" + "{indent0}float2 to = abs({pos_a}.xy / {pos_a}.w - {pos_b}.xy / {pos_b}.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. + "{indent0}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] + "{indent1}offset = float2({sign}" I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".x, 0);\n" + "{indent0}}} else {{\n" + // Line is more wide. Extend geometry up and down. + // Lerp LineWidth/2 from [0..VpHeight] to [1..-1] + "{indent1}offset = float2(0, {sign}-" I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".y);\n" + "{indent0}}}\n", + fmt::arg("indent0", indent0), fmt::arg("indent1", indent1), // + fmt::arg("pos_a", pos_a), fmt::arg("pos_b", pos_b), fmt::arg("sign", sign)); +} + +void GenerateVSLineExpansion(ShaderCode& object, std::string_view indent, u32 texgens) +{ + std::string indent1 = std::string(indent) + " "; + object.Write("{0}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" + "\n" + "{0}float expand_sign = is_right ? 1.0f : -1.0f;\n", + indent); + GenerateLineOffset(object, indent, indent1, "o.pos", "other_pos", "expand_sign * "); + object.Write("\n" + "{}o.pos.xy += offset * o.pos.w;\n", + indent); + if (texgens > 0) + { + object.Write("{}if ((" I_TEXOFFSET "[2] != 0) && is_right) {{\n", indent); + object.Write("{} float texOffset = 1.0 / float(" I_TEXOFFSET "[2]);\n", indent); + for (u32 i = 0; i < texgens; i++) + { + object.Write("{} if (((" I_TEXOFFSET "[0] >> {}) & 0x1) != 0)\n", indent, i); + object.Write("{} o.tex{}.x += texOffset;\n", indent, i); + } + object.Write("{}}}\n", indent); + } +} + +void GenerateVSPointExpansion(ShaderCode& object, std::string_view indent, u32 texgens) +{ + object.Write( + "{0}float2 expand_sign = float2(is_right ? 1.0f : -1.0f, is_bottom ? -1.0f : 1.0f);\n" + "{0}float2 offset = expand_sign * " I_LINEPTPARAMS ".ww / " I_LINEPTPARAMS ".xy;\n" + "{0}o.pos.xy += offset * o.pos.w;\n", + indent); + if (texgens > 0) + { + object.Write("{0}if (" I_TEXOFFSET "[3] != 0) {{\n" + "{0} float texOffsetMagnitude = 1.0f / float(" I_TEXOFFSET "[3]);\n" + "{0} float2 texOffset = float2(is_right ? texOffsetMagnitude : 0.0f, " + "is_bottom ? texOffsetMagnitude : 0.0f);", + indent); + for (u32 i = 0; i < texgens; i++) + { + object.Write("{} if (((" I_TEXOFFSET "[1] >> {}) & 0x1) != 0)\n", indent, i); + object.Write("{} o.tex{}.xy += texOffset;\n", indent, i); + } + object.Write("{}}}\n", indent); + } +} + const char* GetInterpolationQualifier(bool msaa, bool ssaa, bool in_glsl_interface_block, bool in) { if (!msaa) diff --git a/Source/Core/VideoCommon/ShaderGenCommon.h b/Source/Core/VideoCommon/ShaderGenCommon.h index 22bad1b220..25b7e32eb6 100644 --- a/Source/Core/VideoCommon/ShaderGenCommon.h +++ b/Source/Core/VideoCommon/ShaderGenCommon.h @@ -198,6 +198,13 @@ void GenerateVSOutputMembers(ShaderCode& object, APIType api_type, u32 texgens, void AssignVSOutputMembers(ShaderCode& object, std::string_view a, std::string_view b, u32 texgens, const ShaderHostConfig& host_config); +void GenerateLineOffset(ShaderCode& object, std::string_view indent0, std::string_view indent1, + std::string_view pos_a, std::string_view pos_b, std::string_view sign); + +void GenerateVSLineExpansion(ShaderCode& object, std::string_view indent, u32 texgens); + +void GenerateVSPointExpansion(ShaderCode& object, std::string_view indent, u32 texgens); + // We use the flag "centroid" to fix some MSAA rendering bugs. With MSAA, the // pixel shader will be executed for each pixel which has at least one passed sample. // So there may be rendered pixels where the center of the pixel isn't in the primitive. diff --git a/Source/Core/VideoCommon/UberShaderVertex.cpp b/Source/Core/VideoCommon/UberShaderVertex.cpp index 0bfacf88ee..4000f858a9 100644 --- a/Source/Core/VideoCommon/UberShaderVertex.cpp +++ b/Source/Core/VideoCommon/UberShaderVertex.cpp @@ -356,67 +356,19 @@ float3 load_input_float3_rawtex(uint vtx_offset, uint attr_offset) {{ " float4 other_p2 = P2;\n" " if ((components & {}u) != 0u) {{ // VB_HAS_POSMTXIDX\n", VB_HAS_POSMTXIDX); - out.Write(" uint other_posidx = int(load_input_uint4_ubyte4(other_base_offset, " - "vertex_offset_posmtx).r);\n" + out.Write(" uint other_posidx = load_input_uint4_ubyte4(other_base_offset, " + "vertex_offset_posmtx).r;\n" " other_p0 = " I_TRANSFORMMATRICES "[other_posidx];\n" " other_p1 = " I_TRANSFORMMATRICES "[other_posidx+1];\n" " other_p2 = " I_TRANSFORMMATRICES "[other_posidx+2];\n" " }}\n" " float4 other_pos = float4(dot(other_p0, other_rawpos), " - "dot(other_p1, other_rawpos), dot(other_p2, other_rawpos), 1.0);\n" - " 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" - "\n" - " float sign = is_right ? 1.0f : -1.0f;\n" - // GameCube/Wii's line drawing algorithm is a little quirky. It does not - // use the correct line caps. Instead, the line caps are vertical or - // horizontal depending the slope of the line. - " 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(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, sign * " I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".y);\n" - " }}\n" - "\n" - " o.pos.xy += offset * o.pos.w;\n"); - if (num_texgen > 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 < num_texgen; i++) - { - out.Write(" if (((" I_TEXOFFSET "[0] >> {}) & 0x1) != 0)\n", i); - out.Write(" o.tex{}.x += texOffset;\n", i); - } - out.Write(" }}\n"); - } + "dot(other_p1, other_rawpos), dot(other_p2, other_rawpos), 1.0);\n"); + GenerateVSLineExpansion(out, " ", num_texgen); out.Write("}} else if (vs_expand == {}u) {{ // Point\n", static_cast(VSExpand::Point)); out.Write(" bool is_bottom = (gl_VertexID & 2) != 0;\n" - " bool is_right = (gl_VertexID & 1) != 0;\n" - " float2 sign = float2(is_right ? 1.0f : -1.0f, is_bottom ? 1.0f : -1.0f);\n" - " float2 offset = sign * " I_LINEPTPARAMS ".ww / " I_LINEPTPARAMS ".xy;\n" - " o.pos.xy += offset * o.pos.w;\n"); - if (num_texgen > 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 < num_texgen; i++) - { - out.Write(" if (((" I_TEXOFFSET "[1] >> {}) & 0x1) != 0)\n", i); - out.Write(" o.tex{}.xy += texOffset;\n", i); - } - out.Write(" }}\n"); - } + " bool is_right = (gl_VertexID & 1) != 0;\n"); + GenerateVSPointExpansion(out, " ", num_texgen); out.Write("}}\n"); } diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index 948dc3ad34..5570e52cc0 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -547,56 +547,12 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho 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"); - } + GenerateVSLineExpansion(out, "", uid_data->numTexGens); } 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"); - } + out.Write("// Point expansion\n"); + GenerateVSPointExpansion(out, "", uid_data->numTexGens); } if (per_pixel_lighting)