From 6bc9a525f800cbdbc80b790d43a4ac81d947016f Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 16 Apr 2015 18:14:46 +0200 Subject: [PATCH 1/5] Spline: remove n and m, confusing --- GPU/Common/SplineCommon.cpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index fdf441749..7df0db85e 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -294,16 +294,10 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp // Full (mostly) correct tessellation of spline patches. // Not very fast. - // First, generate knot vectors. - int n = spatch.count_u - 1; - int m = spatch.count_v - 1; - - - - float *knot_u = new float[n + 5]; - float *knot_v = new float[m + 5]; - spline_knot(n, spatch.type_u, knot_u); - spline_knot(m, spatch.type_v, knot_v); + float *knot_u = new float[spatch.count_u + 4]; + float *knot_v = new float[spatch.count_v + 4]; + spline_knot(spatch.count_u - 1, spatch.type_u, knot_u); + spline_knot(spatch.count_v - 1, spatch.type_v, knot_v); // Increase tesselation based on the size. Should be approximately right? int patch_div_s = (spatch.count_u - 3) * gstate.getPatchDivisionU(); @@ -330,11 +324,11 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp bool computeNormals = gstate.isLightingEnabled(); for (int tile_v = 0; tile_v < patch_div_t + 1; tile_v++) { - float v = ((float)tile_v * (float)(m - 2) / (float)(patch_div_t + 0.00001f)); // epsilon to prevent division by 0 in spline_s + float v = ((float)tile_v * (float)(spatch.count_v - 3) / (float)(patch_div_t + 0.00001f)); // epsilon to prevent division by 0 in spline_s if (v < 0.0f) v = 0.0f; for (int tile_u = 0; tile_u < patch_div_s + 1; tile_u++) { - float u = ((float)tile_u * (float)(n - 2) / (float)(patch_div_s + 0.00001f)); + float u = ((float)tile_u * (float)(spatch.count_u - 3) / (float)(patch_div_s + 0.00001f)); if (u < 0.0f) u = 0.0f; SimpleVertex *vert = &vertices[tile_v * (patch_div_s + 1) + tile_u]; From b3305246a38e62d7eb596afbfc389fd11286f1ef Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 16 Apr 2015 18:18:49 +0200 Subject: [PATCH 2/5] Spline: Not that it should matter, but move the patch_div clamping down after the subsampling --- GPU/Common/SplineCommon.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 7df0db85e..1f3ea4662 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -307,15 +307,15 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp patch_div_t /= quality; } - if (patch_div_s < 2) patch_div_s = 2; - if (patch_div_t < 2) patch_div_t = 2; - // Downsample until it fits, in case crazy tesselation factors are sent. while ((patch_div_s + 1) * (patch_div_t + 1) > maxVertices) { patch_div_s /= 2; patch_div_t /= 2; } + if (patch_div_s < 2) patch_div_s = 2; + if (patch_div_t < 2) patch_div_t = 2; + // First compute all the vertices and put them in an array SimpleVertex *&vertices = (SimpleVertex*&)dest; From 2e38762708f93052c14da6626e3f24fc3e112b32 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 16 Apr 2015 18:22:08 +0200 Subject: [PATCH 3/5] Spline: Add commented-out sanity check for debugging --- GPU/Common/SplineCommon.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 1f3ea4662..4f349cd47 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -15,6 +15,13 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +/* +#define WIN32_LEAN_AND_MEAN +#include +#undef min +#undef max +*/ + #include #include @@ -322,6 +329,8 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp float tu_width = (float)spatch.count_u - 3.0f; float tv_height = (float)spatch.count_v - 3.0f; + // int max_idx = spatch.count_u * spatch.count_v; + bool computeNormals = gstate.isLightingEnabled(); for (int tile_v = 0; tile_v < patch_div_t + 1; tile_v++) { float v = ((float)tile_v * (float)(spatch.count_v - 3) / (float)(patch_div_t + 0.00001f)); // epsilon to prevent division by 0 in spline_s @@ -378,6 +387,13 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp Vec4f fv = Vec4f::AssignToAll(f); #endif int idx = spatch.count_u * (iv + jj) + (iu + ii); + /* + if (idx >= max_idx) { + char temp[512]; + snprintf(temp, sizeof(temp), "count_u: %d count_v: %d patch_w: %d patch_h: %d ii: %d jj: %d iu: %d iv: %d patch_div_s: %d patch_div_t: %d\n", spatch.count_u, spatch.count_v, patch_w, patch_h, ii, jj, iu, iv, patch_div_s, patch_div_t); + OutputDebugStringA(temp); + DebugBreak(); + }*/ SimpleVertex *a = spatch.points[idx]; AccumulateWeighted(vert_pos, a->pos, fv); if (origTc) { From 6587f4de8f63e4a238837d443c9060e76e988021 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 16 Apr 2015 18:29:50 +0200 Subject: [PATCH 4/5] Spline: Fix #7684 by removing awful epsilons that "fixed" off-by-ones depending on vertex count because of fp rounding. --- GPU/Common/SplineCommon.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 4f349cd47..a3aeddc91 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -332,12 +332,16 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp // int max_idx = spatch.count_u * spatch.count_v; bool computeNormals = gstate.isLightingEnabled(); + + float one_over_patch_div_s = 1.0f / (float)(patch_div_s); + float one_over_patch_div_t = 1.0f / (float)(patch_div_t); + for (int tile_v = 0; tile_v < patch_div_t + 1; tile_v++) { - float v = ((float)tile_v * (float)(spatch.count_v - 3) / (float)(patch_div_t + 0.00001f)); // epsilon to prevent division by 0 in spline_s + float v = (float)tile_v * (float)(spatch.count_v - 3) * one_over_patch_div_t; if (v < 0.0f) v = 0.0f; for (int tile_u = 0; tile_u < patch_div_s + 1; tile_u++) { - float u = ((float)tile_u * (float)(spatch.count_u - 3) / (float)(patch_div_s + 0.00001f)); + float u = (float)tile_u * (float)(spatch.count_u - 3) * one_over_patch_div_s; if (u < 0.0f) u = 0.0f; SimpleVertex *vert = &vertices[tile_v * (patch_div_s + 1) + tile_u]; @@ -357,16 +361,23 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp vert->uv[0] = 0.0f; vert->uv[1] = 0.0f; } else { - vert->uv[0] = tu_width * ((float)tile_u / (float)patch_div_s); - vert->uv[1] = tv_height * ((float)tile_v / (float)patch_div_t); + vert->uv[0] = tu_width * ((float)tile_u * one_over_patch_div_s); + vert->uv[1] = tv_height * ((float)tile_v * one_over_patch_div_t); } + // Collect influences from surrounding control points. float u_weights[4]; float v_weights[4]; int iu = (int)u; int iv = (int)v; + + // TODO: Would really like to fix the surrounding logic somehow to get rid of these but I can't quite get it right.. + // Without the previous epsilons and with large count_u, we will end up doing an out of bounds access later without these. + if (iu >= spatch.count_u - 3) iu = spatch.count_u - 4; + if (iv >= spatch.count_v - 3) iv = spatch.count_v - 4; + spline_n_4(iu, u, knot_u, u_weights); spline_n_4(iv, v, knot_v, v_weights); From 68893c763fe9d88868541b92a8f4195e3e170421 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 16 Apr 2015 18:31:28 +0200 Subject: [PATCH 5/5] Spline: Fix an unrelated kind-of-bug --- GPU/Common/SplineCommon.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index a3aeddc91..d5fccea3a 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -382,8 +382,8 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp spline_n_4(iv, v, knot_v, v_weights); // Handle degenerate patches. without this, spatch.points[] may read outside the number of initialized points. - int patch_w = std::min(spatch.count_u, 4); - int patch_h = std::min(spatch.count_v, 4); + int patch_w = std::min(spatch.count_u - iu, 4); + int patch_h = std::min(spatch.count_v - iv, 4); for (int ii = 0; ii < patch_w; ++ii) { for (int jj = 0; jj < patch_h; ++jj) {