Merge pull request #7688 from hrydgard/spline-fix

Workaround crashes in spline code, fixing #7684
This commit is contained in:
Unknown W. Brackets 2015-04-16 09:45:07 -07:00
commit 5d704e48c1

View File

@ -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 <Windows.h>
#undef min
#undef max
*/
#include <string.h>
#include <algorithm>
@ -294,16 +301,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();
@ -313,28 +314,34 @@ 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;
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();
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)(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) * 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)(n - 2) / (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];
@ -354,22 +361,29 @@ 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);
// 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) {
@ -384,6 +398,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) {