mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 14:19:46 -06:00
VideoCommon: Add vertex shader point and line expansion
This commit is contained in:
@ -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,31 +116,114 @@ 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_UV0 << i)) != 0 || has_texmtx != 0)
|
||||
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)
|
||||
{
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float{} rawtex{};\n", SHADER_TEXTURE0_ATTRIB + i,
|
||||
has_texmtx != 0 ? 3 : 2, i);
|
||||
const u32 has_texmtx = (uid_data->components & (VB_HAS_TEXMTXIDX0 << i));
|
||||
|
||||
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(" 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
|
||||
|
Reference in New Issue
Block a user