From 41d6c3cf3ac73e065dfb0b3d51130f4181d6281e Mon Sep 17 00:00:00 2001 From: xebra Date: Fri, 13 Jul 2018 23:36:36 +0900 Subject: [PATCH] [spline/bezier]Move whole tessellation logic in the shaders into a subroutine. --- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 169 +++++++++++---------- GPU/GLES/VertexShaderGeneratorGLES.cpp | 162 +++++++++++--------- GPU/Vulkan/VertexShaderGeneratorVulkan.cpp | 167 +++++++++++--------- 3 files changed, 273 insertions(+), 225 deletions(-) diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index ab771971babc..5ff0f6978f09 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -297,6 +297,87 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage WRITE(p, " return pos;\n"); WRITE(p, "}\n"); } + + WRITE(p, "struct Tess {\n"); + WRITE(p, " float3 pos;\n"); + if (doTexture && hasTexcoord) + WRITE(p, " float2 tex;\n"); + if (hasColor) + WRITE(p, " float4 col;\n"); + if (hasNormal) + WRITE(p, " float3 nrm;\n"); + WRITE(p, "};\n"); + + WRITE(p, "void tessellate(in VS_IN In, out Tess tess) {\n"); + WRITE(p, " int2 spline_num_patches = int2((u_spline_counts >> 0) & 0xFF, (u_spline_counts >> 8) & 0xFF);\n"); + WRITE(p, " int2 spline_tess = int2((u_spline_counts >> 16) & 0xFF, (u_spline_counts >> 24) & 0xFF);\n"); + // Calculate current patch position and vertex position(index for the weights) + WRITE(p, " int spline_count_u = %s;\n", doBezier ? "spline_num_patches.x * 3 + 1" : "spline_num_patches.x + 3"); + WRITE(p, " int u = In.instanceId %% spline_num_patches.x;\n"); + WRITE(p, " int v = In.instanceId / spline_num_patches.x;\n"); + WRITE(p, " int2 patch_pos = int2(u, v);\n"); + WRITE(p, " int2 vertex_pos = int2(In.position.xy);\n"); + if (doSpline) { + WRITE(p, " bool2 isFirstEdge = !bool2(vertex_pos);\n"); // vertex_pos == 0 + WRITE(p, " bool2 isNotFirstPatch = bool2(patch_pos);\n"); // patch_pos > 0 + WRITE(p, " vertex_pos += patch_pos * spline_tess;\n"); + } + // Load 4x4 control points + WRITE(p, " float3 _pos[16];\n"); + WRITE(p, " float2 _tex[16];\n"); + WRITE(p, " float4 _col[16];\n"); + WRITE(p, " int index;\n"); + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + WRITE(p, " index = (%i + v%s) * spline_count_u + (%i + u%s);\n", i, doBezier ? " * 3" : "", j, doBezier ? " * 3" : ""); + WRITE(p, " _pos[%i] = tess_data[index].pos;\n", i * 4 + j); + if (doTexture && hasTexcoord && hasTexcoordTess) + WRITE(p, " _tex[%i] = tess_data[index].tex;\n", i * 4 + j); + if (hasColor && hasColorTess) + WRITE(p, " _col[%i] = tess_data[index].col;\n", i * 4 + j); + } + } + + // Basis polynomials as weight coefficients + WRITE(p, " float4 basis_u = tess_weights_u[vertex_pos.x].basis;\n"); + WRITE(p, " float4 basis_v = tess_weights_v[vertex_pos.y].basis;\n"); + if (doSpline) { + WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n"); + WRITE(p, " basis_u = float4(basis_u.yzw, 0);\n"); + WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n"); + WRITE(p, " basis_v = float4(basis_v.yzw, 0);\n"); + } + + // Tessellate + WRITE(p, " tess.pos = tess_sample(_pos, basis_u, basis_v);\n"); + if (doTexture && hasTexcoord) { + if (hasTexcoordTess) + WRITE(p, " tess.tex = tess_sample(_tex, basis_u, basis_v);\n"); + else + WRITE(p, " tess.tex = In.normal.xy + float2(patch_pos);\n"); + } + if (hasColor) { + if (hasColorTess) + WRITE(p, " tess.col = tess_sample(_col, basis_u, basis_v);\n"); + else + WRITE(p, " tess.col = tess_data[0].col;\n"); + } + if (hasNormal) { + // Derivatives as weight coefficients + WRITE(p, " float4 deriv_u = tess_weights_u[vertex_pos.x].deriv;\n"); + WRITE(p, " float4 deriv_v = tess_weights_v[vertex_pos.y].deriv;\n"); + if (doSpline) { + WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n"); + WRITE(p, " deriv_u = float4(deriv_u.yzw, 0);\n"); + WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n"); + WRITE(p, " deriv_v = float4(deriv_v.yzw, 0);\n"); + } + + WRITE(p, " float3 du = tess_sample(_pos, deriv_u, basis_v);\n"); + WRITE(p, " float3 dv = tess_sample(_pos, basis_u, deriv_v);\n"); + WRITE(p, " tess.nrm = normalize(cross(du, dv));\n"); + } + WRITE(p, "}\n"); } WRITE(p, "VS_OUT main(VS_IN In) {\n"); @@ -346,80 +427,14 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage } else { // Step 1: World Transform / Skinning if (!enableBones) { - // Hardware tessellation if (doSpline || doBezier) { - WRITE(p, " int2 spline_num_patches = int2((u_spline_counts >> 0) & 0xFF, (u_spline_counts >> 8) & 0xFF);\n"); - WRITE(p, " int2 spline_tess = int2((u_spline_counts >> 16) & 0xFF, (u_spline_counts >> 24) & 0xFF);\n"); - - WRITE(p, " int spline_count_u = %s;\n", doBezier ? "spline_num_patches.x * 3 + 1" : "spline_num_patches.x + 3"); - WRITE(p, " int u = In.instanceId %% spline_num_patches.x;\n"); - WRITE(p, " int v = In.instanceId / spline_num_patches.x;\n"); - WRITE(p, " int2 patch_pos = int2(u, v);\n"); - WRITE(p, " int2 vertex_pos = int2(In.position.xy);\n"); - if (doSpline) { - WRITE(p, " bool2 isFirstEdge = !bool2(vertex_pos);\n"); // vertex_pos == 0 - WRITE(p, " bool2 isNotFirstPatch = bool2(patch_pos);\n"); // patch_pos > 0 - WRITE(p, " vertex_pos += patch_pos * spline_tess;\n"); - } - // Load 4x4 control points - WRITE(p, " float3 _pos[16];\n"); - WRITE(p, " float2 _tex[16];\n"); - WRITE(p, " float4 _col[16];\n"); - WRITE(p, " int index;\n"); - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - WRITE(p, " index = (%i + v%s) * spline_count_u + (%i + u%s);\n", i, doBezier ? " * 3" : "", j, doBezier ? " * 3" : ""); - WRITE(p, " _pos[%i] = tess_data[index].pos;\n", i * 4 + j); - if (doTexture && hasTexcoord && hasTexcoordTess) - WRITE(p, " _tex[%i] = tess_data[index].tex;\n", i * 4 + j); - if (hasColor && hasColorTess) - WRITE(p, " _col[%i] = tess_data[index].col;\n", i * 4 + j); - } - } + // Hardware tessellation + WRITE(p, " Tess tess;\n"); + WRITE(p, " tessellate(In, tess);\n"); - // Basis polynomials as weight coefficients - WRITE(p, " float4 basis_u = tess_weights_u[vertex_pos.x].basis;\n"); - WRITE(p, " float4 basis_v = tess_weights_v[vertex_pos.y].basis;\n"); - if (doSpline) { - WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n"); - WRITE(p, " basis_u = float4(basis_u.yzw, 0);\n"); - WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n"); - WRITE(p, " basis_v = float4(basis_v.yzw, 0);\n"); - } - - // Tessellate - WRITE(p, " float3 pos = tess_sample(_pos, basis_u, basis_v);\n"); - if (doTexture && hasTexcoord) { - if (hasTexcoordTess) - WRITE(p, " float2 tex = tess_sample(_tex, basis_u, basis_v);\n"); - else - WRITE(p, " float2 tex = In.normal.xy + float2(patch_pos);\n"); - } - if (hasColor) { - if (hasColorTess) - WRITE(p, " float4 col = tess_sample(_col, basis_u, basis_v);\n"); - else - WRITE(p, " float4 col = tess_data[0].col;\n"); - } - if (hasNormal) { - // Derivatives as weight coefficients - WRITE(p, " float4 deriv_u = tess_weights_u[vertex_pos.x].deriv;\n"); - WRITE(p, " float4 deriv_v = tess_weights_v[vertex_pos.y].deriv;\n"); - if (doSpline) { - WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n"); - WRITE(p, " deriv_u = float4(deriv_u.yzw, 0);\n"); - WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n"); - WRITE(p, " deriv_v = float4(deriv_v.yzw, 0);\n"); - } - - WRITE(p, " float3 du = tess_sample(_pos, deriv_u, basis_v);\n"); - WRITE(p, " float3 dv = tess_sample(_pos, basis_u, deriv_v);\n"); - WRITE(p, " float3 nrm = cross(du, dv);\n"); - WRITE(p, " nrm = normalize(nrm);\n"); - } - WRITE(p, " float3 worldpos = mul(float4(pos.xyz, 1.0), u_world);\n"); + WRITE(p, " float3 worldpos = mul(float4(tess.pos.xyz, 1.0), u_world);\n"); if (hasNormal) - WRITE(p, " float3 worldnormal = normalize(mul(float4(%snrm, 0.0), u_world));\n", flipNormalTess ? "-" : ""); + WRITE(p, " float3 worldnormal = normalize(mul(float4(%stess.nrm, 0.0), u_world));\n", flipNormalTess ? "-" : ""); else WRITE(p, " float3 worldnormal = float3(0.0, 0.0, 1.0);\n"); } else { @@ -524,9 +539,9 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage const char *diffuseStr = (matUpdate & 2) && hasColor ? "In.color0.rgb" : "u_matdiffuse"; const char *specularStr = (matUpdate & 4) && hasColor ? "In.color0.rgb" : "u_matspecular.rgb"; if (doBezier || doSpline) { - ambientStr = (matUpdate & 1) && hasColor ? "col" : "u_matambientalpha"; - diffuseStr = (matUpdate & 2) && hasColor ? "col.rgb" : "u_matdiffuse"; - specularStr = (matUpdate & 4) && hasColor ? "col.rgb" : "u_matspecular.rgb"; + ambientStr = (matUpdate & 1) && hasColor ? "tess.col" : "u_matambientalpha"; + diffuseStr = (matUpdate & 2) && hasColor ? "tess.col.rgb" : "u_matdiffuse"; + specularStr = (matUpdate & 4) && hasColor ? "tess.col.rgb" : "u_matspecular.rgb"; } bool diffuseIsZero = true; @@ -653,7 +668,7 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage // Lighting doesn't affect color. if (hasColor) { if (doBezier || doSpline) - WRITE(p, " Out.v_color0 = col;\n"); + WRITE(p, " Out.v_color0 = tess.col;\n"); else WRITE(p, " Out.v_color0 = In.color0;\n"); } else { @@ -671,7 +686,7 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage if (scaleUV) { if (hasTexcoord) { if (doBezier || doSpline) - WRITE(p, " Out.v_texcoord = float3(tex.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n"); + WRITE(p, " Out.v_texcoord = float3(tess.tex.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n"); else WRITE(p, " Out.v_texcoord = float3(In.texcoord.xy * u_uvscaleoffset.xy, 0.0);\n"); } else { @@ -680,7 +695,7 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage } else { if (hasTexcoord) { if (doBezier || doSpline) - WRITE(p, " Out.v_texcoord = float3(tex.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n"); + WRITE(p, " Out.v_texcoord = float3(tess.tex.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n"); else WRITE(p, " Out.v_texcoord = float3(In.texcoord.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n"); } else { diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index 895536fc04df..84c782325da8 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -400,6 +400,84 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, WRITE(p, " return pos;\n"); WRITE(p, "}\n"); } + + WRITE(p, "struct Tess {\n"); + WRITE(p, " vec3 pos;\n"); + if (doTexture && hasTexcoord) + WRITE(p, " vec2 tex;\n"); + if (hasColor) + WRITE(p, " vec4 col;\n"); + if (hasNormal) + WRITE(p, " vec3 nrm;\n"); + WRITE(p, "};\n"); + + WRITE(p, "void tessellate(out Tess tess) {\n"); + // Calculate current patch position and vertex position(index for the weights) + WRITE(p, " int spline_count_u = %s;\n", doBezier ? "u_spline_num_patches.x * 3 + 1" : "u_spline_num_patches.x + 3"); + WRITE(p, " int u = gl_InstanceID %% u_spline_num_patches.x;\n"); + WRITE(p, " int v = gl_InstanceID / u_spline_num_patches.x;\n"); + WRITE(p, " ivec2 patch_pos = ivec2(u, v);\n"); + WRITE(p, " ivec2 vertex_pos = ivec2(position.xy);\n"); + if (doSpline) { + WRITE(p, " bvec2 isFirstEdge = not(bvec2(vertex_pos));\n"); // vertex_pos == 0 + WRITE(p, " bvec2 isNotFirstPatch = bvec2(patch_pos);\n"); // patch_pos > 0 + WRITE(p, " vertex_pos += patch_pos * u_spline_tess;\n"); + } + // Load 4x4 control points + WRITE(p, " vec3 _pos[16];\n"); + WRITE(p, " vec2 _tex[16];\n"); + WRITE(p, " vec4 _col[16];\n"); + WRITE(p, " for (int i = 0; i < 4; i++) {\n"); + WRITE(p, " for (int j = 0; j < 4; j++) {\n"); + WRITE(p, " int index = (i + v%s) * spline_count_u + (j + u%s);\n", doBezier ? " * 3" : "", doBezier ? " * 3" : ""); + WRITE(p, " _pos[i * 4 + j] = %s(u_tess_points, ivec2(index, 0), 0).xyz;\n", texelFetch); + if (doTexture && hasTexcoord && hasTexcoordTess) + WRITE(p, " _tex[i * 4 + j] = %s(u_tess_points, ivec2(index, 1), 0).xy;\n", texelFetch); + if (hasColor && hasColorTess) + WRITE(p, " _col[i * 4 + j] = %s(u_tess_points, ivec2(index, 2), 0).rgba;\n", texelFetch); + WRITE(p, " }\n"); + WRITE(p, " }\n"); + + // Basis polynomials as weight coefficients + WRITE(p, " vec4 basis_u = %s(u_tess_weights_u, %s, 0);\n", texelFetch, "ivec2(vertex_pos.x * 2, 0)"); + WRITE(p, " vec4 basis_v = %s(u_tess_weights_v, %s, 0);\n", texelFetch, "ivec2(vertex_pos.y * 2, 0)"); + if (doSpline) { + WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n"); + WRITE(p, " basis_u = vec4(basis_u.yzw, 0);\n"); + WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n"); + WRITE(p, " basis_v = vec4(basis_v.yzw, 0);\n"); + } + + // Tessellate + WRITE(p, " tess.pos = tess_sample(_pos, basis_u, basis_v);\n"); + if (doTexture && hasTexcoord) { + if (hasTexcoordTess) + WRITE(p, " tess.tex = tess_sample(_tex, basis_u, basis_v);\n"); + else + WRITE(p, " tess.tex = normal.xy + vec2(patch_pos);\n"); + } + if (hasColor) { + if (hasColorTess) + WRITE(p, " tess.col = tess_sample(_col, basis_u, basis_v);\n"); + else + WRITE(p, " tess.col = %s(u_tess_points, ivec2(0, 2), 0).rgba;\n", texelFetch); + } + if (hasNormal) { + // Derivatives as weight coefficients + WRITE(p, " vec4 deriv_u = %s(u_tess_weights_u, %s, 0);\n", texelFetch, "ivec2(vertex_pos.x * 2 + 1, 0)"); + WRITE(p, " vec4 deriv_v = %s(u_tess_weights_v, %s, 0);\n", texelFetch, "ivec2(vertex_pos.y * 2 + 1, 0)"); + if (doSpline) { + WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n"); + WRITE(p, " deriv_u = vec4(deriv_u.yzw, 0);\n"); + WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n"); + WRITE(p, " deriv_v = vec4(deriv_v.yzw, 0);\n"); + } + + WRITE(p, " vec3 du = tess_sample(_pos, deriv_u, basis_v);\n"); + WRITE(p, " vec3 dv = tess_sample(_pos, basis_u, deriv_v);\n"); + WRITE(p, " tess.nrm = normalize(cross(du, dv));\n"); + } + WRITE(p, "}\n"); } WRITE(p, "void main() {\n"); @@ -438,76 +516,14 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, } else { // Step 1: World Transform / Skinning if (!enableBones) { - // Hardware tessellation if (doBezier || doSpline) { - WRITE(p, " int spline_count_u = %s;\n", doBezier ? "u_spline_num_patches.x * 3 + 1" : "u_spline_num_patches.x + 3"); - WRITE(p, " int u = gl_InstanceID %% u_spline_num_patches.x;\n"); - WRITE(p, " int v = gl_InstanceID / u_spline_num_patches.x;\n"); - WRITE(p, " ivec2 patch_pos = ivec2(u, v);\n"); - WRITE(p, " ivec2 vertex_pos = ivec2(position.xy);\n"); - if (doSpline) { - WRITE(p, " bvec2 isFirstEdge = not(bvec2(vertex_pos));\n"); // vertex_pos == 0 - WRITE(p, " bvec2 isNotFirstPatch = bvec2(patch_pos);\n"); // patch_pos > 0 - WRITE(p, " vertex_pos += patch_pos * u_spline_tess;\n"); - } - // Load 4x4 control points - WRITE(p, " vec3 _pos[16];\n"); - WRITE(p, " vec2 _tex[16];\n"); - WRITE(p, " vec4 _col[16];\n"); - WRITE(p, " for (int i = 0; i < 4; i++) {\n"); - WRITE(p, " for (int j = 0; j < 4; j++) {\n"); - WRITE(p, " int index = (i + v%s) * spline_count_u + (j + u%s);\n", doBezier ? " * 3" : "", doBezier ? " * 3" : ""); - WRITE(p, " _pos[i * 4 + j] = %s(u_tess_points, ivec2(index, 0), 0).xyz;\n", texelFetch); - if (doTexture && hasTexcoord && hasTexcoordTess) - WRITE(p, " _tex[i * 4 + j] = %s(u_tess_points, ivec2(index, 1), 0).xy;\n", texelFetch); - if (hasColor && hasColorTess) - WRITE(p, " _col[i * 4 + j] = %s(u_tess_points, ivec2(index, 2), 0).rgba;\n", texelFetch); - WRITE(p, " }\n"); - WRITE(p, " }\n"); - - // Basis polynomials as weight coefficients - WRITE(p, " vec4 basis_u = %s(u_tess_weights_u, %s, 0);\n", texelFetch, "ivec2(vertex_pos.x * 2, 0)"); - WRITE(p, " vec4 basis_v = %s(u_tess_weights_v, %s, 0);\n", texelFetch, "ivec2(vertex_pos.y * 2, 0)"); - if (doSpline) { - WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n"); - WRITE(p, " basis_u = vec4(basis_u.yzw, 0);\n"); - WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n"); - WRITE(p, " basis_v = vec4(basis_v.yzw, 0);\n"); - } + // Hardware tessellation + WRITE(p, " Tess tess;\n"); + WRITE(p, " tessellate(tess);\n"); - // Tessellate - WRITE(p, " vec3 pos = tess_sample(_pos, basis_u, basis_v);\n"); - if (doTexture && hasTexcoord) { - if (hasTexcoordTess) - WRITE(p, " vec2 tex = tess_sample(_tex, basis_u, basis_v);\n"); - else - WRITE(p, " vec2 tex = normal.xy + vec2(patch_pos);\n"); - } - if (hasColor) { - if (hasColorTess) - WRITE(p, " vec4 col = tess_sample(_col, basis_u, basis_v);\n"); - else - WRITE(p, " vec4 col = %s(u_tess_points, ivec2(0, 2), 0).rgba;\n", texelFetch); - } - if (hasNormal) { - // Derivatives as weight coefficients - WRITE(p, " vec4 deriv_u = %s(u_tess_weights_u, %s, 0);\n", texelFetch, "ivec2(vertex_pos.x * 2 + 1, 0)"); - WRITE(p, " vec4 deriv_v = %s(u_tess_weights_v, %s, 0);\n", texelFetch, "ivec2(vertex_pos.y * 2 + 1, 0)"); - if (doSpline) { - WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n"); - WRITE(p, " deriv_u = vec4(deriv_u.yzw, 0);\n"); - WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n"); - WRITE(p, " deriv_v = vec4(deriv_v.yzw, 0);\n"); - } - - WRITE(p, " vec3 du = tess_sample(_pos, deriv_u, basis_v);\n"); - WRITE(p, " vec3 dv = tess_sample(_pos, basis_u, deriv_v);\n"); - WRITE(p, " vec3 nrm = cross(du, dv);\n"); - WRITE(p, " nrm = normalize(nrm);\n"); - } - WRITE(p, " vec3 worldpos = (u_world * vec4(pos.xyz, 1.0)).xyz;\n"); + WRITE(p, " vec3 worldpos = (u_world * vec4(tess.pos.xyz, 1.0)).xyz;\n"); if (hasNormal) { - WRITE(p, " mediump vec3 worldnormal = normalize((u_world * vec4(%snrm, 0.0)).xyz);\n", flipNormalTess ? "-" : ""); + WRITE(p, " mediump vec3 worldnormal = normalize((u_world * vec4(%stess.nrm, 0.0)).xyz);\n", flipNormalTess ? "-" : ""); } else { WRITE(p, " mediump vec3 worldnormal = vec3(0.0, 0.0, 1.0);\n"); } @@ -611,9 +627,9 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, const char *diffuseStr = (matUpdate & 2) && hasColor ? "color0.rgb" : "u_matdiffuse"; const char *specularStr = (matUpdate & 4) && hasColor ? "color0.rgb" : "u_matspecular.rgb"; if (doBezier || doSpline) { - ambientStr = (matUpdate & 1) && hasColor ? "col" : "u_matambientalpha"; - diffuseStr = (matUpdate & 2) && hasColor ? "col.rgb" : "u_matdiffuse"; - specularStr = (matUpdate & 4) && hasColor ? "col.rgb" : "u_matspecular.rgb"; + ambientStr = (matUpdate & 1) && hasColor ? "tess.col" : "u_matambientalpha"; + diffuseStr = (matUpdate & 2) && hasColor ? "tess.col.rgb" : "u_matdiffuse"; + specularStr = (matUpdate & 4) && hasColor ? "tess.col.rgb" : "u_matspecular.rgb"; } bool diffuseIsZero = true; @@ -740,7 +756,7 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, // Lighting doesn't affect color. if (hasColor) { if (doBezier || doSpline) - WRITE(p, " v_color0 = col;\n"); + WRITE(p, " v_color0 = tess.col;\n"); else WRITE(p, " v_color0 = color0;\n"); } else { @@ -760,7 +776,7 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, if (doBezier || doSpline) // TODO: Need fix? // Fix to avoid temporarily texture animation bug with hardware tessellation. - WRITE(p, " v_texcoord = vec3(tex * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n"); + WRITE(p, " v_texcoord = vec3(tess.tex * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n"); else WRITE(p, " v_texcoord = vec3(texcoord.xy * u_uvscaleoffset.xy, 0.0);\n"); } else { @@ -769,7 +785,7 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, } else { if (hasTexcoord) { if (doBezier || doSpline) - WRITE(p, " v_texcoord = vec3(tex * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n"); + WRITE(p, " v_texcoord = vec3(tess.tex * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n"); else WRITE(p, " v_texcoord = vec3(texcoord.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n"); } else { diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index 99b799cfcdc3..a45e10c70f0b 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -249,6 +249,87 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { WRITE(p, " return pos;\n"); WRITE(p, "}\n"); } + + WRITE(p, "struct Tess {\n"); + WRITE(p, " vec3 pos;\n"); + if (doTexture && hasTexcoord) + WRITE(p, " vec2 tex;\n"); + if (hasColor) + WRITE(p, " vec4 col;\n"); + if (hasNormal) + WRITE(p, " vec3 nrm;\n"); + WRITE(p, "};\n"); + + WRITE(p, "void tessellate(out Tess tess) {\n"); + // Calculate current patch position and vertex position(index for the weights) + WRITE(p, " ivec2 spline_num_patches = ivec2((base.spline_counts >> 0) & 0xff, (base.spline_counts >> 8) & 0xff);\n"); + WRITE(p, " ivec2 spline_tess = ivec2((base.spline_counts >> 16) & 0xff, (base.spline_counts >> 24) & 0xff);\n"); + + WRITE(p, " int spline_count_u = %s;\n", doBezier ? "spline_num_patches.x * 3 + 1" : "spline_num_patches.x + 3"); + WRITE(p, " int u = gl_InstanceIndex %% spline_num_patches.x;\n"); + WRITE(p, " int v = gl_InstanceIndex / spline_num_patches.x;\n"); + WRITE(p, " ivec2 patch_pos = ivec2(u, v);\n"); + WRITE(p, " ivec2 vertex_pos = ivec2(position.xy);\n"); + if (doSpline) { + WRITE(p, " bvec2 isFirstEdge = not(bvec2(vertex_pos));\n"); // vertex_pos == 0 + WRITE(p, " bvec2 isNotFirstPatch = bvec2(patch_pos);\n"); // patch_pos > 0 + WRITE(p, " vertex_pos += patch_pos * spline_tess;\n"); + } + // Load 4x4 control points + WRITE(p, " vec3 _pos[16];\n"); + WRITE(p, " vec2 _tex[16];\n"); + WRITE(p, " vec4 _col[16];\n"); + WRITE(p, " for (int i = 0; i < 4; i++) {\n"); + WRITE(p, " for (int j = 0; j < 4; j++) {\n"); + WRITE(p, " int idx = (i + v%s) * spline_count_u + (j + u%s);\n", doBezier ? " * 3" : "", doBezier ? " * 3" : ""); + WRITE(p, " _pos[i * 4 + j] = tess_data.data[idx].pos.xyz;\n"); + if (doTexture && hasTexcoord && hasTexcoordTess) + WRITE(p, " _tex[i * 4 + j] = tess_data.data[idx].uv.xy;\n"); + if (hasColor && hasColorTess) + WRITE(p, " _col[i * 4 + j] = tess_data.data[idx].color;\n"); + WRITE(p, " }\n"); + WRITE(p, " }\n"); + + // Basis polynomials as weight coefficients + WRITE(p, " vec4 basis_u = tess_weights_u.data[vertex_pos.x].basis;\n"); + WRITE(p, " vec4 basis_v = tess_weights_v.data[vertex_pos.y].basis;\n"); + if (doSpline) { + WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n"); + WRITE(p, " basis_u = vec4(basis_u.yzw, 0);\n"); + WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n"); + WRITE(p, " basis_v = vec4(basis_v.yzw, 0);\n"); + } + + // Tessellate + WRITE(p, " tess.pos = tess_sample(_pos, basis_u, basis_v);\n"); + if (doTexture && hasTexcoord) { + if (hasTexcoordTess) + WRITE(p, " tess.tex = tess_sample(_tex, basis_u, basis_v);\n"); + else + WRITE(p, " tess.tex = normal.xy + vec2(patch_pos);\n"); + } + if (hasColor) { + if (hasColorTess) + WRITE(p, " tess.col = tess_sample(_col, basis_u, basis_v);\n"); + else + WRITE(p, " tess.col = tess_data.data[0].color;\n"); + } + if (hasNormal) { + // Derivatives as weight coefficients + WRITE(p, " vec4 deriv_u = tess_weights_u.data[vertex_pos.x].deriv;\n"); + WRITE(p, " vec4 deriv_v = tess_weights_v.data[vertex_pos.y].deriv;\n"); + if (doSpline) { + WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n"); + WRITE(p, " deriv_u = vec4(deriv_u.yzw, 0);\n"); + WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n"); + WRITE(p, " deriv_v = vec4(deriv_v.yzw, 0);\n"); + } + + WRITE(p, " vec3 du = tess_sample(_pos, deriv_u, basis_v);\n"); + WRITE(p, " vec3 dv = tess_sample(_pos, basis_u, deriv_v);\n"); + WRITE(p, " tess.nrm = normalize(cross(du, dv));\n"); + } + WRITE(p, "}\n"); } WRITE(p, "void main() {\n"); @@ -288,77 +369,13 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { // Step 1: World Transform / Skinning if (!enableBones) { if (doBezier || doSpline) { - WRITE(p, " ivec2 spline_num_patches = ivec2((base.spline_counts >> 0) & 0xff, (base.spline_counts >> 8) & 0xff);\n"); - WRITE(p, " ivec2 spline_tess = ivec2((base.spline_counts >> 16) & 0xff, (base.spline_counts >> 24) & 0xff);\n"); - - WRITE(p, " int spline_count_u = %s;\n", doBezier ? "spline_num_patches.x * 3 + 1" : "spline_num_patches.x + 3"); - WRITE(p, " int u = gl_InstanceIndex %% spline_num_patches.x;\n"); - WRITE(p, " int v = gl_InstanceIndex / spline_num_patches.x;\n"); - WRITE(p, " ivec2 patch_pos = ivec2(u, v);\n"); - WRITE(p, " ivec2 vertex_pos = ivec2(position.xy);\n"); - if (doSpline) { - WRITE(p, " bvec2 isFirstEdge = not(bvec2(vertex_pos));\n"); // vertex_pos == 0 - WRITE(p, " bvec2 isNotFirstPatch = bvec2(patch_pos);\n"); // patch_pos > 0 - WRITE(p, " vertex_pos += patch_pos * spline_tess;\n"); - } - // Load 4x4 control points - WRITE(p, " vec3 _pos[16];\n"); - WRITE(p, " vec2 _tex[16];\n"); - WRITE(p, " vec4 _col[16];\n"); - WRITE(p, " for (int i = 0; i < 4; i++) {\n"); - WRITE(p, " for (int j = 0; j < 4; j++) {\n"); - WRITE(p, " int idx = (i + v%s) * spline_count_u + (j + u%s);\n", doBezier ? " * 3" : "", doBezier ? " * 3" : ""); - WRITE(p, " _pos[i * 4 + j] = tess_data.data[idx].pos.xyz;\n"); - if (doTexture && hasTexcoord && hasTexcoordTess) - WRITE(p, " _tex[i * 4 + j] = tess_data.data[idx].uv.xy;\n"); - if (hasColor && hasColorTess) - WRITE(p, " _col[i * 4 + j] = tess_data.data[idx].color;\n"); - WRITE(p, " }\n"); - WRITE(p, " }\n"); + // Hardware tessellation + WRITE(p, " Tess tess;\n"); + WRITE(p, " tessellate(tess);\n"); - // Basis polynomials as weight coefficients - WRITE(p, " vec4 basis_u = tess_weights_u.data[vertex_pos.x].basis;\n"); - WRITE(p, " vec4 basis_v = tess_weights_v.data[vertex_pos.y].basis;\n"); - if (doSpline) { - WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n"); - WRITE(p, " basis_u = vec4(basis_u.yzw, 0);\n"); - WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n"); - WRITE(p, " basis_v = vec4(basis_v.yzw, 0);\n"); - } - - // Tessellate - WRITE(p, " vec3 pos = tess_sample(_pos, basis_u, basis_v);\n"); - if (doTexture && hasTexcoord) { - if (hasTexcoordTess) - WRITE(p, " vec2 tex = tess_sample(_tex, basis_u, basis_v);\n"); - else - WRITE(p, " vec2 tex = normal.xy + vec2(patch_pos);\n"); - } - if (hasColor) { - if (hasColorTess) - WRITE(p, " vec4 col = tess_sample(_col, basis_u, basis_v);\n"); - else - WRITE(p, " vec4 col = tess_data.data[0].color;\n"); - } - if (hasNormal) { - // Derivatives as weight coefficients - WRITE(p, " vec4 deriv_u = tess_weights_u.data[vertex_pos.x].deriv;\n"); - WRITE(p, " vec4 deriv_v = tess_weights_v.data[vertex_pos.y].deriv;\n"); - if (doSpline) { - WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n"); - WRITE(p, " deriv_u = vec4(deriv_u.yzw, 0);\n"); - WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n"); - WRITE(p, " deriv_v = vec4(deriv_v.yzw, 0);\n"); - } - - WRITE(p, " vec3 du = tess_sample(_pos, deriv_u, basis_v);\n"); - WRITE(p, " vec3 dv = tess_sample(_pos, basis_u, deriv_v);\n"); - WRITE(p, " vec3 nrm = cross(du, dv);\n"); - WRITE(p, " nrm = normalize(nrm);\n"); - } - WRITE(p, " vec3 worldpos = vec4(pos.xyz, 1.0) * base.world_mtx;\n"); + WRITE(p, " vec3 worldpos = vec4(tess.pos.xyz, 1.0) * base.world_mtx;\n"); if (hasNormal) { - WRITE(p, " mediump vec3 worldnormal = normalize(vec4(%snrm, 0.0) * base.world_mtx);\n", flipNormalTess ? "-" : ""); + WRITE(p, " mediump vec3 worldnormal = normalize(vec4(%stess.nrm, 0.0) * base.world_mtx);\n", flipNormalTess ? "-" : ""); } else { WRITE(p, " mediump vec3 worldnormal = vec3(0.0, 0.0, 1.0);\n"); } @@ -415,9 +432,9 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { const char *diffuseStr = ((matUpdate & 2) && hasColor) ? "color0.rgb" : "light.matdiffuse"; const char *specularStr = ((matUpdate & 4) && hasColor) ? "color0.rgb" : "light.matspecular.rgb"; if (doBezier || doSpline) { - ambientStr = (matUpdate & 1) && hasColor ? "col" : "base.matambientalpha"; - diffuseStr = (matUpdate & 2) && hasColor ? "col.rgb" : "light.matdiffuse"; - specularStr = (matUpdate & 4) && hasColor ? "col.rgb" : "light.matspecular.rgb"; + ambientStr = (matUpdate & 1) && hasColor ? "tess.col" : "base.matambientalpha"; + diffuseStr = (matUpdate & 2) && hasColor ? "tess.col.rgb" : "light.matdiffuse"; + specularStr = (matUpdate & 4) && hasColor ? "tess.col.rgb" : "light.matspecular.rgb"; } bool diffuseIsZero = true; @@ -538,7 +555,7 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { // Lighting doesn't affect color. if (hasColor) { if (doBezier || doSpline) - WRITE(p, " v_color0 = col;\n"); + WRITE(p, " v_color0 = tess.col;\n"); else WRITE(p, " v_color0 = color0;\n"); } else { @@ -559,7 +576,7 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { if (scaleUV) { if (hasTexcoord) { if (doBezier || doSpline) - WRITE(p, " v_texcoord = vec3(tex.xy * base.uvscaleoffset.xy + base.uvscaleoffset.zw, 0.0);\n"); + WRITE(p, " v_texcoord = vec3(tess.tex.xy * base.uvscaleoffset.xy + base.uvscaleoffset.zw, 0.0);\n"); else WRITE(p, " v_texcoord = vec3(texcoord.xy * base.uvscaleoffset.xy, 0.0);\n"); } else { @@ -568,7 +585,7 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { } else { if (hasTexcoord) { if (doBezier || doSpline) - WRITE(p, " v_texcoord = vec3(tex.xy * base.uvscaleoffset.xy + base.uvscaleoffset.zw, 0.0);\n"); + WRITE(p, " v_texcoord = vec3(tess.tex.xy * base.uvscaleoffset.xy + base.uvscaleoffset.zw, 0.0);\n"); else WRITE(p, " v_texcoord = vec3(texcoord.xy * base.uvscaleoffset.xy + base.uvscaleoffset.zw, 0.0);\n"); } else {