diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 7e07807228..6fb31015bb 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -214,8 +214,8 @@ public: const float inv_tess = 1.0f / (float)tess; for (int i = 0; i < num_patches; ++i) { - const int _tess = (i == num_patches - 1) ? (tess + 1) : tess; - for (int j = 0; j < _tess; ++j) { + const int start = (i == 0) ? 0 : 1; + for (int j = start; j <= tess; ++j) { const int index = i * tess + j; const float t = (float)index * inv_tess; CalcWeights(t, knots + i, divs[i], weights[index]); @@ -346,9 +346,9 @@ public: const float inv_v = 1.0f / (float)patch.tess_v; for (int patch_u = 0; patch_u < patch.num_patches_u; ++patch_u) { - const int tess_u = patch.GetTessU(patch_u); + const int start_u = patch.GetTessStart(patch_u); for (int patch_v = 0; patch_v < patch.num_patches_v; ++patch_v) { - const int tess_v = patch.GetTessV(patch_v); + const int start_v = patch.GetTessStart(patch_v); // Prepare 4x4 control points to tessellate const int idx = patch.GetPointIndex(patch_u, patch_v); @@ -358,7 +358,7 @@ public: Tessellator tess_tex(tex, idx_v); Tessellator tess_nrm(pos, idx_v); - for (int tile_u = 0; tile_u < tess_u; ++tile_u) { + for (int tile_u = start_u; tile_u <= patch.tess_u; ++tile_u) { const int index_u = patch.GetIndexU(patch_u, tile_u); const Weight &wu = weights.u[index_u]; @@ -371,7 +371,7 @@ public: if (sampleNrm) tess_nrm.SampleU(wu.deriv); - for (int tile_v = 0; tile_v < tess_v; ++tile_v) { + for (int tile_v = start_v; tile_v <= patch.tess_v; ++tile_v) { const int index_v = patch.GetIndexV(patch_v, tile_v); const Weight &wv = weights.v[index_v]; diff --git a/GPU/Common/SplineCommon.h b/GPU/Common/SplineCommon.h index b15bd4d2e2..7fa9585a9a 100644 --- a/GPU/Common/SplineCommon.h +++ b/GPU/Common/SplineCommon.h @@ -80,8 +80,7 @@ struct BezierPatch { } } - int GetTessU(int patch_u) const { return tess_u + 1; } - int GetTessV(int patch_v) const { return tess_v + 1; } + int GetTessStart(int patch) const { return 0; } int GetPointIndex(int patch_u, int patch_v) const { return patch_v * 3 * count_u + patch_u * 3;} @@ -142,8 +141,7 @@ struct SplinePatchLocal { num_divisions_v = num_patches_v * tess_v; } - int GetTessU(int patch_u) const { return (patch_u == num_patches_u - 1) ? tess_u + 1 : tess_u; } - int GetTessV(int patch_v) const { return (patch_v == num_patches_v - 1) ? tess_v + 1 : tess_v; } + int GetTessStart(int patch) const { return (patch == 0) ? 0 : 1; } int GetPointIndex(int patch_u, int patch_v) const { return patch_v * count_u + patch_u;} diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 62ad03c781..ab771971ba 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -357,10 +357,8 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage WRITE(p, " int2 patch_pos = int2(u, v);\n"); WRITE(p, " int2 vertex_pos = int2(In.position.xy);\n"); if (doSpline) { - WRITE(p, " if ((vertex_pos.x == spline_tess.x) && (u < spline_num_patches.x - 1))\n"); - WRITE(p, " u++;\n"); // Use next patch position - WRITE(p, " if ((vertex_pos.y == spline_tess.y) && (v < spline_num_patches.y - 1))\n"); - WRITE(p, " v++;\n"); // Use next patch position + 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 @@ -382,6 +380,12 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage // 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"); @@ -401,6 +405,12 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage // 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"); diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index d7f8a39f45..895536fc04 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -446,10 +446,8 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, WRITE(p, " ivec2 patch_pos = ivec2(u, v);\n"); WRITE(p, " ivec2 vertex_pos = ivec2(position.xy);\n"); if (doSpline) { - WRITE(p, " if ((vertex_pos.x == u_spline_tess.x) && (u < u_spline_num_patches.x - 1))\n"); - WRITE(p, " u++;\n"); // Use next patch position - WRITE(p, " if ((vertex_pos.y == u_spline_tess.y) && (v < u_spline_num_patches.y - 1))\n"); - WRITE(p, " v++;\n"); // Use next patch position + 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 @@ -470,6 +468,12 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, // 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, " vec3 pos = tess_sample(_pos, basis_u, basis_v);\n"); @@ -489,6 +493,12 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, // 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"); diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index 6598e4000a..99b799cfcd 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -297,10 +297,8 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { WRITE(p, " ivec2 patch_pos = ivec2(u, v);\n"); WRITE(p, " ivec2 vertex_pos = ivec2(position.xy);\n"); if (doSpline) { - WRITE(p, " if ((vertex_pos.x == spline_tess.x) && (u < spline_num_patches.x - 1))\n"); - WRITE(p, " u++;\n"); // Use next patch position - WRITE(p, " if ((vertex_pos.y == spline_tess.y) && (v < spline_num_patches.y - 1))\n"); - WRITE(p, " v++;\n"); // Use next patch position + 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 @@ -321,6 +319,12 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { // 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"); @@ -340,6 +344,12 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { // 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");