summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon/VertexShaderGen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Core/VideoCommon/VertexShaderGen.cpp')
-rw-r--r--Source/Core/VideoCommon/VertexShaderGen.cpp236
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