From 7383e90c19d2d2450a481479c5d826320e39b12e Mon Sep 17 00:00:00 2001 From: weihuoya Date: Thu, 23 Aug 2018 12:46:09 +0800 Subject: [PATCH 001/347] handle cullface, help to #10597 --- GPU/Common/DrawEngineCommon.cpp | 8 ++++---- GPU/GPUCommon.cpp | 21 ++++++++++----------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 95d6d5ad2e..809811bc30 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -522,7 +522,7 @@ void DrawEngineCommon::DecodeVertsStep(u8 *dest, int &i, int &decodedVerts) { decodedVerts += indexUpperBound - indexLowerBound + 1; bool clockwise = true; - if (dc.cullMode != -1 && gstate.isCullEnabled() && gstate.getCullMode() != dc.cullMode) { + if (gstate.isCullEnabled() && gstate.getCullMode() != dc.cullMode) { clockwise = false; } indexGen.AddPrim(dc.prim, dc.vertexCount, clockwise); @@ -550,7 +550,7 @@ void DrawEngineCommon::DecodeVertsStep(u8 *dest, int &i, int &decodedVerts) { case GE_VTYPE_IDX_8BIT >> GE_VTYPE_IDX_SHIFT: for (int j = i; j <= lastMatch; j++) { bool clockwise = true; - if (drawCalls[j].cullMode != -1 && gstate.isCullEnabled() && gstate.getCullMode() != drawCalls[j].cullMode) { + if (gstate.isCullEnabled() && gstate.getCullMode() != drawCalls[j].cullMode) { clockwise = false; } indexGen.TranslatePrim(drawCalls[j].prim, drawCalls[j].vertexCount, (const u8 *)drawCalls[j].inds, indexLowerBound, clockwise); @@ -559,7 +559,7 @@ void DrawEngineCommon::DecodeVertsStep(u8 *dest, int &i, int &decodedVerts) { case GE_VTYPE_IDX_16BIT >> GE_VTYPE_IDX_SHIFT: for (int j = i; j <= lastMatch; j++) { bool clockwise = true; - if (drawCalls[j].cullMode != -1 && gstate.isCullEnabled() && gstate.getCullMode() != drawCalls[j].cullMode) { + if (gstate.isCullEnabled() && gstate.getCullMode() != drawCalls[j].cullMode) { clockwise = false; } indexGen.TranslatePrim(drawCalls[j].prim, drawCalls[j].vertexCount, (const u16_le *)drawCalls[j].inds, indexLowerBound, clockwise); @@ -568,7 +568,7 @@ void DrawEngineCommon::DecodeVertsStep(u8 *dest, int &i, int &decodedVerts) { case GE_VTYPE_IDX_32BIT >> GE_VTYPE_IDX_SHIFT: for (int j = i; j <= lastMatch; j++) { bool clockwise = true; - if (drawCalls[j].cullMode != -1 && gstate.isCullEnabled() && gstate.getCullMode() != drawCalls[j].cullMode) { + if (gstate.isCullEnabled() && gstate.getCullMode() != drawCalls[j].cullMode) { clockwise = false; } indexGen.TranslatePrim(drawCalls[j].prim, drawCalls[j].vertexCount, (const u32_le *)drawCalls[j].inds, indexLowerBound, clockwise); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 6339504d0d..2474cda362 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1533,7 +1533,7 @@ void GPUCommon::Execute_Prim(u32 op, u32 diff) { UpdateUVScaleOffset(); // cull mode - int cullMode = gstate.isCullEnabled() ? gstate.getCullMode() : -1; + int cullMode = gstate.getCullMode(); uint32_t vertTypeID = GetVertTypeID(vertexType, gstate.getUVGenMode()); drawEngineCommon_->SubmitPrim(verts, inds, prim, count, vertTypeID, cullMode, &bytesRead); @@ -1582,13 +1582,6 @@ void GPUCommon::Execute_Prim(u32 op, u32 diff) { inds = Memory::GetPointerUnchecked(gstate_c.indexAddr); } - if (newPrim != GE_PRIM_TRIANGLE_STRIP && cullMode != -1 && cullMode != gstate.getCullMode()) { - DEBUG_LOG(G3D, "flush cull mode before prim: %d", newPrim); - drawEngineCommon_->DispatchFlush(); - gstate.cmdmem[GE_CMD_CULL] ^= 1; - gstate_c.Dirty(DIRTY_RASTER_STATE); - } - drawEngineCommon_->SubmitPrim(verts, inds, newPrim, count, vertTypeID, cullMode, &bytesRead); AdvanceVerts(vertexType, count, bytesRead); totalVertCount += count; @@ -1616,8 +1609,14 @@ void GPUCommon::Execute_Prim(u32 op, u32 diff) { case GE_CMD_BASE: gstate.cmdmem[GE_CMD_BASE] = data; break; + case GE_CMD_CULLFACEENABLE: + // Earth Defence Force 2 + if (gstate.cmdmem[GE_CMD_CULLFACEENABLE] != data) { + goto bail; + } + break; case GE_CMD_CULL: - // flip face by indices for GE_PRIM_TRIANGLE_STRIP + // flip face by indices for triangles cullMode = data & 1; break; case GE_CMD_NOP: @@ -1679,10 +1678,10 @@ bail: UpdatePC(currentList->pc, currentList->pc + cmdCount * 4); currentList->pc += cmdCount * 4; // flush back cull mode - if (cullMode != -1 && cullMode != gstate.getCullMode()) { - drawEngineCommon_->DispatchFlush(); + if (cullMode != gstate.getCullMode()) { gstate.cmdmem[GE_CMD_CULL] ^= 1; gstate_c.Dirty(DIRTY_RASTER_STATE); + drawEngineCommon_->DispatchFlush(); } } From 5c7284f8f2534bf408c81f68009ac1f97722cd35 Mon Sep 17 00:00:00 2001 From: xebra Date: Mon, 29 Jan 2018 18:25:38 +0900 Subject: [PATCH 002/347] [spline/bezier]Get rid of divisions in spline weights calculation. --- GPU/Common/SplineCommon.cpp | 122 ++++++++++++++++++++---------------- 1 file changed, 69 insertions(+), 53 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 7af7926dde..8da96cb259 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -151,50 +151,56 @@ static Vec3f Bernstein3DDerivative(const Vec3f& p0, const Vec3f& p1, const Vec3f return p0 * bern0deriv(x) + p1 * bern1deriv(x) + p2 * bern2deriv(x) + p3 * bern3deriv(x); } -static void spline_n_4(int i, float t, float *knot, float *splineVal) { - knot += i + 1; +struct KnotDiv { + float _3_0 = 1.0f / 3.0f; + float _4_1 = 1.0f / 3.0f; + float _5_2 = 1.0f / 3.0f; + float _3_1 = 1.0f / 2.0f; + float _4_2 = 1.0f / 2.0f; + float _3_2 = 1.0f; // Always 1 +}; + +static void spline_n_4(int i, float t, float *knot, const KnotDiv &div, float *splineVal) { + knot += i; #ifdef _M_SSE - const __m128 knot012 = _mm_loadu_ps(&knot[0]); - const __m128 knot345 = _mm_loadu_ps(&knot[3]); - const __m128 t012 = _mm_sub_ps(_mm_set_ps1(t), knot012); - const __m128 f30_41_52 = _mm_div_ps(t012, _mm_sub_ps(knot345, knot012)); + const __m128 knot012 = _mm_loadu_ps(knot); + const __m128 t012 = _mm_sub_ps(_mm_set_ps1(t), knot012); + const __m128 f30_41_52 = _mm_mul_ps(t012, _mm_loadu_ps(&div._3_0)); + const __m128 f52_31_42 = _mm_mul_ps(t012, _mm_loadu_ps(&div._5_2)); + const float &f32 = t012.m128_f32[2]; - const __m128 knot343 = _mm_shuffle_ps(knot345, knot345, _MM_SHUFFLE(3, 0, 1, 0)); - const __m128 knot122 = _mm_shuffle_ps(knot012, knot012, _MM_SHUFFLE(3, 2, 2, 1)); - const __m128 t122 = _mm_shuffle_ps(t012, t012, _MM_SHUFFLE(3, 2, 2, 1)); - const __m128 f31_42_32 = _mm_div_ps(t122, _mm_sub_ps(knot343, knot122)); - - // It's still faster to use SSE, even with this. - alignas(16) float ff30_41_52[4]; - alignas(16) float ff31_42_32[4]; - _mm_store_ps(ff30_41_52, f30_41_52); - _mm_store_ps(ff31_42_32, f31_42_32); - - const float &f30 = ff30_41_52[0]; - const float &f41 = ff30_41_52[1]; - const float &f52 = ff30_41_52[2]; - const float &f31 = ff31_42_32[0]; - const float &f42 = ff31_42_32[1]; - const float &f32 = ff31_42_32[2]; + // Following comments are for explains order of the multiply. + // float a = (1-f30)*(1-f31); + // float c = (1-f41)*(1-f42); + // float b = ( f31 * f41); + // float d = ( f42 * f52); + const __m128 f30_41_31_42 = _mm_shuffle_ps(f30_41_52, f52_31_42, _MM_SHUFFLE(2, 1, 1, 0)); + const __m128 f31_42_41_52 = _mm_shuffle_ps(f52_31_42, f30_41_52, _MM_SHUFFLE(2, 1, 2, 1)); + const __m128 c1_1_0_0 = { 1, 1, 0, 0 }; + const __m128 acbd = _mm_mul_ps(_mm_sub_ps(c1_1_0_0, f30_41_31_42), _mm_sub_ps(c1_1_0_0, f31_42_41_52)); + const float &a = acbd.m128_f32[0]; + const float &b = acbd.m128_f32[2]; + const float &c = acbd.m128_f32[1]; + const float &d = acbd.m128_f32[3]; #else // TODO: Maybe compilers could be coaxed into vectorizing this code without the above explicitly... float t0 = (t - knot[0]); float t1 = (t - knot[1]); float t2 = (t - knot[2]); - // TODO: All our knots are integers so we should be able to get rid of these divisions (How?) - float f30 = t0/(knot[3]-knot[0]); - float f41 = t1/(knot[4]-knot[1]); - float f52 = t2/(knot[5]-knot[2]); - float f31 = t1/(knot[3]-knot[1]); - float f42 = t2/(knot[4]-knot[2]); - float f32 = t2/(knot[3]-knot[2]); -#endif + + float f30 = t0 * div._3_0; + float f41 = t1 * div._4_1; + float f52 = t2 * div._5_2; + float f31 = t1 * div._3_1; + float f42 = t2 * div._4_2; + float f32 = t2 * div._3_2; float a = (1-f30)*(1-f31); float b = (f31*f41); float c = (1-f41)*(1-f42); float d = (f42*f52); +#endif splineVal[0] = a-(a*f32); splineVal[1] = 1-a-b+((a+b+c-1)*f32); @@ -203,25 +209,33 @@ static void spline_n_4(int i, float t, float *knot, float *splineVal) { } // knot should be an array sized n + 5 (n + 1 + 1 + degree (cubic)) -static void spline_knot(int n, int type, float *knot) { - memset(knot, 0, sizeof(float) * (n + 5)); - for (int i = 0; i < n - 1; ++i) - knot[i + 3] = (float)i; +static void spline_knot(int n, int type, float *knots, KnotDiv *divs) { + // Basic theory (-2 to +3), optimized with KnotDiv (-2 to +0) + // for (int i = 0; i < n + 5; ++i) { + for (int i = 0; i < n + 2; ++i) { + knots[i] = (float)i - 2; + } - if ((type & 1) == 0) { - knot[0] = -3; - knot[1] = -2; - knot[2] = -1; - } - if ((type & 2) == 0) { - knot[n + 2] = (float)(n - 1); - knot[n + 3] = (float)(n); - knot[n + 4] = (float)(n + 1); - } else { - knot[n + 2] = (float)(n - 2); - knot[n + 3] = (float)(n - 2); - knot[n + 4] = (float)(n - 2); - } + if ((type & 1) != 0) { + knots[0] = 0; + knots[1] = 0; + + divs[0]._3_0 = 1.0f; + divs[0]._4_1 = 1.0f / 2.0f; + divs[0]._3_1 = 1.0f; + if (n > 1) + divs[1]._3_0 = 1.0f / 2.0f; + } + if ((type & 2) != 0) { + // knots[n + 2] = (float)n; // Got rid of this line optimized with KnotDiv + // knots[n + 3] = (float)n; // Got rid of this line optimized with KnotDiv + // knots[n + 4] = (float)n; // Got rid of this line optimized with KnotDiv + divs[n - 1]._4_1 = 1.0f / 2.0f; + divs[n - 1]._5_2 = 1.0f; + divs[n - 1]._4_2 = 1.0f; + if (n > 1) + divs[n - 2]._5_2 = 1.0f / 2.0f; + } } bool CanUseHardwareTessellation(GEPatchPrimType prim) { @@ -359,8 +373,10 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp 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); + KnotDiv *divs_u = new KnotDiv[spatch.count_u - 3]; + KnotDiv *divs_v = new KnotDiv[spatch.count_v - 3]; + spline_knot(spatch.count_u - 3, spatch.type_u, knot_u, divs_u); + spline_knot(spatch.count_v - 3, spatch.type_v, knot_v, divs_v); // Increase tessellation based on the size. Should be approximately right? int patch_div_s = (spatch.count_u - 3) * spatch.tess_u; @@ -439,8 +455,8 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp 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); + spline_n_4(iu, u, knot_u, divs_u[iu], u_weights); + spline_n_4(iv, v, knot_v, divs_v[iv], 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 - iu, 4); From a9ac860da2ebafc7ee37d53ea93e5b759322d070 Mon Sep 17 00:00:00 2001 From: xebra Date: Mon, 29 Jan 2018 19:24:42 +0900 Subject: [PATCH 003/347] [spline/bezier]Add spline derivative calculation for normal generation. --- GPU/Common/SplineCommon.cpp | 117 +++++++++++++++--------------------- 1 file changed, 49 insertions(+), 68 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 8da96cb259..18ed96cdd8 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -160,29 +160,33 @@ struct KnotDiv { float _3_2 = 1.0f; // Always 1 }; -static void spline_n_4(int i, float t, float *knot, const KnotDiv &div, float *splineVal) { +static void spline_n_4(int i, float t, float *knot, const KnotDiv &div, float *splineVal, float *derivs) { knot += i; #ifdef _M_SSE - const __m128 knot012 = _mm_loadu_ps(knot); - const __m128 t012 = _mm_sub_ps(_mm_set_ps1(t), knot012); - const __m128 f30_41_52 = _mm_mul_ps(t012, _mm_loadu_ps(&div._3_0)); - const __m128 f52_31_42 = _mm_mul_ps(t012, _mm_loadu_ps(&div._5_2)); - const float &f32 = t012.m128_f32[2]; + const __m128 knot012 = _mm_loadu_ps(knot); + const __m128 t012 = _mm_sub_ps(_mm_set_ps1(t), knot012); + const __m128 f30_41_52 = _mm_mul_ps(t012, _mm_loadu_ps(&div._3_0)); + const __m128 f52_31_42 = _mm_mul_ps(t012, _mm_loadu_ps(&div._5_2)); + const float &f32 = t012.m128_f32[2]; - // Following comments are for explains order of the multiply. - // float a = (1-f30)*(1-f31); - // float c = (1-f41)*(1-f42); - // float b = ( f31 * f41); - // float d = ( f42 * f52); - const __m128 f30_41_31_42 = _mm_shuffle_ps(f30_41_52, f52_31_42, _MM_SHUFFLE(2, 1, 1, 0)); - const __m128 f31_42_41_52 = _mm_shuffle_ps(f52_31_42, f30_41_52, _MM_SHUFFLE(2, 1, 2, 1)); - const __m128 c1_1_0_0 = { 1, 1, 0, 0 }; - const __m128 acbd = _mm_mul_ps(_mm_sub_ps(c1_1_0_0, f30_41_31_42), _mm_sub_ps(c1_1_0_0, f31_42_41_52)); - const float &a = acbd.m128_f32[0]; - const float &b = acbd.m128_f32[2]; - const float &c = acbd.m128_f32[1]; - const float &d = acbd.m128_f32[3]; + // Following comments are for explains order of the multiply. +// float a = (1-f30)*(1-f31); +// float c = (1-f41)*(1-f42); +// float b = ( f31 * f41); +// float d = ( f42 * f52); + const __m128 f30_41_31_42 = _mm_shuffle_ps(f30_41_52, f52_31_42, _MM_SHUFFLE(2, 1, 1, 0)); + const __m128 f31_42_41_52 = _mm_shuffle_ps(f52_31_42, f30_41_52, _MM_SHUFFLE(2, 1, 2, 1)); + const __m128 c1_1_0_0 = { 1, 1, 0, 0 }; + const __m128 acbd = _mm_mul_ps(_mm_sub_ps(c1_1_0_0, f30_41_31_42), _mm_sub_ps(c1_1_0_0, f31_42_41_52)); + const float &a = acbd.m128_f32[0]; + const float &b = acbd.m128_f32[2]; + const float &c = acbd.m128_f32[1]; + const float &d = acbd.m128_f32[3]; + + // For derivative + const float &f31 = f30_41_31_42.m128_f32[2]; + const float &f42 = f30_41_31_42.m128_f32[3]; #else // TODO: Maybe compilers could be coaxed into vectorizing this code without the above explicitly... float t0 = (t - knot[0]); @@ -206,6 +210,20 @@ static void spline_n_4(int i, float t, float *knot, const KnotDiv &div, float *s splineVal[1] = 1-a-b+((a+b+c-1)*f32); splineVal[2] = b+((1-b-c-d)*f32); splineVal[3] = d*f32; + + // Derivative + float i1 = (1 - f31) * (1 - f32); + float i2 = f31 * (1 - f32) + (1 - f42) * f32; + float i3 = f42 * f32; + + float f130 = i1 * div._3_0; + float f241 = i2 * div._4_1; + float f352 = i3 * div._5_2; + + derivs[0] = 3 * (0 - f130); + derivs[1] = 3 * (f130 - f241); + derivs[2] = 3 * (f241 - f352); + derivs[3] = 3 * (f352 - 0); } // knot should be an array sized n + 5 (n + 1 + 1 + degree (cubic)) @@ -426,6 +444,9 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp Vec3f vert_pos; vert_pos.SetZero(); Vec3f vert_nrm; + Vec3f du, dv; + du.SetZero(); + dv.SetZero(); if (origNrm) { vert_nrm.SetZero(); } @@ -446,6 +467,8 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp // Collect influences from surrounding control points. float u_weights[4]; float v_weights[4]; + float u_derivs[4]; + float v_derivs[4]; int iu = (int)u; int iv = (int)v; @@ -455,8 +478,8 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp 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, divs_u[iu], u_weights); - spline_n_4(iv, v, knot_v, divs_v[iv], v_weights); + spline_n_4(iu, u, knot_u, divs_u[iu], u_weights, u_derivs); + spline_n_4(iv, v, knot_v, divs_v[iv], v_weights, v_derivs); // Handle degenerate patches. without this, spatch.points[] may read outside the number of initialized points. int patch_w = std::min(spatch.count_u - iu, 4); @@ -493,13 +516,15 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp AccumulateWeighted(vert_color, a_color, fv); } if (origNrm) { - AccumulateWeighted(vert_nrm, a->nrm, fv); + AccumulateWeighted(du, a->pos, Vec4f::AssignToAll(u_derivs[ii] * v_weights[jj])); + AccumulateWeighted(dv, a->pos, Vec4f::AssignToAll(u_weights[ii] * v_derivs[jj])); } } } } vert->pos = vert_pos; if (origNrm) { + vert_nrm = Cross(du, dv); #ifdef _M_SSE const __m128 normalize = SSENormalizeMultiplier(useSSE4, vert_nrm.vec); vert_nrm.vec = _mm_mul_ps(vert_nrm.vec, normalize); @@ -519,52 +544,8 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp delete[] knot_u; delete[] knot_v; - - // Hacky normal generation through central difference. - if (computeNormals && !origNrm) { -#ifdef _M_SSE - const __m128 facing = spatch.patchFacing ? _mm_set_ps1(-1.0f) : _mm_set_ps1(1.0f); -#endif - - for (int v = 0; v < patch_div_t + 1; v++) { - Vec3f vl_pos = vertices[v * (patch_div_s + 1)].pos; - Vec3f vc_pos = vertices[v * (patch_div_s + 1)].pos; - - for (int u = 0; u < patch_div_s + 1; u++) { - const int t = std::max(0, v - 1); - const int r = std::min(patch_div_s, u + 1); - const int b = std::min(patch_div_t, v + 1); - - const Vec3f vr_pos = vertices[v * (patch_div_s + 1) + r].pos; - -#ifdef _M_SSE - const __m128 right = _mm_sub_ps(vr_pos.vec, vl_pos.vec); - - const Vec3f vb_pos = vertices[b * (patch_div_s + 1) + u].pos; - const Vec3f vt_pos = vertices[t * (patch_div_s + 1) + u].pos; - const __m128 down = _mm_sub_ps(vb_pos.vec, vt_pos.vec); - - const __m128 crossed = SSECrossProduct(right, down); - const __m128 normalize = SSENormalizeMultiplier(useSSE4, crossed); - - Vec3f finalNrm = _mm_mul_ps(normalize, _mm_mul_ps(crossed, facing)); - vertices[v * (patch_div_s + 1) + u].nrm = finalNrm; -#else - const Vec3Packedf &right = vr_pos - vl_pos; - const Vec3Packedf &down = vertices[b * (patch_div_s + 1) + u].pos - vertices[t * (patch_div_s + 1) + u].pos; - - vertices[v * (patch_div_s + 1) + u].nrm = Cross(right, down).Normalized(); - if (spatch.patchFacing) { - vertices[v * (patch_div_s + 1) + u].nrm *= -1.0f; - } -#endif - - // Rotate for the next one to the right. - vl_pos = vc_pos; - vc_pos = vr_pos; - } - } - } + delete[] divs_u; + delete[] divs_v; GEPatchPrimType prim_type = spatch.primType; // Tessellate. From a4860b6c808780d4cfb2857d6fd5aaeadbf3dfc8 Mon Sep 17 00:00:00 2001 From: xebra Date: Tue, 30 Jan 2018 10:31:48 +0900 Subject: [PATCH 004/347] [spline/bezier]Managing buffer allocation. # Conflicts: # GPU/Common/SplineCommon.cpp --- GPU/Common/SplineCommon.cpp | 54 ++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 18ed96cdd8..b208d8667d 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -846,10 +846,35 @@ void TessellateBezierPatch(u8 *&dest, u16 *&indices, int &count, int tess_u, int } } +class SimpleBufferManager { +private: + u8 *buf_; + size_t totalSize, maxSize_; +public: + SimpleBufferManager(u8 *buf, size_t maxSize) + : buf_(buf), totalSize(0), maxSize_(maxSize) {} + + u8 *Allocate(size_t size) { + size = (size + 15) & ~15; // Align for 16 bytes + + if ((totalSize + size) > maxSize_) + return nullptr; // No more memory + + size_t tmp = totalSize; + totalSize += size; + return buf_ + tmp; + } +}; + +// This maps GEPatchPrimType to GEPrimitiveType. +const GEPrimitiveType primType[] = { GE_PRIM_TRIANGLES, GE_PRIM_LINES, GE_PRIM_POINTS, GE_PRIM_POINTS }; + void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indices, int tess_u, int tess_v, int count_u, int count_v, int type_u, int type_v, GEPatchPrimType prim_type, bool computeNormals, bool patchFacing, u32 vertType, int *bytesRead) { PROFILE_THIS_SCOPE("spline"); DispatchFlush(); + SimpleBufferManager managedBuf(decoded, DECODED_VERTEX_BUFFER_SIZE); + u16 index_lower_bound = 0; u16 index_upper_bound = count_u * count_v - 1; IndexConverter idxConv(vertType, indices); @@ -865,8 +890,8 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi } // Simplify away bones and morph before proceeding - SimpleVertex *simplified_control_points = (SimpleVertex *)(decoded + 65536 * 12); - u8 *temp_buffer = decoded + 65536 * 18; + SimpleVertex *simplified_control_points = (SimpleVertex *)managedBuf.Allocate(sizeof(SimpleVertex) * index_upper_bound + 1); + u8 *temp_buffer = managedBuf.Allocate(sizeof(SimpleVertex) * count_u * count_v); u32 origVertType = vertType; vertType = NormalizeVertices((u8 *)simplified_control_points, temp_buffer, (u8 *)control_points, index_lower_bound, index_upper_bound, vertType); @@ -878,8 +903,7 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi ERROR_LOG(G3D, "Something went really wrong, vertex size: %i vs %i", vertexSize, (int)sizeof(SimpleVertex)); } - // TODO: Do something less idiotic to manage this buffer - auto points = new const SimpleVertex *[count_u * count_v]; + SimpleVertex **points = (SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * count_u * count_v); // Make an array of pointers to the control points, to get rid of indices. for (int idx = 0; idx < count_u * count_v; idx++) { @@ -903,9 +927,9 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi patch.patchFacing = patchFacing; if (CanUseHardwareTessellation(prim_type)) { - float *pos = (float*)(decoded + 65536 * 18); // Size 4 float - float *tex = pos + count_u * count_v * 4; // Size 4 float - float *col = tex + count_u * count_v * 4; // Size 4 float + float *pos = (float*)managedBuf.Allocate(sizeof(float) * count_u * count_v * 4); // Size 4 float + float *tex = (float*)managedBuf.Allocate(sizeof(float) * count_u * count_v * 4); // Size 4 float + float *col = (float*)managedBuf.Allocate(sizeof(float) * count_u * count_v * 4); // Size 4 float const bool hasColor = (origVertType & GE_VTYPE_COL_MASK) != 0; const bool hasTexCoords = (origVertType & GE_VTYPE_TC_MASK) != 0; @@ -936,7 +960,6 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi int maxVertexCount = SPLINE_BUFFER_SIZE / vertexSize; TessellateSplinePatch(dest, quadIndices_, count, patch, origVertType, maxVertexCount); } - delete[] points; u32 vertTypeWithIndex16 = (vertType & ~GE_VTYPE_IDX_MASK) | GE_VTYPE_IDX_16BIT; @@ -967,6 +990,8 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi DispatchFlush(); + SimpleBufferManager managedBuf(decoded, DECODED_VERTEX_BUFFER_SIZE); + u16 index_lower_bound = 0; u16 index_upper_bound = count_u * count_v - 1; IndexConverter idxConv(vertType, indices); @@ -984,8 +1009,8 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi // Simplify away bones and morph before proceeding // There are normally not a lot of control points so just splitting decoded should be reasonably safe, although not great. - SimpleVertex *simplified_control_points = (SimpleVertex *)(decoded + 65536 * 12); - u8 *temp_buffer = decoded + 65536 * 18; + SimpleVertex *simplified_control_points = (SimpleVertex *)managedBuf.Allocate(sizeof(SimpleVertex) * index_upper_bound + 1); + u8 *temp_buffer = managedBuf.Allocate(sizeof(SimpleVertex) * count_u * count_v); u32 origVertType = vertType; vertType = NormalizeVertices((u8 *)simplified_control_points, temp_buffer, (u8 *)control_points, index_lower_bound, index_upper_bound, vertType); @@ -997,9 +1022,9 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi ERROR_LOG(G3D, "Something went really wrong, vertex size: %i vs %i", vertexSize, (int)sizeof(SimpleVertex)); } - float *pos = (float*)(decoded + 65536 * 18); // Size 4 float - float *tex = pos + count_u * count_v * 4; // Size 4 float - float *col = tex + count_u * count_v * 4; // Size 4 float + float *pos = (float*)managedBuf.Allocate(sizeof(float) * count_u * count_v * 4); // Size 4 float + float *tex = (float*)managedBuf.Allocate(sizeof(float) * count_u * count_v * 4); // Size 4 float + float *col = (float*)managedBuf.Allocate(sizeof(float) * count_u * count_v * 4); // Size 4 float const bool hasColor = (origVertType & GE_VTYPE_COL_MASK) != 0; const bool hasTexCoords = (origVertType & GE_VTYPE_TC_MASK) != 0; @@ -1031,7 +1056,7 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi memcpy(col, Vec4f::FromRGBA(point->color_32).AsArray(), 4 * sizeof(float)); } } else { - patches = new BezierPatch[num_patches_u * num_patches_v]; + patches = (BezierPatch *)managedBuf.Allocate(sizeof(BezierPatch) * num_patches_u * num_patches_v); for (int patch_u = 0; patch_u < num_patches_u; patch_u++) { for (int patch_v = 0; patch_v < num_patches_v; patch_v++) { BezierPatch& patch = patches[patch_u + patch_v * num_patches_u]; @@ -1079,7 +1104,6 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi const BezierPatch &patch = patches[patch_idx]; TessellateBezierPatch(dest, inds, count, tess_u, tess_v, patch, origVertType); } - delete[] patches; } u32 vertTypeWithIndex16 = (vertType & ~GE_VTYPE_IDX_MASK) | GE_VTYPE_IDX_16BIT; From 28a50053bde368ebf19880dabf845e9e850777bd Mon Sep 17 00:00:00 2001 From: xebra Date: Tue, 30 Jan 2018 11:26:32 +0900 Subject: [PATCH 005/347] [spline/bezier]minor fix --- GPU/Common/SplineCommon.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index b208d8667d..1f003edf58 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -873,6 +873,10 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi PROFILE_THIS_SCOPE("spline"); DispatchFlush(); + // Real hardware seems to draw nothing when given < 4 either U or V. + if (count_u < 4 || count_v < 4) + return; + SimpleBufferManager managedBuf(decoded, DECODED_VERTEX_BUFFER_SIZE); u16 index_lower_bound = 0; @@ -884,11 +888,6 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi VertexDecoder *origVDecoder = GetVertexDecoder((vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24)); *bytesRead = count_u * count_v * origVDecoder->VertexSize(); - // Real hardware seems to draw nothing when given < 4 either U or V. - if (count_u < 4 || count_v < 4) { - return; - } - // Simplify away bones and morph before proceeding SimpleVertex *simplified_control_points = (SimpleVertex *)managedBuf.Allocate(sizeof(SimpleVertex) * index_upper_bound + 1); u8 *temp_buffer = managedBuf.Allocate(sizeof(SimpleVertex) * count_u * count_v); @@ -987,9 +986,13 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indices, int tess_u, int tess_v, int count_u, int count_v, GEPatchPrimType prim_type, bool computeNormals, bool patchFacing, u32 vertType, int *bytesRead) { PROFILE_THIS_SCOPE("bezier"); - DispatchFlush(); + // Real hardware seems to draw nothing when given < 4 either U or V. + // This would result in num_patches_u / num_patches_v being 0. + if (count_u < 4 || count_v < 4) + return; + SimpleBufferManager managedBuf(decoded, DECODED_VERTEX_BUFFER_SIZE); u16 index_lower_bound = 0; @@ -1001,12 +1004,6 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi VertexDecoder *origVDecoder = GetVertexDecoder((vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24)); *bytesRead = count_u * count_v * origVDecoder->VertexSize(); - // Real hardware seems to draw nothing when given < 4 either U or V. - // This would result in num_patches_u / num_patches_v being 0. - if (count_u < 4 || count_v < 4) { - return; - } - // Simplify away bones and morph before proceeding // There are normally not a lot of control points so just splitting decoded should be reasonably safe, although not great. SimpleVertex *simplified_control_points = (SimpleVertex *)managedBuf.Allocate(sizeof(SimpleVertex) * index_upper_bound + 1); From 1d4e8ccd25e03c2d9ae7c8fed918aaa4068ede67 Mon Sep 17 00:00:00 2001 From: xebra Date: Tue, 30 Jan 2018 14:41:39 +0900 Subject: [PATCH 006/347] [spline/bezier]minor fix --- GPU/Common/SplineCommon.cpp | 49 ++++++++++++++----------------------- 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 1f003edf58..91db3deeb4 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -910,7 +910,6 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi } int count = 0; - u8 *dest = splineBuffer; SplinePatchLocal patch; @@ -1019,17 +1018,24 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi ERROR_LOG(G3D, "Something went really wrong, vertex size: %i vs %i", vertexSize, (int)sizeof(SimpleVertex)); } - float *pos = (float*)managedBuf.Allocate(sizeof(float) * count_u * count_v * 4); // Size 4 float - float *tex = (float*)managedBuf.Allocate(sizeof(float) * count_u * count_v * 4); // Size 4 float - float *col = (float*)managedBuf.Allocate(sizeof(float) * count_u * count_v * 4); // Size 4 float - const bool hasColor = (origVertType & GE_VTYPE_COL_MASK) != 0; - const bool hasTexCoords = (origVertType & GE_VTYPE_TC_MASK) != 0; + // If specified as 0, uses 1. + if (tess_u < 1) tess_u = 1; + if (tess_v < 1) tess_v = 1; + + int count = 0; + u8 *dest = splineBuffer; + u16 *inds = quadIndices_; // Bezier patches share less control points than spline patches. Otherwise they are pretty much the same (except bezier don't support the open/close thing) int num_patches_u = (count_u - 1) / 3; int num_patches_v = (count_v - 1) / 3; - BezierPatch *patches = nullptr; if (CanUseHardwareTessellation(prim_type)) { + float *pos = (float*)managedBuf.Allocate(sizeof(float) * count_u * count_v * 4); // Size 4 float + float *tex = (float*)managedBuf.Allocate(sizeof(float) * count_u * count_v * 4); // Size 4 float + float *col = (float*)managedBuf.Allocate(sizeof(float) * count_u * count_v * 4); // Size 4 float + const bool hasColor = (origVertType & GE_VTYPE_COL_MASK) != 0; + const bool hasTexCoords = (origVertType & GE_VTYPE_TC_MASK) != 0; + int posStride, texStride, colStride; tessDataTransfer->PrepareBuffers(pos, tex, col, posStride, texStride, colStride, count_u * count_v, hasColor, hasTexCoords); float *p = pos; @@ -1052,8 +1058,11 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi const SimpleVertex *point = simplified_control_points + (indices ? idxConv.convert(0) : 0); memcpy(col, Vec4f::FromRGBA(point->color_32).AsArray(), 4 * sizeof(float)); } + tessDataTransfer->SendDataToShader(pos, tex, col, count_u * count_v, hasColor, hasTexCoords); + TessellateBezierPatchHardware(dest, inds, count, tess_u, tess_v, prim_type); + numPatches = num_patches_u * num_patches_v; } else { - patches = (BezierPatch *)managedBuf.Allocate(sizeof(BezierPatch) * num_patches_u * num_patches_v); + BezierPatch *patches = (BezierPatch *)managedBuf.Allocate(sizeof(BezierPatch) * num_patches_u * num_patches_v); for (int patch_u = 0; patch_u < num_patches_u; patch_u++) { for (int patch_v = 0; patch_v < num_patches_v; patch_v++) { BezierPatch& patch = patches[patch_u + patch_v * num_patches_u]; @@ -1069,34 +1078,14 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi patch.patchFacing = patchFacing; } } - } - - int count = 0; - u8 *dest = splineBuffer; - - // We shouldn't really split up into separate 4x4 patches, instead we should do something that works - // like the splines, so we subdivide across the whole "mega-patch". - - // If specified as 0, uses 1. - if (tess_u < 1) { - tess_u = 1; - } - if (tess_v < 1) { - tess_v = 1; - } - - u16 *inds = quadIndices_; - if (CanUseHardwareTessellation(prim_type)) { - tessDataTransfer->SendDataToShader(pos, tex, col, count_u * count_v, hasColor, hasTexCoords); - TessellateBezierPatchHardware(dest, inds, count, tess_u, tess_v, prim_type); - numPatches = num_patches_u * num_patches_v; - } else { int maxVertices = SPLINE_BUFFER_SIZE / vertexSize; // Downsample until it fits, in case crazy tessellation factors are sent. while ((tess_u + 1) * (tess_v + 1) * num_patches_u * num_patches_v > maxVertices) { tess_u /= 2; tess_v /= 2; } + // We shouldn't really split up into separate 4x4 patches, instead we should do something that works + // like the splines, so we subdivide across the whole "mega-patch". for (int patch_idx = 0; patch_idx < num_patches_u*num_patches_v; ++patch_idx) { const BezierPatch &patch = patches[patch_idx]; TessellateBezierPatch(dest, inds, count, tess_u, tess_v, patch, origVertType); From a7754c4b9c56091b0a335cb964ac422499a58c51 Mon Sep 17 00:00:00 2001 From: xebra Date: Tue, 30 Jan 2018 14:53:03 +0900 Subject: [PATCH 007/347] [spline/bezier]minor fix # Conflicts: # GPU/Common/SplineCommon.cpp --- GPU/Common/SplineCommon.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 91db3deeb4..2977f7b44b 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -902,12 +902,10 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi ERROR_LOG(G3D, "Something went really wrong, vertex size: %i vs %i", vertexSize, (int)sizeof(SimpleVertex)); } - SimpleVertex **points = (SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * count_u * count_v); - // Make an array of pointers to the control points, to get rid of indices. - for (int idx = 0; idx < count_u * count_v; idx++) { + SimpleVertex **points = (SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * count_u * count_v); + for (int idx = 0; idx < count_u * count_v; idx++) points[idx] = simplified_control_points + (indices ? idxConv.convert(idx) : idx); - } int count = 0; u8 *dest = splineBuffer; @@ -1022,6 +1020,11 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi if (tess_u < 1) tess_u = 1; if (tess_v < 1) tess_v = 1; + // Make an array of pointers to the control points, to get rid of indices. + SimpleVertex **points = (SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * count_u * count_v); + for (int idx = 0; idx < count_u * count_v; idx++) + points[idx] = simplified_control_points + (indices ? idxConv.convert(idx) : idx); + int count = 0; u8 *dest = splineBuffer; u16 *inds = quadIndices_; @@ -1042,22 +1045,20 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi float *t = tex; float *c = col; for (int idx = 0; idx < count_u * count_v; idx++) { - const SimpleVertex *point = simplified_control_points + (indices ? idxConv.convert(idx) : idx); - memcpy(p, point->pos.AsArray(), 3 * sizeof(float)); + memcpy(p, points[idx]->pos.AsArray(), 3 * sizeof(float)); p += posStride; if (hasTexCoords) { - memcpy(t, point->uv, 2 * sizeof(float)); + memcpy(t, points[idx]->uv, 2 * sizeof(float)); t += texStride; } if (hasColor) { - memcpy(c, Vec4f::FromRGBA(point->color_32).AsArray(), 4 * sizeof(float)); + memcpy(c, Vec4f::FromRGBA(points[idx]->color_32).AsArray(), 4 * sizeof(float)); c += colStride; } } - if (!hasColor) { - const SimpleVertex *point = simplified_control_points + (indices ? idxConv.convert(0) : 0); - memcpy(col, Vec4f::FromRGBA(point->color_32).AsArray(), 4 * sizeof(float)); - } + if (!hasColor) + memcpy(col, Vec4f::FromRGBA(points[0]->color_32).AsArray(), 4 * sizeof(float)); + tessDataTransfer->SendDataToShader(pos, tex, col, count_u * count_v, hasColor, hasTexCoords); TessellateBezierPatchHardware(dest, inds, count, tess_u, tess_v, prim_type); numPatches = num_patches_u * num_patches_v; From 3c2837bee7ff2bedf7535928d9a021c0f5d5b603 Mon Sep 17 00:00:00 2001 From: xebra Date: Tue, 30 Jan 2018 14:56:21 +0900 Subject: [PATCH 008/347] [spline/bezier]minor fix --- GPU/Common/SplineCommon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 2977f7b44b..69e579bca7 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -1069,7 +1069,7 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi BezierPatch& patch = patches[patch_u + patch_v * num_patches_u]; for (int point = 0; point < 16; ++point) { int idx = (patch_u * 3 + point % 4) + (patch_v * 3 + point / 4) * count_u; - patch.points[point] = simplified_control_points + (indices ? idxConv.convert(idx) : idx); + patch.points[point] = points[idx]; } patch.u_index = patch_u * 3; patch.v_index = patch_v * 3; From b1289cddce6b9365f51d1c4a34514356e407e12f Mon Sep 17 00:00:00 2001 From: xebra Date: Wed, 27 Jun 2018 23:37:21 +0900 Subject: [PATCH 009/347] [spline/bezier]minor fix --- 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 69e579bca7..fe105e63bd 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -903,7 +903,7 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi } // Make an array of pointers to the control points, to get rid of indices. - SimpleVertex **points = (SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * count_u * count_v); + const SimpleVertex **points = (const SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * count_u * count_v); for (int idx = 0; idx < count_u * count_v; idx++) points[idx] = simplified_control_points + (indices ? idxConv.convert(idx) : idx); @@ -1021,7 +1021,7 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi if (tess_v < 1) tess_v = 1; // Make an array of pointers to the control points, to get rid of indices. - SimpleVertex **points = (SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * count_u * count_v); + const SimpleVertex **points = (const SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * count_u * count_v); for (int idx = 0; idx < count_u * count_v; idx++) points[idx] = simplified_control_points + (indices ? idxConv.convert(idx) : idx); From 485260c937c166f818c53959e9111a4d8f729e0d Mon Sep 17 00:00:00 2001 From: xebra Date: Tue, 30 Jan 2018 16:16:25 +0900 Subject: [PATCH 010/347] [spline/bezier]Make a function to copy control points. --- GPU/Common/SplineCommon.cpp | 55 +++++++++++++------------------------ 1 file changed, 19 insertions(+), 36 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index fe105e63bd..d1afe1585e 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -846,6 +846,23 @@ void TessellateBezierPatch(u8 *&dest, u16 *&indices, int &count, int tess_u, int } } +static void CopyControlPoints(const SimpleVertex *const *points, float *pos, float *tex, float *col, int posStride, int texStride, int colStride, int size, bool hasColor, bool hasTexCoords) { + for (int idx = 0; idx < size; idx++) { + memcpy(pos, points[idx]->pos.AsArray(), 3 * sizeof(float)); + pos += posStride; + if (hasTexCoords) { + memcpy(tex, points[idx]->uv, 2 * sizeof(float)); + tex += texStride; + } + if (hasColor) { + memcpy(col, Vec4f::FromRGBA(points[idx]->color_32).AsArray(), 4 * sizeof(float)); + col += colStride; + } + } + if (!hasColor) + memcpy(col, Vec4f::FromRGBA(points[0]->color_32).AsArray(), 4 * sizeof(float)); +} + class SimpleBufferManager { private: u8 *buf_; @@ -931,24 +948,7 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi int posStride, texStride, colStride; tessDataTransfer->PrepareBuffers(pos, tex, col, posStride, texStride, colStride, count_u * count_v, hasColor, hasTexCoords); - float *p = pos; - float *t = tex; - float *c = col; - for (int idx = 0; idx < count_u * count_v; idx++) { - memcpy(p, points[idx]->pos.AsArray(), 3 * sizeof(float)); - p += posStride; - if (hasTexCoords) { - memcpy(t, points[idx]->uv, 2 * sizeof(float)); - t += texStride; - } - if (hasColor) { - memcpy(c, Vec4f::FromRGBA(points[idx]->color_32).AsArray(), 4 * sizeof(float)); - c += colStride; - } - } - if (!hasColor) - memcpy(col, Vec4f::FromRGBA(points[0]->color_32).AsArray(), 4 * sizeof(float)); - + CopyControlPoints(points, pos, tex, col, posStride, texStride, colStride, count_u * count_v, hasColor, hasTexCoords); tessDataTransfer->SendDataToShader(pos, tex, col, count_u * count_v, hasColor, hasTexCoords); TessellateSplinePatchHardware(dest, quadIndices_, count, patch); numPatches = (count_u - 3) * (count_v - 3); @@ -1041,24 +1041,7 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi int posStride, texStride, colStride; tessDataTransfer->PrepareBuffers(pos, tex, col, posStride, texStride, colStride, count_u * count_v, hasColor, hasTexCoords); - float *p = pos; - float *t = tex; - float *c = col; - for (int idx = 0; idx < count_u * count_v; idx++) { - memcpy(p, points[idx]->pos.AsArray(), 3 * sizeof(float)); - p += posStride; - if (hasTexCoords) { - memcpy(t, points[idx]->uv, 2 * sizeof(float)); - t += texStride; - } - if (hasColor) { - memcpy(c, Vec4f::FromRGBA(points[idx]->color_32).AsArray(), 4 * sizeof(float)); - c += colStride; - } - } - if (!hasColor) - memcpy(col, Vec4f::FromRGBA(points[0]->color_32).AsArray(), 4 * sizeof(float)); - + CopyControlPoints(points, pos, tex, col, posStride, texStride, colStride, count_u * count_v, hasColor, hasTexCoords); tessDataTransfer->SendDataToShader(pos, tex, col, count_u * count_v, hasColor, hasTexCoords); TessellateBezierPatchHardware(dest, inds, count, tess_u, tess_v, prim_type); numPatches = num_patches_u * num_patches_v; From 966ff32ee75c9376ee9248302a88c61063534c30 Mon Sep 17 00:00:00 2001 From: xebra Date: Thu, 28 Jun 2018 01:41:16 +0900 Subject: [PATCH 011/347] [spline/bezier]Improve the logic of copying control-points. --- GPU/Common/DrawEngineCommon.cpp | 24 +++++++++++++++++++++ GPU/Common/DrawEngineCommon.h | 10 ++++----- GPU/Common/SplineCommon.cpp | 22 ++----------------- GPU/D3D11/DrawEngineD3D11.cpp | 18 ++++++++-------- GPU/D3D11/DrawEngineD3D11.h | 3 +-- GPU/Directx9/DrawEngineDX9.cpp | 3 +-- GPU/Directx9/DrawEngineDX9.h | 2 +- GPU/GLES/DrawEngineGLES.cpp | 38 ++++++++++++++++++++------------- GPU/GLES/DrawEngineGLES.h | 4 ++-- GPU/Vulkan/DrawEngineVulkan.cpp | 18 ++++++---------- GPU/Vulkan/DrawEngineVulkan.h | 3 +-- 11 files changed, 74 insertions(+), 71 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 95d6d5ad2e..966aedd6e1 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -739,3 +739,27 @@ void DrawEngineCommon::SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, } } } + +void DrawEngineCommon::TessellationDataTransfer::CopyControlPoints(float *pos, float *tex, float *col, int posStride, int texStride, int colStride, const SimpleVertex *const *points, int size, u32 vertType) { + bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0; + bool hasTexCoord = (vertType & GE_VTYPE_TC_MASK) != 0; + + for (int i = 0; i < size; ++i) { + memcpy(pos, points[i]->pos.AsArray(), 3 * sizeof(float)); + pos += posStride; + } + if (hasTexCoord) { + for (int i = 0; i < size; ++i) { + memcpy(tex, points[i]->uv, 2 * sizeof(float)); + tex += texStride; + } + } + if (hasColor) { + for (int i = 0; i < size; ++i) { + memcpy(col, Vec4f::FromRGBA(points[i]->color_32).AsArray(), 4 * sizeof(float)); + col += colStride; + } + } else { + memcpy(col, Vec4f::FromRGBA(points[0]->color_32).AsArray(), 4 * sizeof(float)); + } +} diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 03e9e50cf3..aa5531d011 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -50,6 +50,8 @@ inline uint32_t GetVertTypeID(uint32_t vertType, int uvGenMode) { return (vertType & 0xFFFFFF) | (uvGenMode << 24); } +struct SimpleVertex; + class DrawEngineCommon { public: DrawEngineCommon(); @@ -177,13 +179,9 @@ protected: int prevSizeCol; public: virtual ~TessellationDataTransfer() {} + void CopyControlPoints(float *pos, float *tex, float *col, int posStride, int texStride, int colStride, const SimpleVertex *const *points, int size, u32 vertType); // Send spline/bezier's control points to vertex shader through floating point texture. - virtual void PrepareBuffers(float *&pos, float *&tex, float *&col, int &posStride, int &texStride, int &colStride, int size, bool hasColor, bool hasTexCoords) { - posStride = 4; - texStride = 4; - colStride = 4; - } - virtual void SendDataToShader(const float *pos, const float *tex, const float *col, int size, bool hasColor, bool hasTexCoords) = 0; + virtual void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType) = 0; virtual void EndFrame() {} }; TessellationDataTransfer *tessDataTransfer; diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index d1afe1585e..12db1e322e 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -940,16 +940,7 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi patch.patchFacing = patchFacing; if (CanUseHardwareTessellation(prim_type)) { - float *pos = (float*)managedBuf.Allocate(sizeof(float) * count_u * count_v * 4); // Size 4 float - float *tex = (float*)managedBuf.Allocate(sizeof(float) * count_u * count_v * 4); // Size 4 float - float *col = (float*)managedBuf.Allocate(sizeof(float) * count_u * count_v * 4); // Size 4 float - const bool hasColor = (origVertType & GE_VTYPE_COL_MASK) != 0; - const bool hasTexCoords = (origVertType & GE_VTYPE_TC_MASK) != 0; - - int posStride, texStride, colStride; - tessDataTransfer->PrepareBuffers(pos, tex, col, posStride, texStride, colStride, count_u * count_v, hasColor, hasTexCoords); - CopyControlPoints(points, pos, tex, col, posStride, texStride, colStride, count_u * count_v, hasColor, hasTexCoords); - tessDataTransfer->SendDataToShader(pos, tex, col, count_u * count_v, hasColor, hasTexCoords); + tessDataTransfer->SendDataToShader(points, count_u * count_v, origVertType); TessellateSplinePatchHardware(dest, quadIndices_, count, patch); numPatches = (count_u - 3) * (count_v - 3); } else { @@ -1033,16 +1024,7 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi int num_patches_u = (count_u - 1) / 3; int num_patches_v = (count_v - 1) / 3; if (CanUseHardwareTessellation(prim_type)) { - float *pos = (float*)managedBuf.Allocate(sizeof(float) * count_u * count_v * 4); // Size 4 float - float *tex = (float*)managedBuf.Allocate(sizeof(float) * count_u * count_v * 4); // Size 4 float - float *col = (float*)managedBuf.Allocate(sizeof(float) * count_u * count_v * 4); // Size 4 float - const bool hasColor = (origVertType & GE_VTYPE_COL_MASK) != 0; - const bool hasTexCoords = (origVertType & GE_VTYPE_TC_MASK) != 0; - - int posStride, texStride, colStride; - tessDataTransfer->PrepareBuffers(pos, tex, col, posStride, texStride, colStride, count_u * count_v, hasColor, hasTexCoords); - CopyControlPoints(points, pos, tex, col, posStride, texStride, colStride, count_u * count_v, hasColor, hasTexCoords); - tessDataTransfer->SendDataToShader(pos, tex, col, count_u * count_v, hasColor, hasTexCoords); + tessDataTransfer->SendDataToShader(points, count_u * count_v, origVertType); TessellateBezierPatchHardware(dest, inds, count, tess_u, tess_v, prim_type); numPatches = num_patches_u * num_patches_v; } else { diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index eac5cf078f..63b753d1ea 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -692,7 +692,7 @@ rotateVBO: GPUDebug::NotifyDraw(); } -void DrawEngineD3D11::TessellationDataTransferD3D11::PrepareBuffers(float *&pos, float *&tex, float *&col, int &posStride, int &texStride, int &colStride, int size, bool hasColor, bool hasTexCoords) { +void DrawEngineD3D11::TessellationDataTransferD3D11::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType) { struct TessData { float pos[3]; float pad1; float uv[2]; float pad2[2]; @@ -716,14 +716,14 @@ void DrawEngineD3D11::TessellationDataTransferD3D11::PrepareBuffers(float *&pos, context_->Map(buf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); uint8_t *data = (uint8_t *)map.pData; - pos = (float *)(data); - tex = (float *)(data + offsetof(TessData, uv)); - col = (float *)(data + offsetof(TessData, color)); - posStride = sizeof(TessData) / sizeof(float); - colStride = hasColor ? (sizeof(TessData) / sizeof(float)) : 0; - texStride = sizeof(TessData) / sizeof(float); -} + float *pos = (float *)(data); + float *tex = (float *)(data + offsetof(TessData, uv)); + float *col = (float *)(data + offsetof(TessData, color)); + int stride = sizeof(TessData) / sizeof(float); + bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0; + bool hasTexCoord = (vertType & GE_VTYPE_TC_MASK) != 0; + + CopyControlPoints(pos, tex, col, stride, stride, stride, points, size, vertType); -void DrawEngineD3D11::TessellationDataTransferD3D11::SendDataToShader(const float * pos, const float * tex, const float * col, int size, bool hasColor, bool hasTexCoords) { context_->Unmap(buf, 0); } diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h index 8b797a3d2d..e64296dba1 100644 --- a/GPU/D3D11/DrawEngineD3D11.h +++ b/GPU/D3D11/DrawEngineD3D11.h @@ -221,7 +221,6 @@ private: } } - void PrepareBuffers(float *&pos, float *&tex, float *&col, int &posStride, int &texStride, int &colStride, int size, bool hasColor, bool hasTexCoords) override; - void SendDataToShader(const float *pos, const float *tex, const float *col, int size, bool hasColor, bool hasTexCoords) override; + void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType) override; }; }; diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index e4f24703ee..f3f373f314 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -624,8 +624,7 @@ rotateVBO: GPUDebug::NotifyDraw(); } -void DrawEngineDX9::TessellationDataTransferDX9::SendDataToShader(const float * pos, const float * tex, const float * col, int size, bool hasColor, bool hasTexCoords) -{ +void DrawEngineDX9::TessellationDataTransferDX9::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType) { } } // namespace diff --git a/GPU/Directx9/DrawEngineDX9.h b/GPU/Directx9/DrawEngineDX9.h index ef015b02b5..1c7c082e7d 100644 --- a/GPU/Directx9/DrawEngineDX9.h +++ b/GPU/Directx9/DrawEngineDX9.h @@ -166,7 +166,7 @@ private: } ~TessellationDataTransferDX9() { } - void SendDataToShader(const float *pos, const float *tex, const float *col, int size, bool hasColor, bool hasTexCoords) override; + void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType) override; }; }; diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index a8857b17bc..ed0ff62d74 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -655,37 +655,45 @@ bool DrawEngineGLES::IsCodePtrVertexDecoder(const u8 *ptr) const { return decJitCache_->IsInSpace(ptr); } -void DrawEngineGLES::TessellationDataTransferGLES::SendDataToShader(const float *pos, const float *tex, const float *col, int size, bool hasColor, bool hasTexCoords) { +void DrawEngineGLES::TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType) { + bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0; + bool hasTexCoord = (vertType & GE_VTYPE_TC_MASK) != 0; + int sizeColor = hasColor ? size : 1; + + float *pos = new float[size * 4]; + float *tex = nullptr; + if (hasTexCoord) + tex = new float[size * 4]; + float *col = new float[sizeColor * 4]; + int stride = 4; + + CopyControlPoints(pos, tex, col, stride, stride, stride, points, size, vertType); + // Removed the 1D texture support, it's unlikely to be relevant for performance. + + // Position if (data_tex[0]) renderManager_->DeleteTexture(data_tex[0]); - uint8_t *pos_data = new uint8_t[size * sizeof(float) * 4]; - memcpy(pos_data, pos, size * sizeof(float) * 4); data_tex[0] = renderManager_->CreateTexture(GL_TEXTURE_2D); - renderManager_->TextureImage(data_tex[0], 0, size, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT, pos_data, GLRAllocType::NEW, false); + renderManager_->TextureImage(data_tex[0], 0, size, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT, (u8 *)pos, GLRAllocType::NEW, false); renderManager_->FinalizeTexture(data_tex[0], 0, false); renderManager_->BindTexture(TEX_SLOT_SPLINE_POS, data_tex[0]); - // Texcoords - if (hasTexCoords) { + // Texcoord + if (hasTexCoord) { if (data_tex[1]) renderManager_->DeleteTexture(data_tex[1]); - uint8_t *tex_data = new uint8_t[size * sizeof(float) * 4]; - memcpy(tex_data, tex, size * sizeof(float) * 4); data_tex[1] = renderManager_->CreateTexture(GL_TEXTURE_2D); - renderManager_->TextureImage(data_tex[1], 0, size, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT, tex_data, GLRAllocType::NEW, false); + renderManager_->TextureImage(data_tex[1], 0, size, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT, (u8 *)tex, GLRAllocType::NEW, false); renderManager_->FinalizeTexture(data_tex[1], 0, false); - renderManager_->BindTexture(TEX_SLOT_SPLINE_NRM, data_tex[1]); + renderManager_->BindTexture(TEX_SLOT_SPLINE_TEX, data_tex[1]); } + // Color if (data_tex[2]) renderManager_->DeleteTexture(data_tex[2]); data_tex[2] = renderManager_->CreateTexture(GL_TEXTURE_2D); - int sizeColor = hasColor ? size : 1; - uint8_t *col_data = new uint8_t[sizeColor * sizeof(float) * 4]; - memcpy(col_data, col, sizeColor * sizeof(float) * 4); - - renderManager_->TextureImage(data_tex[2], 0, sizeColor, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT, col_data, GLRAllocType::NEW, false); + renderManager_->TextureImage(data_tex[2], 0, sizeColor, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT, (u8 *)col, GLRAllocType::NEW, false); renderManager_->FinalizeTexture(data_tex[2], 0, false); renderManager_->BindTexture(TEX_SLOT_SPLINE_COL, data_tex[2]); } diff --git a/GPU/GLES/DrawEngineGLES.h b/GPU/GLES/DrawEngineGLES.h index 2901a1c384..a0646c9ab6 100644 --- a/GPU/GLES/DrawEngineGLES.h +++ b/GPU/GLES/DrawEngineGLES.h @@ -47,7 +47,7 @@ enum { TEX_SLOT_ALPHATEST = 2, TEX_SLOT_CLUT = 3, TEX_SLOT_SPLINE_POS = 4, - TEX_SLOT_SPLINE_NRM = 5, + TEX_SLOT_SPLINE_TEX = 5, TEX_SLOT_SPLINE_COL = 6, }; @@ -218,7 +218,7 @@ private: ~TessellationDataTransferGLES() { EndFrame(); } - void SendDataToShader(const float *pos, const float *tex, const float *col, int size, bool hasColor, bool hasTexCoords) override; + void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType) override; void EndFrame() override; // Queues textures for deletion. }; }; diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 16f0c495fb..e100513f2b 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -1001,9 +1001,7 @@ DrawEngineVulkan::TessellationDataTransferVulkan::TessellationDataTransferVulkan DrawEngineVulkan::TessellationDataTransferVulkan::~TessellationDataTransferVulkan() { } -void DrawEngineVulkan::TessellationDataTransferVulkan::PrepareBuffers(float *&pos, float *&tex, float *&col, int &posStride, int &texStride, int &colStride, int size, bool hasColor, bool hasTexCoords) { - colStride = 4; - +void DrawEngineVulkan::TessellationDataTransferVulkan::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType) { // SSBOs that are not simply float1 or float2 need to be padded up to a float4 size. vec3 members // also need to be 16-byte aligned, hence the padding. struct TessData { @@ -1016,14 +1014,10 @@ void DrawEngineVulkan::TessellationDataTransferVulkan::PrepareBuffers(float *&po uint8_t *data = (uint8_t *)push_->PushAligned(size * sizeof(TessData), &offset_, &buf_, ssboAlignment); range_ = size * sizeof(TessData); - pos = (float *)(data); - tex = (float *)(data + offsetof(TessData, uv)); - col = (float *)(data + offsetof(TessData, color)); - posStride = sizeof(TessData) / sizeof(float); - colStride = hasColor ? (sizeof(TessData) / sizeof(float)) : 0; - texStride = sizeof(TessData) / sizeof(float); -} + float *pos = (float *)(data); + float *tex = (float *)(data + offsetof(TessData, uv)); + float *col = (float *)(data + offsetof(TessData, color)); + int stride = sizeof(TessData) / sizeof(float); -void DrawEngineVulkan::TessellationDataTransferVulkan::SendDataToShader(const float *pos, const float *tex, const float *col, int size, bool hasColor, bool hasTexCoords) { - // Nothing to do here! The caller will write directly to the pushbuffer through the pointers it got through PrepareBuffers. + CopyControlPoints(pos, tex, col, stride, stride, stride, points, size, vertType); } diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index 494a4ccd4b..a9837f44a3 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -284,8 +284,7 @@ private: ~TessellationDataTransferVulkan(); void SetPushBuffer(VulkanPushBuffer *push) { push_ = push; } - void SendDataToShader(const float *pos, const float *tex, const float *col, int size, bool hasColor, bool hasTexCoords) override; - void PrepareBuffers(float *&pos, float *&tex, float *&col, int &posStride, int &texStride, int &colStride, int size, bool hasColor, bool hasTexCoords) override; + void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType) override; void GetBufferAndOffset(VkBuffer *buf, VkDeviceSize *offset, VkDeviceSize *range) { *buf = buf_; From 7cbc97f19eba233007a3b6fde1943a506088992b Mon Sep 17 00:00:00 2001 From: xebra Date: Tue, 30 Jan 2018 16:24:42 +0900 Subject: [PATCH 012/347] [spline/bezier]minor cleanup --- GPU/Common/SplineCommon.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 12db1e322e..40640f4369 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -111,7 +111,6 @@ static void CopyQuadIndex(u16 *&indices, GEPatchPrimType type, const int idx0, c } } -#undef b2 // Bernstein basis functions inline float bern0(float x) { return (1 - x) * (1 - x) * (1 - x); } From 30c3c87da813d294c014493fc37c5339b202529a Mon Sep 17 00:00:00 2001 From: xebra Date: Tue, 30 Jan 2018 17:42:41 +0900 Subject: [PATCH 013/347] [spline/bezier]Make a function to build indices. --- GPU/Common/SplineCommon.cpp | 54 +++++++++++-------------------------- 1 file changed, 15 insertions(+), 39 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 40640f4369..a82176dc17 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -100,8 +100,7 @@ static void CopyQuadIndex(u16 *&indices, GEPatchPrimType type, const int idx0, c *(indices++) = idx3; *(indices++) = idx1; *(indices++) = idx2; - } - else { + } else { *(indices++) = idx0; *(indices++) = idx2; *(indices++) = idx1; @@ -111,6 +110,17 @@ static void CopyQuadIndex(u16 *&indices, GEPatchPrimType type, const int idx0, c } } +static void BuildIndex(u16 *indices, int &count, int num_u, int num_v, GEPatchPrimType prim_type, int total = 0) { + for (int v = 0; v < num_v; ++v) { + for (int u = 0; u < num_u; ++u) { + int idx0 = v * (num_u + 1) + u + total; // Top left + int idx2 = (v + 1) * (num_u + 1) + u + total; // Bottom left + + CopyQuadIndex(indices, prim_type, idx0, idx0 + 1, idx2, idx2 + 1); + count += 6; + } + } +} // Bernstein basis functions inline float bern0(float x) { return (1 - x) * (1 - x) * (1 - x); } @@ -283,18 +293,7 @@ static void TessellateSplinePatchHardware(u8 *&dest, u16 *indices, int &count, c } } - // Combine the vertices into triangles. - for (int tile_v = 0; tile_v < spatch.tess_v; ++tile_v) { - for (int tile_u = 0; tile_u < spatch.tess_u; ++tile_u) { - int idx0 = tile_v * (spatch.tess_u + 1) + tile_u; - int idx1 = tile_v * (spatch.tess_u + 1) + tile_u + 1; - int idx2 = (tile_v + 1) * (spatch.tess_u + 1) + tile_u; - int idx3 = (tile_v + 1) * (spatch.tess_u + 1) + tile_u + 1; - - CopyQuadIndex(indices, spatch.primType, idx0, idx1, idx2, idx3); - count += 6; - } - } + BuildIndex(indices, count, spatch.tess_u, spatch.tess_v, spatch.primType); } static void _SplinePatchLowQuality(u8 *&dest, u16 *indices, int &count, const SplinePatchLocal &spatch, u32 origVertType) { @@ -546,19 +545,7 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp delete[] divs_u; delete[] divs_v; - GEPatchPrimType prim_type = spatch.primType; - // Tessellate. - for (int tile_v = 0; tile_v < patch_div_t; ++tile_v) { - for (int tile_u = 0; tile_u < patch_div_s; ++tile_u) { - int idx0 = tile_v * (patch_div_s + 1) + tile_u; - int idx1 = tile_v * (patch_div_s + 1) + tile_u + 1; - int idx2 = (tile_v + 1) * (patch_div_s + 1) + tile_u; - int idx3 = (tile_v + 1) * (patch_div_s + 1) + tile_u + 1; - - CopyQuadIndex(indices, prim_type, idx0, idx1, idx2, idx3); - count += 6; - } - } + BuildIndex(indices, count, patch_div_s, patch_div_t, spatch.primType); } template @@ -817,18 +804,7 @@ static void TessellateBezierPatchHardware(u8 *&dest, u16 *indices, int &count, i } } - // Combine the vertices into triangles. - for (int tile_v = 0; tile_v < tess_v; ++tile_v) { - for (int tile_u = 0; tile_u < tess_u; ++tile_u) { - int idx0 = tile_v * (tess_u + 1) + tile_u; - int idx1 = tile_v * (tess_u + 1) + tile_u + 1; - int idx2 = (tile_v + 1) * (tess_u + 1) + tile_u; - int idx3 = (tile_v + 1) * (tess_u + 1) + tile_u + 1; - - CopyQuadIndex(indices, primType, idx0, idx1, idx2, idx3); - count += 6; - } - } + BuildIndex(indices, count, tess_u, tess_v, primType); } void TessellateBezierPatch(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType) { From d8ccc1c2b558a81afb7b7a8c06593d93c2d4b9a5 Mon Sep 17 00:00:00 2001 From: xebra Date: Tue, 30 Jan 2018 18:10:11 +0900 Subject: [PATCH 014/347] [spline/bezier]minor fix --- 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 a82176dc17..232b834746 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -881,7 +881,7 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi *bytesRead = count_u * count_v * origVDecoder->VertexSize(); // Simplify away bones and morph before proceeding - SimpleVertex *simplified_control_points = (SimpleVertex *)managedBuf.Allocate(sizeof(SimpleVertex) * index_upper_bound + 1); + SimpleVertex *simplified_control_points = (SimpleVertex *)managedBuf.Allocate(sizeof(SimpleVertex) * (index_upper_bound + 1)); u8 *temp_buffer = managedBuf.Allocate(sizeof(SimpleVertex) * count_u * count_v); u32 origVertType = vertType; @@ -969,7 +969,7 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi // Simplify away bones and morph before proceeding // There are normally not a lot of control points so just splitting decoded should be reasonably safe, although not great. - SimpleVertex *simplified_control_points = (SimpleVertex *)managedBuf.Allocate(sizeof(SimpleVertex) * index_upper_bound + 1); + SimpleVertex *simplified_control_points = (SimpleVertex *)managedBuf.Allocate(sizeof(SimpleVertex) * (index_upper_bound + 1)); u8 *temp_buffer = managedBuf.Allocate(sizeof(SimpleVertex) * count_u * count_v); u32 origVertType = vertType; From 15a11d58c99384a836d9ca9d377e774e44447c4f Mon Sep 17 00:00:00 2001 From: xebra Date: Tue, 30 Jan 2018 18:17:54 +0900 Subject: [PATCH 015/347] Modify IndexConverter class to functor. --- GPU/Common/SplineCommon.cpp | 8 ++++---- GPU/Common/VertexDecoderCommon.h | 2 +- GPU/Software/TransformUnit.cpp | 12 ++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 232b834746..1bd537da18 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -873,7 +873,7 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi u16 index_lower_bound = 0; u16 index_upper_bound = count_u * count_v - 1; - IndexConverter idxConv(vertType, indices); + IndexConverter ConvertIndex(vertType, indices); if (indices) GetIndexBounds(indices, count_u * count_v, vertType, &index_lower_bound, &index_upper_bound); @@ -897,7 +897,7 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi // Make an array of pointers to the control points, to get rid of indices. const SimpleVertex **points = (const SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * count_u * count_v); for (int idx = 0; idx < count_u * count_v; idx++) - points[idx] = simplified_control_points + (indices ? idxConv.convert(idx) : idx); + points[idx] = simplified_control_points + (indices ? ConvertIndex(idx) : idx); int count = 0; u8 *dest = splineBuffer; @@ -960,7 +960,7 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi u16 index_lower_bound = 0; u16 index_upper_bound = count_u * count_v - 1; - IndexConverter idxConv(vertType, indices); + IndexConverter ConvertIndex(vertType, indices); if (indices) GetIndexBounds(indices, count_u*count_v, vertType, &index_lower_bound, &index_upper_bound); @@ -989,7 +989,7 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi // Make an array of pointers to the control points, to get rid of indices. const SimpleVertex **points = (const SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * count_u * count_v); for (int idx = 0; idx < count_u * count_v; idx++) - points[idx] = simplified_control_points + (indices ? idxConv.convert(idx) : idx); + points[idx] = simplified_control_points + (indices ? ConvertIndex(idx) : idx); int count = 0; u8 *dest = splineBuffer; diff --git a/GPU/Common/VertexDecoderCommon.h b/GPU/Common/VertexDecoderCommon.h index 97ea633c1e..209186fd96 100644 --- a/GPU/Common/VertexDecoderCommon.h +++ b/GPU/Common/VertexDecoderCommon.h @@ -102,7 +102,7 @@ public: : indices(indices), indexType(vertType & GE_VTYPE_IDX_MASK) { } - inline u32 convert(u32 index) const { + u32 operator() (u32 index) const { switch (indexType) { case GE_VTYPE_IDX_8BIT: return indices8[index]; diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index e31d062de5..45fc87ccde 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -280,7 +280,7 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy u16 index_lower_bound = 0; u16 index_upper_bound = vertex_count - 1; - IndexConverter idxConv(vertex_type, indices); + IndexConverter ConvertIndex(vertex_type, indices); if (indices) GetIndexBounds(indices, vertex_count, vertex_type, &index_lower_bound, &index_upper_bound); @@ -321,7 +321,7 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy { for (int vtx = 0; vtx < vertex_count; ++vtx) { if (indices) { - vreader.Goto(idxConv.convert(vtx) - index_lower_bound); + vreader.Goto(ConvertIndex(vtx) - index_lower_bound); } else { vreader.Goto(vtx); } @@ -380,7 +380,7 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy int skip_count = data_index == 0 ? 1 : 0; for (int vtx = 0; vtx < vertex_count; ++vtx) { if (indices) { - vreader.Goto(idxConv.convert(vtx) - index_lower_bound); + vreader.Goto(ConvertIndex(vtx) - index_lower_bound); } else { vreader.Goto(vtx); } @@ -410,7 +410,7 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy for (int vtx = 0; vtx < vertex_count; ++vtx) { if (indices) { - vreader.Goto(idxConv.convert(vtx) - index_lower_bound); + vreader.Goto(ConvertIndex(vtx) - index_lower_bound); } else { vreader.Goto(vtx); } @@ -452,7 +452,7 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy // Only read the central vertex if we're not continuing. if (data_index == 0) { if (indices) { - vreader.Goto(idxConv.convert(0) - index_lower_bound); + vreader.Goto(ConvertIndex(0) - index_lower_bound); } else { vreader.Goto(0); } @@ -463,7 +463,7 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy for (int vtx = start_vtx; vtx < vertex_count; ++vtx) { if (indices) { - vreader.Goto(idxConv.convert(vtx) - index_lower_bound); + vreader.Goto(ConvertIndex(vtx) - index_lower_bound); } else { vreader.Goto(vtx); } From 62ad5fe546391dd9213b78c2b8998260f40e60bb Mon Sep 17 00:00:00 2001 From: xebra Date: Wed, 31 Jan 2018 09:03:13 +0900 Subject: [PATCH 016/347] Fix namespace Vec2f. --- GPU/Common/SplineCommon.cpp | 14 +++++++------- GPU/Math3D.h | 3 +-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 1bd537da18..4f92cae074 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -134,7 +134,7 @@ inline float bern2deriv(float x) { return 3 * (2 - 3 * x) * x; } inline float bern3deriv(float x) { return 3 * x * x; } // http://en.wikipedia.org/wiki/Bernstein_polynomial -static Math3D::Vec2f Bernstein3D(const Math3D::Vec2f& p0, const Math3D::Vec2f& p1, const Math3D::Vec2f& p2, const Math3D::Vec2f& p3, float x) { +static Vec2f Bernstein3D(const Vec2f& p0, const Vec2f& p1, const Vec2f& p2, const Vec2f& p3, float x) { if (x == 0) return p0; else if (x == 1) return p3; return p0 * bern0(x) + p1 * bern1(x) + p2 * bern2(x) + p3 * bern3(x); @@ -693,7 +693,7 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te PrecomputedCurves prepos(tess_u + 1); PrecomputedCurves precol(tess_u + 1); - PrecomputedCurves pretex(tess_u + 1); + PrecomputedCurves pretex(tess_u + 1); PrecomputedCurves prederivU(tess_u + 1); const bool computeNormals = patch.computeNormals; @@ -715,10 +715,10 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te precol.horiz4[i] = Bernstein3D(patch.points[12]->color_32, patch.points[13]->color_32, patch.points[14]->color_32, patch.points[15]->color_32, u); } if (sampleTexcoords) { - pretex.horiz1[i] = Bernstein3D(Math3D::Vec2f(patch.points[0]->uv), Math3D::Vec2f(patch.points[1]->uv), Math3D::Vec2f(patch.points[2]->uv), Math3D::Vec2f(patch.points[3]->uv), u); - pretex.horiz2[i] = Bernstein3D(Math3D::Vec2f(patch.points[4]->uv), Math3D::Vec2f(patch.points[5]->uv), Math3D::Vec2f(patch.points[6]->uv), Math3D::Vec2f(patch.points[7]->uv), u); - pretex.horiz3[i] = Bernstein3D(Math3D::Vec2f(patch.points[8]->uv), Math3D::Vec2f(patch.points[9]->uv), Math3D::Vec2f(patch.points[10]->uv), Math3D::Vec2f(patch.points[11]->uv), u); - pretex.horiz4[i] = Bernstein3D(Math3D::Vec2f(patch.points[12]->uv), Math3D::Vec2f(patch.points[13]->uv), Math3D::Vec2f(patch.points[14]->uv), Math3D::Vec2f(patch.points[15]->uv), u); + pretex.horiz1[i] = Bernstein3D(Vec2f(patch.points[0]->uv), Vec2f(patch.points[1]->uv), Vec2f(patch.points[2]->uv), Vec2f(patch.points[3]->uv), u); + pretex.horiz2[i] = Bernstein3D(Vec2f(patch.points[4]->uv), Vec2f(patch.points[5]->uv), Vec2f(patch.points[6]->uv), Vec2f(patch.points[7]->uv), u); + pretex.horiz3[i] = Bernstein3D(Vec2f(patch.points[8]->uv), Vec2f(patch.points[9]->uv), Vec2f(patch.points[10]->uv), Vec2f(patch.points[11]->uv), u); + pretex.horiz4[i] = Bernstein3D(Vec2f(patch.points[12]->uv), Vec2f(patch.points[13]->uv), Vec2f(patch.points[14]->uv), Vec2f(patch.points[15]->uv), u); } if (computeNormals) { @@ -757,7 +757,7 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te vert.uv[1] = v + patch.v_index * third; } else { // Sample UV from control points - const Math3D::Vec2f res = pretex.Bernstein3D(tile_u, bv); + const Vec2f res = pretex.Bernstein3D(tile_u, bv); vert.uv[0] = res.x; vert.uv[1] = res.y; } diff --git a/GPU/Math3D.h b/GPU/Math3D.h index ba01d31600..420de4e91a 100644 --- a/GPU/Math3D.h +++ b/GPU/Math3D.h @@ -177,8 +177,6 @@ public: const Vec2 ts() const { return Vec2(y, x); } }; -typedef Vec2 Vec2f; - template class Vec3Packed; @@ -817,6 +815,7 @@ private: }; // namespace Math3D +typedef Math3D::Vec2 Vec2f; typedef Math3D::Vec3 Vec3f; typedef Math3D::Vec3Packed Vec3Packedf; typedef Math3D::Vec4 Vec4f; From 36ed61d08d6933155af0af6fa5341731fb011a85 Mon Sep 17 00:00:00 2001 From: xebra Date: Wed, 31 Jan 2018 11:34:37 +0900 Subject: [PATCH 017/347] [spline/bezier]Pre-convert control-points for the accumulation of SIMD optimization, and avoid conversion in hot loops. # Conflicts: # GPU/Common/SplineCommon.cpp # GPU/Common/SplineCommon.h --- GPU/Common/SplineCommon.cpp | 40 ++++++++++++++++++++++++++----------- GPU/Common/SplineCommon.h | 9 ++++++--- 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 4f92cae074..35d2bf3c1e 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -366,9 +366,9 @@ static void _SplinePatchLowQuality(u8 *&dest, u16 *indices, int &count, const Sp } -static inline void AccumulateWeighted(Vec3f &out, const Vec3Packedf &in, const Vec4f &w) { +static inline void AccumulateWeighted(Vec3f &out, const Vec3f &in, const Vec4f &w) { #ifdef _M_SSE - out.vec = _mm_add_ps(out.vec, _mm_mul_ps(_mm_loadu_ps(in.AsArray()), w.vec)); + out.vec = _mm_add_ps(out.vec, _mm_mul_ps(in.vec, w.vec)); #else out += in * w.x; #endif @@ -382,6 +382,14 @@ static inline void AccumulateWeighted(Vec4f &out, const Vec4f &in, const Vec4f & #endif } +static inline void AccumulateWeighted(Vec2f &out, const Vec2f &in, const Vec4f &w) { +#ifdef _M_SSE + out.vec = _mm_add_ps(out.vec, _mm_mul_ps(in.vec, w.vec)); +#else + out += in * w; +#endif +} + template static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const SplinePatchLocal &spatch, u32 origVertType, int quality, int maxVertices) { // Full (mostly) correct tessellation of spline patches. @@ -445,6 +453,7 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp Vec3f du, dv; du.SetZero(); dv.SetZero(); + Vec2f vert_tex; if (origNrm) { vert_nrm.SetZero(); } @@ -454,8 +463,7 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp memcpy(vert->color, spatch.points[0]->color, 4); } if (origTc) { - vert->uv[0] = 0.0f; - vert->uv[1] = 0.0f; + vert_tex.SetZero(); } else { 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); @@ -503,19 +511,16 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp OutputDebugStringA(temp); Crash(); }*/ - const SimpleVertex *a = spatch.points[idx]; - AccumulateWeighted(vert_pos, a->pos, fv); + AccumulateWeighted(vert_pos, spatch.pos[idx], fv); if (origTc) { - vert->uv[0] += a->uv[0] * f; - vert->uv[1] += a->uv[1] * f; + AccumulateWeighted(vert_tex, spatch.tex[idx], fv); } if (origCol) { - Vec4f a_color = Vec4f::FromRGBA(a->color_32); - AccumulateWeighted(vert_color, a_color, fv); + AccumulateWeighted(vert_color, spatch.col[idx], fv); } if (origNrm) { - AccumulateWeighted(du, a->pos, Vec4f::AssignToAll(u_derivs[ii] * v_weights[jj])); - AccumulateWeighted(dv, a->pos, Vec4f::AssignToAll(u_weights[ii] * v_derivs[jj])); + AccumulateWeighted(du, spatch.pos[idx], Vec4f::AssignToAll(u_derivs[ii] * v_weights[jj])); + AccumulateWeighted(dv, spatch.pos[idx], Vec4f::AssignToAll(u_weights[ii] * v_derivs[jj])); } } } @@ -537,6 +542,9 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp if (origCol) { vert->color_32 = vert_color.ToRGBA(); } + if (origTc) { + vert_tex.Write(vert->uv); + } } } @@ -919,6 +927,14 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi TessellateSplinePatchHardware(dest, quadIndices_, count, patch); numPatches = (count_u - 3) * (count_v - 3); } else { + patch.pos = (Vec3f *)managedBuf.Allocate(sizeof(Vec3f) * count_u * count_v); + patch.tex = (Vec2f *)managedBuf.Allocate(sizeof(Vec2f) * count_u * count_v); + patch.col = (Vec4f *)managedBuf.Allocate(sizeof(Vec4f) * count_u * count_v); + for (int idx = 0; idx < count_u * count_v; idx++) { + patch.pos[idx] = Vec3f(points[idx]->pos); + patch.tex[idx] = Vec2f(points[idx]->uv); + patch.col[idx] = Vec4f::FromRGBA(points[idx]->color_32); + } int maxVertexCount = SPLINE_BUFFER_SIZE / vertexSize; TessellateSplinePatch(dest, quadIndices_, count, patch, origVertType, maxVertexCount); } diff --git a/GPU/Common/SplineCommon.h b/GPU/Common/SplineCommon.h index 52bf75b69b..49dfa94f36 100644 --- a/GPU/Common/SplineCommon.h +++ b/GPU/Common/SplineCommon.h @@ -36,7 +36,9 @@ struct SimpleVertex { // We decode all vertices into a common format for easy interpolation and stuff. // Not fast but can be optimized later. struct BezierPatch { - const SimpleVertex *points[16]; + Vec3f *pos; + Vec4f *col; + Vec2f *tex; // These are used to generate UVs. int u_index, v_index; @@ -48,7 +50,9 @@ struct BezierPatch { }; struct SplinePatchLocal { - const SimpleVertex **points; + Vec3f *pos; + Vec4f *col; + Vec2f *tex; int tess_u; int tess_v; int count_u; @@ -68,4 +72,3 @@ enum SplineQuality { bool CanUseHardwareTessellation(GEPatchPrimType prim); void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, const SplinePatchLocal &spatch, u32 origVertType, int maxVertices); -void TessellateBezierPatch(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType); From c8e45ae4bfc15d9445864989f34284fc35652f5b Mon Sep 17 00:00:00 2001 From: xebra Date: Wed, 31 Jan 2018 12:44:05 +0900 Subject: [PATCH 018/347] [spline/bezier]Use real tessellation in low-quality with "fixed to 2" tessellation factor. # Conflicts: # GPU/Common/SplineCommon.cpp --- GPU/Common/SplineCommon.cpp | 163 +++--------------------------------- GPU/Common/SplineCommon.h | 1 + 2 files changed, 12 insertions(+), 152 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 35d2bf3c1e..2a6e66cd19 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -74,24 +74,6 @@ inline __m128 SSENormalizeMultiplier(bool useSSE4, __m128 v) #endif - -#define START_OPEN 1 -#define END_OPEN 2 - - - -static void CopyQuad(u8 *&dest, const SimpleVertex *v1, const SimpleVertex *v2, const SimpleVertex *v3, const SimpleVertex *v4) { - int vertexSize = sizeof(SimpleVertex); - memcpy(dest, v1, vertexSize); - dest += vertexSize; - memcpy(dest, v2, vertexSize); - dest += vertexSize; - memcpy(dest, v3, vertexSize); - dest += vertexSize; - memcpy(dest, v4, vertexSize); - dest += vertexSize; -} - static void CopyQuadIndex(u16 *&indices, GEPatchPrimType type, const int idx0, const int idx1, const int idx2, const int idx3) { if (type == GE_PATCHPRIM_LINES) { *(indices++) = idx0; @@ -243,6 +225,7 @@ static void spline_knot(int n, int type, float *knots, KnotDiv *divs) { knots[i] = (float)i - 2; } + // The first edge is open if ((type & 1) != 0) { knots[0] = 0; knots[1] = 0; @@ -253,6 +236,7 @@ static void spline_knot(int n, int type, float *knots, KnotDiv *divs) { if (n > 1) divs[1]._3_0 = 1.0f / 2.0f; } + // The last edge is open if ((type & 2) != 0) { // knots[n + 2] = (float)n; // Got rid of this line optimized with KnotDiv // knots[n + 3] = (float)n; // Got rid of this line optimized with KnotDiv @@ -296,76 +280,6 @@ static void TessellateSplinePatchHardware(u8 *&dest, u16 *indices, int &count, c BuildIndex(indices, count, spatch.tess_u, spatch.tess_v, spatch.primType); } -static void _SplinePatchLowQuality(u8 *&dest, u16 *indices, int &count, const SplinePatchLocal &spatch, u32 origVertType) { - // Fast and easy way - just draw the control points, generate some very basic normal vector substitutes. - // Very inaccurate but okay for Loco Roco. Maybe should keep it as an option because it's fast. - - const int tile_min_u = (spatch.type_u & START_OPEN) ? 0 : 1; - const int tile_min_v = (spatch.type_v & START_OPEN) ? 0 : 1; - const int tile_max_u = (spatch.type_u & END_OPEN) ? spatch.count_u - 1 : spatch.count_u - 2; - const int tile_max_v = (spatch.type_v & END_OPEN) ? spatch.count_v - 1 : spatch.count_v - 2; - - float tu_width = (float)spatch.count_u - 3.0f; - float tv_height = (float)spatch.count_v - 3.0f; - tu_width /= (float)(tile_max_u - tile_min_u); - tv_height /= (float)(tile_max_v - tile_min_v); - - GEPatchPrimType prim_type = spatch.primType; - bool computeNormals = spatch.computeNormals; - bool patchFacing = spatch.patchFacing; - - int i = 0; - for (int tile_v = tile_min_v; tile_v < tile_max_v; ++tile_v) { - for (int tile_u = tile_min_u; tile_u < tile_max_u; ++tile_u) { - int point_index = tile_u + tile_v * spatch.count_u; - - SimpleVertex v0 = *spatch.points[point_index]; - SimpleVertex v1 = *spatch.points[point_index + 1]; - SimpleVertex v2 = *spatch.points[point_index + spatch.count_u]; - SimpleVertex v3 = *spatch.points[point_index + spatch.count_u + 1]; - - // Generate UV. TODO: Do this even if UV specified in control points? - if ((origVertType & GE_VTYPE_TC_MASK) == 0) { - float u = (tile_u - tile_min_u) * tu_width; - float v = (tile_v - tile_min_v) * tv_height; - - v0.uv[0] = u; - v0.uv[1] = v; - v1.uv[0] = u + tu_width; - v1.uv[1] = v; - v2.uv[0] = u; - v2.uv[1] = v + tv_height; - v3.uv[0] = u + tu_width; - v3.uv[1] = v + tv_height; - } - - // Generate normal if lighting is enabled (otherwise there's no point). - // This is a really poor quality algorithm, we get facet normals. - if (computeNormals) { - Vec3Packedf norm = Cross(v1.pos - v0.pos, v2.pos - v0.pos); - norm.Normalize(); - if (patchFacing) - norm *= -1.0f; - v0.nrm = norm; - v1.nrm = norm; - v2.nrm = norm; - v3.nrm = norm; - } - - int idx0 = i * 4 + 0; - int idx1 = i * 4 + 1; - int idx2 = i * 4 + 2; - int idx3 = i * 4 + 3; - i++; - - CopyQuad(dest, &v0, &v1, &v2, &v3); - CopyQuadIndex(indices, prim_type, idx0, idx1, idx2, idx3); - count += 6; - } - } - -} - static inline void AccumulateWeighted(Vec3f &out, const Vec3f &in, const Vec4f &w) { #ifdef _M_SSE out.vec = _mm_add_ps(out.vec, _mm_mul_ps(in.vec, w.vec)); @@ -405,6 +319,11 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp // Increase tessellation based on the size. Should be approximately right? int patch_div_s = (spatch.count_u - 3) * spatch.tess_u; int patch_div_t = (spatch.count_v - 3) * spatch.tess_v; + if (quality == 0) { + // Low quality + patch_div_s = (spatch.count_u - 3) * 2; + patch_div_t = (spatch.count_v - 3) * 2; + } if (quality > 1) { // Don't cut below 2, though. if (patch_div_s > 2) { @@ -460,7 +379,7 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp if (origCol) { vert_color.SetZero(); } else { - memcpy(vert->color, spatch.points[0]->color, 4); + vert->color_32 = spatch.defcolor; } if (origTc) { vert_tex.SetZero(); @@ -596,7 +515,7 @@ static void SplinePatchFullQualityDispatch(u8 *&dest, u16 *indices, int &count, void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, const SplinePatchLocal &spatch, u32 origVertType, int maxVertexCount) { switch (g_Config.iSplineBezierQuality) { case LOW_QUALITY: - _SplinePatchLowQuality(dest, indices, count, spatch, origVertType); + SplinePatchFullQualityDispatch(dest, indices, count, spatch, origVertType, 0, maxVertexCount); break; case MEDIUM_QUALITY: SplinePatchFullQualityDispatch(dest, indices, count, spatch, origVertType, 2, maxVertexCount); @@ -607,66 +526,6 @@ void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, const SplinePatc } } -static void _BezierPatchLowQuality(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType) { - const float third = 1.0f / 3.0f; - // Fast and easy way - just draw the control points, generate some very basic normal vector subsitutes. - // Very inaccurate though but okay for Loco Roco. Maybe should keep it as an option. - - float u_base = patch.u_index / 3.0f; - float v_base = patch.v_index / 3.0f; - - GEPatchPrimType prim_type = patch.primType; - - for (int tile_v = 0; tile_v < 3; tile_v++) { - for (int tile_u = 0; tile_u < 3; tile_u++) { - int point_index = tile_u + tile_v * 4; - - SimpleVertex v0 = *patch.points[point_index]; - SimpleVertex v1 = *patch.points[point_index + 1]; - SimpleVertex v2 = *patch.points[point_index + 4]; - SimpleVertex v3 = *patch.points[point_index + 5]; - - // Generate UV. TODO: Do this even if UV specified in control points? - if ((origVertType & GE_VTYPE_TC_MASK) == 0) { - float u = u_base + tile_u * third; - float v = v_base + tile_v * third; - v0.uv[0] = u; - v0.uv[1] = v; - v1.uv[0] = u + third; - v1.uv[1] = v; - v2.uv[0] = u; - v2.uv[1] = v + third; - v3.uv[0] = u + third; - v3.uv[1] = v + third; - } - - // Generate normal if lighting is enabled (otherwise there's no point). - // This is a really poor quality algorithm, we get facet normals. - if (patch.computeNormals) { - Vec3Packedf norm = Cross(v1.pos - v0.pos, v2.pos - v0.pos); - norm.Normalize(); - if (patch.patchFacing) - norm *= -1.0f; - v0.nrm = norm; - v1.nrm = norm; - v2.nrm = norm; - v3.nrm = norm; - } - - int total = patch.index * 3 * 3 * 4; // A patch has 3x3 tiles, and each tiles have 4 vertices. - int tile_index = tile_u + tile_v * 3; - int idx0 = total + tile_index * 4 + 0; - int idx1 = total + tile_index * 4 + 1; - int idx2 = total + tile_index * 4 + 2; - int idx3 = total + tile_index * 4 + 3; - - CopyQuad(dest, &v0, &v1, &v2, &v3); - CopyQuadIndex(indices, prim_type, idx0, idx1, idx2, idx3); - count += 6; - } - } -} - template struct PrecomputedCurves { PrecomputedCurves(int count) { @@ -818,7 +677,7 @@ static void TessellateBezierPatchHardware(u8 *&dest, u16 *indices, int &count, i void TessellateBezierPatch(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType) { switch (g_Config.iSplineBezierQuality) { case LOW_QUALITY: - _BezierPatchLowQuality(dest, indices, count, tess_u, tess_v, patch, origVertType); + _BezierPatchHighQuality(dest, indices, count, 2, 2, patch, origVertType); break; case MEDIUM_QUALITY: _BezierPatchHighQuality(dest, indices, count, std::max(tess_u / 2, 1), std::max(tess_v / 2, 1), patch, origVertType); @@ -917,10 +776,10 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi patch.type_v = type_v; patch.count_u = count_u; patch.count_v = count_v; - patch.points = points; patch.computeNormals = computeNormals; patch.primType = prim_type; patch.patchFacing = patchFacing; + patch.defcolor = points[0]->color_32; if (CanUseHardwareTessellation(prim_type)) { tessDataTransfer->SendDataToShader(points, count_u * count_v, origVertType); diff --git a/GPU/Common/SplineCommon.h b/GPU/Common/SplineCommon.h index 49dfa94f36..9f7133a2f4 100644 --- a/GPU/Common/SplineCommon.h +++ b/GPU/Common/SplineCommon.h @@ -53,6 +53,7 @@ struct SplinePatchLocal { Vec3f *pos; Vec4f *col; Vec2f *tex; + u32_le defcolor; int tess_u; int tess_v; int count_u; From d0682d7829ec590d00582e8a0e5b076dfe702d59 Mon Sep 17 00:00:00 2001 From: xebra Date: Wed, 31 Jan 2018 16:38:11 +0900 Subject: [PATCH 019/347] [spline/bezier]Move SIMD optimization of vector operations to Math3D.h. Needs rebuild to avoid a dialog confirmation on Visual Studio. --- GPU/Common/SplineCommon.cpp | 98 +++---------------------------------- GPU/Math3D.cpp | 40 ++++++++++++++- GPU/Math3D.h | 93 ++++++++++++++++++++++++++++++++++- 3 files changed, 139 insertions(+), 92 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 2a6e66cd19..6b84c8cc76 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -30,50 +30,6 @@ #include "GPU/ge_constants.h" #include "GPU/GPUState.h" // only needed for UVScale stuff -#if defined(_M_SSE) -#include - -inline __m128 SSECrossProduct(__m128 a, __m128 b) -{ - const __m128 left = _mm_mul_ps(_mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 0, 2, 1)), _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 1, 0, 2))); - const __m128 right = _mm_mul_ps(_mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 1, 0, 2)), _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 0, 2, 1))); - return _mm_sub_ps(left, right); -} - -inline __m128 SSENormalizeMultiplierSSE2(__m128 v) -{ - const __m128 sq = _mm_mul_ps(v, v); - const __m128 r2 = _mm_shuffle_ps(sq, sq, _MM_SHUFFLE(0, 0, 0, 1)); - const __m128 r3 = _mm_shuffle_ps(sq, sq, _MM_SHUFFLE(0, 0, 0, 2)); - const __m128 res = _mm_add_ss(r3, _mm_add_ss(r2, sq)); - - const __m128 rt = _mm_rsqrt_ss(res); - return _mm_shuffle_ps(rt, rt, _MM_SHUFFLE(0, 0, 0, 0)); -} - -#if _M_SSE >= 0x401 -#include - -inline __m128 SSENormalizeMultiplierSSE4(__m128 v) -{ - return _mm_rsqrt_ps(_mm_dp_ps(v, v, 0xFF)); -} - -inline __m128 SSENormalizeMultiplier(bool useSSE4, __m128 v) -{ - if (useSSE4) - return SSENormalizeMultiplierSSE4(v); - return SSENormalizeMultiplierSSE2(v); -} -#else -inline __m128 SSENormalizeMultiplier(bool useSSE4, __m128 v) -{ - return SSENormalizeMultiplierSSE2(v); -} -#endif - -#endif - static void CopyQuadIndex(u16 *&indices, GEPatchPrimType type, const int idx0, const int idx1, const int idx2, const int idx3) { if (type == GE_PATCHPRIM_LINES) { *(indices++) = idx0; @@ -280,30 +236,6 @@ static void TessellateSplinePatchHardware(u8 *&dest, u16 *indices, int &count, c BuildIndex(indices, count, spatch.tess_u, spatch.tess_v, spatch.primType); } -static inline void AccumulateWeighted(Vec3f &out, const Vec3f &in, const Vec4f &w) { -#ifdef _M_SSE - out.vec = _mm_add_ps(out.vec, _mm_mul_ps(in.vec, w.vec)); -#else - out += in * w.x; -#endif -} - -static inline void AccumulateWeighted(Vec4f &out, const Vec4f &in, const Vec4f &w) { -#ifdef _M_SSE - out.vec = _mm_add_ps(out.vec, _mm_mul_ps(in.vec, w.vec)); -#else - out += in * w; -#endif -} - -static inline void AccumulateWeighted(Vec2f &out, const Vec2f &in, const Vec4f &w) { -#ifdef _M_SSE - out.vec = _mm_add_ps(out.vec, _mm_mul_ps(in.vec, w.vec)); -#else - out += in * w; -#endif -} - template static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const SplinePatchLocal &spatch, u32 origVertType, int quality, int maxVertices) { // Full (mostly) correct tessellation of spline patches. @@ -368,13 +300,11 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp Vec4f vert_color(0, 0, 0, 0); Vec3f vert_pos; vert_pos.SetZero(); - Vec3f vert_nrm; Vec3f du, dv; - du.SetZero(); - dv.SetZero(); Vec2f vert_tex; if (origNrm) { - vert_nrm.SetZero(); + du.SetZero(); + dv.SetZero(); } if (origCol) { vert_color.SetZero(); @@ -417,11 +347,6 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp float f = u_spline * v_spline; if (f > 0.0f) { -#ifdef _M_SSE - Vec4f fv(_mm_set_ps1(f)); -#else - Vec4f fv = Vec4f::AssignToAll(f); -#endif int idx = spatch.count_u * (iv + jj) + (iu + ii); /* if (idx >= max_idx) { @@ -430,30 +355,23 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp OutputDebugStringA(temp); Crash(); }*/ - AccumulateWeighted(vert_pos, spatch.pos[idx], fv); + vert_pos += spatch.pos[idx] * f; if (origTc) { - AccumulateWeighted(vert_tex, spatch.tex[idx], fv); + vert_tex += spatch.tex[idx] * f; } if (origCol) { - AccumulateWeighted(vert_color, spatch.col[idx], fv); + vert_color += spatch.col[idx] * f; } if (origNrm) { - AccumulateWeighted(du, spatch.pos[idx], Vec4f::AssignToAll(u_derivs[ii] * v_weights[jj])); - AccumulateWeighted(dv, spatch.pos[idx], Vec4f::AssignToAll(u_weights[ii] * v_derivs[jj])); + du += spatch.pos[idx] * (u_derivs[ii] * v_weights[jj]); + dv += spatch.pos[idx] * (u_weights[ii] * v_derivs[jj]); } } } } vert->pos = vert_pos; if (origNrm) { - vert_nrm = Cross(du, dv); -#ifdef _M_SSE - const __m128 normalize = SSENormalizeMultiplier(useSSE4, vert_nrm.vec); - vert_nrm.vec = _mm_mul_ps(vert_nrm.vec, normalize); -#else - vert_nrm.Normalize(); -#endif - vert->nrm = vert_nrm; + vert->nrm = Cross(du, dv).Normalized(useSSE4); } else { vert->nrm.SetZero(); vert->nrm.z = 1.0f; diff --git a/GPU/Math3D.cpp b/GPU/Math3D.cpp index f43f41ade6..c46a4e520d 100644 --- a/GPU/Math3D.cpp +++ b/GPU/Math3D.cpp @@ -102,11 +102,49 @@ float Vec3::Distance2To(Vec3 &other) return Vec3(other-(*this)).Length2(); } +#if defined(_M_SSE) +__m128 SSENormalizeMultiplierSSE2(__m128 v) +{ + const __m128 sq = _mm_mul_ps(v, v); + const __m128 r2 = _mm_shuffle_ps(sq, sq, _MM_SHUFFLE(0, 0, 0, 1)); + const __m128 r3 = _mm_shuffle_ps(sq, sq, _MM_SHUFFLE(0, 0, 0, 2)); + const __m128 res = _mm_add_ss(r3, _mm_add_ss(r2, sq)); + + const __m128 rt = _mm_rsqrt_ss(res); + return _mm_shuffle_ps(rt, rt, _MM_SHUFFLE(0, 0, 0, 0)); +} + +#if _M_SSE >= 0x401 +__m128 SSENormalizeMultiplierSSE4(__m128 v) +{ + return _mm_rsqrt_ps(_mm_dp_ps(v, v, 0xFF)); +} + +__m128 SSENormalizeMultiplier(bool useSSE4, __m128 v) +{ + if (useSSE4) + return SSENormalizeMultiplierSSE4(v); + return SSENormalizeMultiplierSSE2(v); +} +#else +__m128 SSENormalizeMultiplier(bool useSSE4, __m128 v) +{ + return SSENormalizeMultiplierSSE2(v); +} +#endif template<> -Vec3 Vec3::Normalized() const +Vec3 Vec3::Normalized(bool useSSE4) const +{ + const __m128 normalize = SSENormalizeMultiplier(useSSE4, vec); + return _mm_mul_ps(normalize, vec); +} +#else +template<> +Vec3 Vec3::Normalized(bool useSSE4) const { return (*this) / Length(); } +#endif template<> float Vec3::Normalize() diff --git a/GPU/Math3D.h b/GPU/Math3D.h index 420de4e91a..04743436ea 100644 --- a/GPU/Math3D.h +++ b/GPU/Math3D.h @@ -25,6 +25,9 @@ #if defined(_M_SSE) #include +#if _M_SSE >= 0x401 +#include +#endif #endif namespace Math3D { @@ -293,7 +296,7 @@ public: void SetLength(const float l); Vec3 WithLength(const float l) const; float Distance2To(Vec3 &other); - Vec3 Normalized() const; + Vec3 Normalized(bool useSSE4 = false) const; float Normalize(); // returns the previous length, which is often useful T& operator [] (int i) //allow vector[2] = 3 (vector.z=3) @@ -1081,6 +1084,94 @@ __forceinline void Vec4::ToRGBA(u8 *rgba) const *(u32 *)rgba = ToRGBA(); } +#if defined(_M_SSE) +// Specialized for SIMD optimization + +// Vec2 operation +template<> +inline void Vec2::operator += (const Vec2 &other) +{ + vec = _mm_add_ps(vec, other.vec); +} + +template<> +inline Vec2 Vec2::operator + (const Vec2 &other) const +{ + return Vec2(_mm_add_ps(vec, other.vec)); +} + +template<> +inline Vec2 Vec2::operator * (const Vec2 &other) const +{ + return Vec2(_mm_mul_ps(vec, other.vec)); +} + +template<> template<> +inline Vec2 Vec2::operator * (const float &other) const +{ + return Vec2(_mm_mul_ps(vec, _mm_set_ps1(other))); +} + +// Vec3 operation +template<> +inline void Vec3::operator += (const Vec3 &other) +{ + vec = _mm_add_ps(vec, other.vec); +} + +template<> +inline Vec3 Vec3::operator + (const Vec3 &other) const +{ + return Vec3(_mm_add_ps(vec, other.vec)); +} + +template<> +inline Vec3 Vec3::operator * (const Vec3 &other) const +{ + return Vec3(_mm_mul_ps(vec, other.vec)); +} + +template<> template<> +inline Vec3 Vec3::operator * (const float &other) const +{ + return Vec3(_mm_mul_ps(vec, _mm_set_ps1(other))); +} + +// Vec4 operation +template<> +inline void Vec4::operator += (const Vec4 &other) +{ + vec = _mm_add_ps(vec, other.vec); +} + +template<> +inline Vec4 Vec4::operator + (const Vec4 &other) const +{ + return Vec4(_mm_add_ps(vec, other.vec)); +} + +template<> +inline Vec4 Vec4::operator * (const Vec4 &other) const +{ + return Vec4(_mm_mul_ps(vec, other.vec)); +} + +template<> template<> +inline Vec4 Vec4::operator * (const float &other) const +{ + return Vec4(_mm_mul_ps(vec, _mm_set_ps1(other))); +} + +// Vec3 cross product +template<> +inline Vec3 Cross(const Vec3 &a, const Vec3 &b) +{ + const __m128 left = _mm_mul_ps(_mm_shuffle_ps(a.vec, a.vec, _MM_SHUFFLE(3, 0, 2, 1)), _mm_shuffle_ps(b.vec, b.vec, _MM_SHUFFLE(3, 1, 0, 2))); + const __m128 right = _mm_mul_ps(_mm_shuffle_ps(a.vec, a.vec, _MM_SHUFFLE(3, 1, 0, 2)), _mm_shuffle_ps(b.vec, b.vec, _MM_SHUFFLE(3, 0, 2, 1))); + return _mm_sub_ps(left, right); +} +#endif + }; // namespace Math3D // linear interpolation via float: 0.0=begin, 1.0=end From a340390996919584dbab135e18f428cde05ff09e Mon Sep 17 00:00:00 2001 From: xebra Date: Wed, 31 Jan 2018 18:39:43 +0900 Subject: [PATCH 020/347] [spline/bezier]Move bezier patch loops into the function and pre-convert control-points. --- GPU/Common/SplineCommon.cpp | 213 +++++++++++++++++------------------- GPU/Common/SplineCommon.h | 8 +- 2 files changed, 101 insertions(+), 120 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 6b84c8cc76..c2c5990e74 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -72,28 +72,13 @@ inline float bern2deriv(float x) { return 3 * (2 - 3 * x) * x; } inline float bern3deriv(float x) { return 3 * x * x; } // http://en.wikipedia.org/wiki/Bernstein_polynomial -static Vec2f Bernstein3D(const Vec2f& p0, const Vec2f& p1, const Vec2f& p2, const Vec2f& p3, float x) { +template +static T Bernstein3D(const T& p0, const T& p1, const T& p2, const T& p3, float x) { if (x == 0) return p0; - else if (x == 1) return p3; + if (x == 1) return p3; return p0 * bern0(x) + p1 * bern1(x) + p2 * bern2(x) + p3 * bern3(x); } -static Vec3f Bernstein3D(const Vec3f& p0, const Vec3f& p1, const Vec3f& p2, const Vec3f& p3, float x) { - if (x == 0) return p0; - else if (x == 1) return p3; - return p0 * bern0(x) + p1 * bern1(x) + p2 * bern2(x) + p3 * bern3(x); -} - -static Vec4f Bernstein3D(const Vec4f& p0, const Vec4f& p1, const Vec4f& p2, const Vec4f& p3, float x) { - if (x == 0) return p0; - else if (x == 1) return p3; - return p0 * bern0(x) + p1 * bern1(x) + p2 * bern2(x) + p3 * bern3(x); -} - -static Vec4f Bernstein3D(const u32& p0, const u32& p1, const u32& p2, const u32& p3, float x) { - return Bernstein3D(Vec4f::FromRGBA(p0), Vec4f::FromRGBA(p1), Vec4f::FromRGBA(p2), Vec4f::FromRGBA(p3), x); -} - static Vec3f Bernstein3DDerivative(const Vec3f& p0, const Vec3f& p1, const Vec3f& p2, const Vec3f& p3, float x) { return p0 * bern0deriv(x) + p1 * bern1deriv(x) + p2 * bern2deriv(x) + p3 * bern3deriv(x); } @@ -485,91 +470,95 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te const bool sampleColors = (origVertType & GE_VTYPE_COL_MASK) != 0; const bool sampleTexcoords = (origVertType & GE_VTYPE_TC_MASK) != 0; - // Precompute the horizontal curves to we only have to evaluate the vertical ones. - for (int i = 0; i < tess_u + 1; i++) { - float u = ((float)i / (float)tess_u); - prepos.horiz1[i] = Bernstein3D(patch.points[0]->pos, patch.points[1]->pos, patch.points[2]->pos, patch.points[3]->pos, u); - prepos.horiz2[i] = Bernstein3D(patch.points[4]->pos, patch.points[5]->pos, patch.points[6]->pos, patch.points[7]->pos, u); - prepos.horiz3[i] = Bernstein3D(patch.points[8]->pos, patch.points[9]->pos, patch.points[10]->pos, patch.points[11]->pos, u); - prepos.horiz4[i] = Bernstein3D(patch.points[12]->pos, patch.points[13]->pos, patch.points[14]->pos, patch.points[15]->pos, u); + int num_patches_u = (patch.count_u - 1) / 3; + int num_patches_v = (patch.count_v - 1) / 3; + for (int patch_u = 0; patch_u < num_patches_u; ++patch_u) { + for (int patch_v = 0; patch_v < num_patches_v; ++patch_v) { + // Precompute the horizontal curves to we only have to evaluate the vertical ones. + Vec3f *_pos[16]; + Vec4f *_col[16]; + Vec2f *_tex[16]; + for (int point = 0; point < 16; ++point) { + int idx = (patch_u * 3 + point % 4) + (patch_v * 3 + point / 4) * patch.count_u; + _pos[point] = &patch.pos[idx]; + _col[point] = &patch.col[idx]; + _tex[point] = &patch.tex[idx]; + } + for (int i = 0; i < tess_u + 1; i++) { + float u = ((float)i / (float)tess_u); + prepos.horiz1[i] = Bernstein3D(*_pos[0], *_pos[1], *_pos[2], *_pos[3], u); + prepos.horiz2[i] = Bernstein3D(*_pos[4], *_pos[5], *_pos[6], *_pos[7], u); + prepos.horiz3[i] = Bernstein3D(*_pos[8], *_pos[9], *_pos[10], *_pos[11], u); + prepos.horiz4[i] = Bernstein3D(*_pos[12], *_pos[13], *_pos[14], *_pos[15], u); - if (sampleColors) { - precol.horiz1[i] = Bernstein3D(patch.points[0]->color_32, patch.points[1]->color_32, patch.points[2]->color_32, patch.points[3]->color_32, u); - precol.horiz2[i] = Bernstein3D(patch.points[4]->color_32, patch.points[5]->color_32, patch.points[6]->color_32, patch.points[7]->color_32, u); - precol.horiz3[i] = Bernstein3D(patch.points[8]->color_32, patch.points[9]->color_32, patch.points[10]->color_32, patch.points[11]->color_32, u); - precol.horiz4[i] = Bernstein3D(patch.points[12]->color_32, patch.points[13]->color_32, patch.points[14]->color_32, patch.points[15]->color_32, u); - } - if (sampleTexcoords) { - pretex.horiz1[i] = Bernstein3D(Vec2f(patch.points[0]->uv), Vec2f(patch.points[1]->uv), Vec2f(patch.points[2]->uv), Vec2f(patch.points[3]->uv), u); - pretex.horiz2[i] = Bernstein3D(Vec2f(patch.points[4]->uv), Vec2f(patch.points[5]->uv), Vec2f(patch.points[6]->uv), Vec2f(patch.points[7]->uv), u); - pretex.horiz3[i] = Bernstein3D(Vec2f(patch.points[8]->uv), Vec2f(patch.points[9]->uv), Vec2f(patch.points[10]->uv), Vec2f(patch.points[11]->uv), u); - pretex.horiz4[i] = Bernstein3D(Vec2f(patch.points[12]->uv), Vec2f(patch.points[13]->uv), Vec2f(patch.points[14]->uv), Vec2f(patch.points[15]->uv), u); - } + if (sampleColors) { + precol.horiz1[i] = Bernstein3D(*_col[0], *_col[1], *_col[2], *_col[3], u); + precol.horiz2[i] = Bernstein3D(*_col[4], *_col[5], *_col[6], *_col[7], u); + precol.horiz3[i] = Bernstein3D(*_col[8], *_col[9], *_col[10], *_col[11], u); + precol.horiz4[i] = Bernstein3D(*_col[12], *_col[13], *_col[14], *_col[15], u); + } + if (sampleTexcoords) { + pretex.horiz1[i] = Bernstein3D(*_tex[0], *_tex[1], *_tex[2], *_tex[3], u); + pretex.horiz2[i] = Bernstein3D(*_tex[4], *_tex[5], *_tex[6], *_tex[7], u); + pretex.horiz3[i] = Bernstein3D(*_tex[8], *_tex[9], *_tex[10], *_tex[11], u); + pretex.horiz4[i] = Bernstein3D(*_tex[12], *_tex[13], *_tex[14], *_tex[15], u); + } - if (computeNormals) { - prederivU.horiz1[i] = Bernstein3DDerivative(patch.points[0]->pos, patch.points[1]->pos, patch.points[2]->pos, patch.points[3]->pos, u); - prederivU.horiz2[i] = Bernstein3DDerivative(patch.points[4]->pos, patch.points[5]->pos, patch.points[6]->pos, patch.points[7]->pos, u); - prederivU.horiz3[i] = Bernstein3DDerivative(patch.points[8]->pos, patch.points[9]->pos, patch.points[10]->pos, patch.points[11]->pos, u); - prederivU.horiz4[i] = Bernstein3DDerivative(patch.points[12]->pos, patch.points[13]->pos, patch.points[14]->pos, patch.points[15]->pos, u); - } - } - - - for (int tile_v = 0; tile_v < tess_v + 1; ++tile_v) { - for (int tile_u = 0; tile_u < tess_u + 1; ++tile_u) { - float u = ((float)tile_u / (float)tess_u); - float v = ((float)tile_v / (float)tess_v); - float bv = v; - - SimpleVertex &vert = vertices[tile_v * (tess_u + 1) + tile_u]; - - if (computeNormals) { - const Vec3f derivU = prederivU.Bernstein3D(tile_u, bv); - const Vec3f derivV = prepos.Bernstein3DDerivative(tile_u, bv); - - vert.nrm = Cross(derivU, derivV).Normalized(); - if (patch.patchFacing) - vert.nrm *= -1.0f; - } else { - vert.nrm.SetZero(); + if (computeNormals) { + prederivU.horiz1[i] = Bernstein3DDerivative(*_pos[0], *_pos[1], *_pos[2], *_pos[3], u); + prederivU.horiz2[i] = Bernstein3DDerivative(*_pos[4], *_pos[5], *_pos[6], *_pos[7], u); + prederivU.horiz3[i] = Bernstein3DDerivative(*_pos[8], *_pos[9], *_pos[10], *_pos[11], u); + prederivU.horiz4[i] = Bernstein3DDerivative(*_pos[12], *_pos[13], *_pos[14], *_pos[15], u); + } } - vert.pos = prepos.Bernstein3D(tile_u, bv); + for (int tile_v = 0; tile_v < tess_v + 1; ++tile_v) { + for (int tile_u = 0; tile_u < tess_u + 1; ++tile_u) { + float u = ((float)tile_u / (float)tess_u); + float v = ((float)tile_v / (float)tess_v); + float bv = v; - if (!sampleTexcoords) { - // Generate texcoord - vert.uv[0] = u + patch.u_index * third; - vert.uv[1] = v + patch.v_index * third; - } else { - // Sample UV from control points - const Vec2f res = pretex.Bernstein3D(tile_u, bv); - vert.uv[0] = res.x; - vert.uv[1] = res.y; - } + SimpleVertex &vert = vertices[tile_v * (tess_u + 1) + tile_u]; - if (sampleColors) { - vert.color_32 = precol.Bernstein3D(tile_u, bv).ToRGBA(); - } else { - memcpy(vert.color, patch.points[0]->color, 4); + if (computeNormals) { + const Vec3f derivU = prederivU.Bernstein3D(tile_u, bv); + const Vec3f derivV = prepos.Bernstein3DDerivative(tile_u, bv); + + vert.nrm = Cross(derivU, derivV).Normalized(); + if (patch.patchFacing) + vert.nrm *= -1.0f; + } else { + vert.nrm.SetZero(); + } + + vert.pos = prepos.Bernstein3D(tile_u, bv); + + if (!sampleTexcoords) { + // Generate texcoord + vert.uv[0] = u + patch_u * third; + vert.uv[1] = v + patch_u * third; + } else { + // Sample UV from control points + const Vec2f res = pretex.Bernstein3D(tile_u, bv); + vert.uv[0] = res.x; + vert.uv[1] = res.y; + } + + if (sampleColors) { + vert.color_32 = precol.Bernstein3D(tile_u, bv).ToRGBA(); + } else { + vert.color_32 = patch.defcolor; + } + } } + + int patch_index = patch_v * num_patches_u + patch_u; + int total = patch_index * (tess_u + 1) * (tess_v + 1); + BuildIndex(indices + count, count, tess_u, tess_v, patch.primType, total); + + dest += (tess_u + 1) * (tess_v + 1) * sizeof(SimpleVertex); } } - - GEPatchPrimType prim_type = patch.primType; - // Combine the vertices into triangles. - for (int tile_v = 0; tile_v < tess_v; ++tile_v) { - for (int tile_u = 0; tile_u < tess_u; ++tile_u) { - int total = patch.index * (tess_u + 1) * (tess_v + 1); - int idx0 = total + tile_v * (tess_u + 1) + tile_u; - int idx1 = total + tile_v * (tess_u + 1) + tile_u + 1; - int idx2 = total + (tile_v + 1) * (tess_u + 1) + tile_u; - int idx3 = total + (tile_v + 1) * (tess_u + 1) + tile_u + 1; - - CopyQuadIndex(indices, prim_type, idx0, idx1, idx2, idx3); - count += 6; - } - } - dest += (tess_u + 1) * (tess_v + 1) * sizeof(SimpleVertex); } // Prepare mesh of one patch for "Instanced Tessellation". @@ -796,21 +785,20 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi TessellateBezierPatchHardware(dest, inds, count, tess_u, tess_v, prim_type); numPatches = num_patches_u * num_patches_v; } else { - BezierPatch *patches = (BezierPatch *)managedBuf.Allocate(sizeof(BezierPatch) * num_patches_u * num_patches_v); - for (int patch_u = 0; patch_u < num_patches_u; patch_u++) { - for (int patch_v = 0; patch_v < num_patches_v; patch_v++) { - BezierPatch& patch = patches[patch_u + patch_v * num_patches_u]; - for (int point = 0; point < 16; ++point) { - int idx = (patch_u * 3 + point % 4) + (patch_v * 3 + point / 4) * count_u; - patch.points[point] = points[idx]; - } - patch.u_index = patch_u * 3; - patch.v_index = patch_v * 3; - patch.index = patch_v * num_patches_u + patch_u; - patch.primType = prim_type; - patch.computeNormals = computeNormals; - patch.patchFacing = patchFacing; - } + BezierPatch patch; + patch.count_u = count_u; + patch.count_v = count_v; + patch.primType = prim_type; + patch.computeNormals = computeNormals; + patch.patchFacing = patchFacing; + patch.defcolor = points[0]->color_32; + patch.pos = (Vec3f *)managedBuf.Allocate(sizeof(Vec3f) * count_u * count_v); + patch.tex = (Vec2f *)managedBuf.Allocate(sizeof(Vec2f) * count_u * count_v); + patch.col = (Vec4f *)managedBuf.Allocate(sizeof(Vec4f) * count_u * count_v); + for (int idx = 0; idx < count_u * count_v; idx++) { + patch.pos[idx] = Vec3f(points[idx]->pos); + patch.tex[idx] = Vec2f(points[idx]->uv); + patch.col[idx] = Vec4f::FromRGBA(points[idx]->color_32); } int maxVertices = SPLINE_BUFFER_SIZE / vertexSize; // Downsample until it fits, in case crazy tessellation factors are sent. @@ -818,12 +806,7 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi tess_u /= 2; tess_v /= 2; } - // We shouldn't really split up into separate 4x4 patches, instead we should do something that works - // like the splines, so we subdivide across the whole "mega-patch". - for (int patch_idx = 0; patch_idx < num_patches_u*num_patches_v; ++patch_idx) { - const BezierPatch &patch = patches[patch_idx]; - TessellateBezierPatch(dest, inds, count, tess_u, tess_v, patch, origVertType); - } + TessellateBezierPatch(dest, inds, count, tess_u, tess_v, patch, origVertType); } u32 vertTypeWithIndex16 = (vertType & ~GE_VTYPE_IDX_MASK) | GE_VTYPE_IDX_16BIT; diff --git a/GPU/Common/SplineCommon.h b/GPU/Common/SplineCommon.h index 9f7133a2f4..e0411c1153 100644 --- a/GPU/Common/SplineCommon.h +++ b/GPU/Common/SplineCommon.h @@ -39,11 +39,9 @@ struct BezierPatch { Vec3f *pos; Vec4f *col; Vec2f *tex; - - // These are used to generate UVs. - int u_index, v_index; - - int index; + u32_le defcolor; + int count_u; + int count_v; GEPatchPrimType primType; bool computeNormals; bool patchFacing; From 3aeb3201b9ecdcd2d8e0cf5e357cbcdf1a8dbdf3 Mon Sep 17 00:00:00 2001 From: xebra Date: Wed, 31 Jan 2018 19:25:43 +0900 Subject: [PATCH 021/347] [spline/bezier]Improve bezier weights calculation. --- GPU/Common/SplineCommon.cpp | 89 +++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 44 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index c2c5990e74..74a211de07 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -61,26 +61,27 @@ static void BuildIndex(u16 *indices, int &count, int num_u, int num_v, GEPatchPr } // Bernstein basis functions -inline float bern0(float x) { return (1 - x) * (1 - x) * (1 - x); } -inline float bern1(float x) { return 3 * x * (1 - x) * (1 - x); } -inline float bern2(float x) { return 3 * x * x * (1 - x); } -inline float bern3(float x) { return x * x * x; } +void Bernstein3DBasis(float x, float weights[4]) { + weights[0] = (1 - x) * (1 - x) * (1 - x); + weights[1] = 3 * x * (1 - x) * (1 - x); + weights[2] = 3 * x * x * (1 - x); + weights[3] = x * x * x; +} -inline float bern0deriv(float x) { return -3 * (x - 1) * (x - 1); } -inline float bern1deriv(float x) { return 9 * x * x - 12 * x + 3; } -inline float bern2deriv(float x) { return 3 * (2 - 3 * x) * x; } -inline float bern3deriv(float x) { return 3 * x * x; } +void Bernstein3DDerivative(float x, float derivs[4]) { + derivs[0] = -3 * (x - 1) * (x - 1); + derivs[1] = 9 * x * x - 12 * x + 3; + derivs[2] = 3 * (2 - 3 * x) * x; + derivs[3] = 3 * x * x; +} // http://en.wikipedia.org/wiki/Bernstein_polynomial template -static T Bernstein3D(const T& p0, const T& p1, const T& p2, const T& p3, float x) { - if (x == 0) return p0; - if (x == 1) return p3; - return p0 * bern0(x) + p1 * bern1(x) + p2 * bern2(x) + p3 * bern3(x); -} - -static Vec3f Bernstein3DDerivative(const Vec3f& p0, const Vec3f& p1, const Vec3f& p2, const Vec3f& p3, float x) { - return p0 * bern0deriv(x) + p1 * bern1deriv(x) + p2 * bern2deriv(x) + p3 * bern3deriv(x); +static T Bernstein3D(const T& p0, const T& p1, const T& p2, const T& p3, float w[4]) { + if (w[0] == 1) return p0; + if (w[3] == 1) return p3; + // Linear combination + return p0 * w[0] + p1 * w[1] + p2 * w[2] + p3 * w[3]; } struct KnotDiv { @@ -441,12 +442,8 @@ struct PrecomputedCurves { FreeAlignedMemory(horiz1); } - T Bernstein3D(int u, float bv) { - return ::Bernstein3D(horiz1[u], horiz2[u], horiz3[u], horiz4[u], bv); - } - - T Bernstein3DDerivative(int u, float bv) { - return ::Bernstein3DDerivative(horiz1[u], horiz2[u], horiz3[u], horiz4[u], bv); + T Bernstein3D(int u, float w[4]) { + return ::Bernstein3D(horiz1[u], horiz2[u], horiz3[u], horiz4[u], w); } T *horiz1; @@ -484,31 +481,34 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te _col[point] = &patch.col[idx]; _tex[point] = &patch.tex[idx]; } + float weights[4], derivs[4]; for (int i = 0; i < tess_u + 1; i++) { float u = ((float)i / (float)tess_u); - prepos.horiz1[i] = Bernstein3D(*_pos[0], *_pos[1], *_pos[2], *_pos[3], u); - prepos.horiz2[i] = Bernstein3D(*_pos[4], *_pos[5], *_pos[6], *_pos[7], u); - prepos.horiz3[i] = Bernstein3D(*_pos[8], *_pos[9], *_pos[10], *_pos[11], u); - prepos.horiz4[i] = Bernstein3D(*_pos[12], *_pos[13], *_pos[14], *_pos[15], u); + Bernstein3DBasis(u, weights); + prepos.horiz1[i] = Bernstein3D(*_pos[0], *_pos[1], *_pos[2], *_pos[3], weights); + prepos.horiz2[i] = Bernstein3D(*_pos[4], *_pos[5], *_pos[6], *_pos[7], weights); + prepos.horiz3[i] = Bernstein3D(*_pos[8], *_pos[9], *_pos[10], *_pos[11], weights); + prepos.horiz4[i] = Bernstein3D(*_pos[12], *_pos[13], *_pos[14], *_pos[15], weights); if (sampleColors) { - precol.horiz1[i] = Bernstein3D(*_col[0], *_col[1], *_col[2], *_col[3], u); - precol.horiz2[i] = Bernstein3D(*_col[4], *_col[5], *_col[6], *_col[7], u); - precol.horiz3[i] = Bernstein3D(*_col[8], *_col[9], *_col[10], *_col[11], u); - precol.horiz4[i] = Bernstein3D(*_col[12], *_col[13], *_col[14], *_col[15], u); + precol.horiz1[i] = Bernstein3D(*_col[0], *_col[1], *_col[2], *_col[3], weights); + precol.horiz2[i] = Bernstein3D(*_col[4], *_col[5], *_col[6], *_col[7], weights); + precol.horiz3[i] = Bernstein3D(*_col[8], *_col[9], *_col[10], *_col[11], weights); + precol.horiz4[i] = Bernstein3D(*_col[12], *_col[13], *_col[14], *_col[15], weights); } if (sampleTexcoords) { - pretex.horiz1[i] = Bernstein3D(*_tex[0], *_tex[1], *_tex[2], *_tex[3], u); - pretex.horiz2[i] = Bernstein3D(*_tex[4], *_tex[5], *_tex[6], *_tex[7], u); - pretex.horiz3[i] = Bernstein3D(*_tex[8], *_tex[9], *_tex[10], *_tex[11], u); - pretex.horiz4[i] = Bernstein3D(*_tex[12], *_tex[13], *_tex[14], *_tex[15], u); + pretex.horiz1[i] = Bernstein3D(*_tex[0], *_tex[1], *_tex[2], *_tex[3], weights); + pretex.horiz2[i] = Bernstein3D(*_tex[4], *_tex[5], *_tex[6], *_tex[7], weights); + pretex.horiz3[i] = Bernstein3D(*_tex[8], *_tex[9], *_tex[10], *_tex[11], weights); + pretex.horiz4[i] = Bernstein3D(*_tex[12], *_tex[13], *_tex[14], *_tex[15], weights); } if (computeNormals) { - prederivU.horiz1[i] = Bernstein3DDerivative(*_pos[0], *_pos[1], *_pos[2], *_pos[3], u); - prederivU.horiz2[i] = Bernstein3DDerivative(*_pos[4], *_pos[5], *_pos[6], *_pos[7], u); - prederivU.horiz3[i] = Bernstein3DDerivative(*_pos[8], *_pos[9], *_pos[10], *_pos[11], u); - prederivU.horiz4[i] = Bernstein3DDerivative(*_pos[12], *_pos[13], *_pos[14], *_pos[15], u); + Bernstein3DDerivative(u, derivs); + prederivU.horiz1[i] = Bernstein3D(*_pos[0], *_pos[1], *_pos[2], *_pos[3], derivs); + prederivU.horiz2[i] = Bernstein3D(*_pos[4], *_pos[5], *_pos[6], *_pos[7], derivs); + prederivU.horiz3[i] = Bernstein3D(*_pos[8], *_pos[9], *_pos[10], *_pos[11], derivs); + prederivU.horiz4[i] = Bernstein3D(*_pos[12], *_pos[13], *_pos[14], *_pos[15], derivs); } } @@ -516,13 +516,14 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te for (int tile_u = 0; tile_u < tess_u + 1; ++tile_u) { float u = ((float)tile_u / (float)tess_u); float v = ((float)tile_v / (float)tess_v); - float bv = v; SimpleVertex &vert = vertices[tile_v * (tess_u + 1) + tile_u]; + Bernstein3DBasis(v, weights); if (computeNormals) { - const Vec3f derivU = prederivU.Bernstein3D(tile_u, bv); - const Vec3f derivV = prepos.Bernstein3DDerivative(tile_u, bv); + Bernstein3DDerivative(v, derivs); + const Vec3f derivU = prederivU.Bernstein3D(tile_u, weights); + const Vec3f derivV = prepos.Bernstein3D(tile_u, derivs); vert.nrm = Cross(derivU, derivV).Normalized(); if (patch.patchFacing) @@ -531,7 +532,7 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te vert.nrm.SetZero(); } - vert.pos = prepos.Bernstein3D(tile_u, bv); + vert.pos = prepos.Bernstein3D(tile_u, weights); if (!sampleTexcoords) { // Generate texcoord @@ -539,13 +540,13 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te vert.uv[1] = v + patch_u * third; } else { // Sample UV from control points - const Vec2f res = pretex.Bernstein3D(tile_u, bv); + const Vec2f res = pretex.Bernstein3D(tile_u, weights); vert.uv[0] = res.x; vert.uv[1] = res.y; } if (sampleColors) { - vert.color_32 = precol.Bernstein3D(tile_u, bv).ToRGBA(); + vert.color_32 = precol.Bernstein3D(tile_u, weights).ToRGBA(); } else { vert.color_32 = patch.defcolor; } From 2a3210ac057124b5f5185d817771b85f89665e3e Mon Sep 17 00:00:00 2001 From: xebra Date: Wed, 31 Jan 2018 20:18:47 +0900 Subject: [PATCH 022/347] [spline/bezier]Make a bezier weights calculation class and precalculate all bezier weights at the beginning. --- GPU/Common/SplineCommon.cpp | 104 +++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 42 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 74a211de07..4bc4256f5e 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -60,20 +60,36 @@ static void BuildIndex(u16 *indices, int &count, int num_u, int num_v, GEPatchPr } } -// Bernstein basis functions -void Bernstein3DBasis(float x, float weights[4]) { - weights[0] = (1 - x) * (1 - x) * (1 - x); - weights[1] = 3 * x * (1 - x) * (1 - x); - weights[2] = 3 * x * x * (1 - x); - weights[3] = x * x * x; -} +struct Weight { + float weights[4], derivs[4]; +}; -void Bernstein3DDerivative(float x, float derivs[4]) { - derivs[0] = -3 * (x - 1) * (x - 1); - derivs[1] = 9 * x * x - 12 * x + 3; - derivs[2] = 3 * (2 - 3 * x) * x; - derivs[3] = 3 * x * x; -} +class Bezier3DWeight { +private: + void CalcWeights(float t, Weight &w) { + // Bernstein 3D basis polynomial + w.weights[0] = (1 - t) * (1 - t) * (1 - t); + w.weights[1] = 3 * t * (1 - t) * (1 - t); + w.weights[2] = 3 * t * t * (1 - t); + w.weights[3] = t * t * t; + + // Derivative + w.derivs[0] = -3 * (1 - t) * (1 - t); + w.derivs[1] = 9 * t * t - 12 * t + 3; + w.derivs[2] = 3 * (2 - 3 * t) * t; + w.derivs[3] = 3 * t * t; + } +public: + Weight *CalcWeightsAll(int tess) { + Weight *weights = new Weight[tess + 1]; + const float inv_u = 1.0f / (float)tess; + for (int i = 0; i < tess + 1; ++i) { + const float t = (float)i * inv_u; + CalcWeights(t, weights[i]); + } + return weights; + } +}; // http://en.wikipedia.org/wiki/Bernstein_polynomial template @@ -467,6 +483,14 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te const bool sampleColors = (origVertType & GE_VTYPE_COL_MASK) != 0; const bool sampleTexcoords = (origVertType & GE_VTYPE_TC_MASK) != 0; + Bezier3DWeight bezierWeight; + Weight *weights_u, *weights_v; + weights_u = bezierWeight.CalcWeightsAll(tess_u); + if (tess_u == tess_v) + weights_v = weights_u; // Use same weights + else + weights_v = bezierWeight.CalcWeightsAll(tess_u); + int num_patches_u = (patch.count_u - 1) / 3; int num_patches_v = (patch.count_v - 1) / 3; for (int patch_u = 0; patch_u < num_patches_u; ++patch_u) { @@ -481,49 +505,43 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te _col[point] = &patch.col[idx]; _tex[point] = &patch.tex[idx]; } - float weights[4], derivs[4]; for (int i = 0; i < tess_u + 1; i++) { - float u = ((float)i / (float)tess_u); - Bernstein3DBasis(u, weights); - prepos.horiz1[i] = Bernstein3D(*_pos[0], *_pos[1], *_pos[2], *_pos[3], weights); - prepos.horiz2[i] = Bernstein3D(*_pos[4], *_pos[5], *_pos[6], *_pos[7], weights); - prepos.horiz3[i] = Bernstein3D(*_pos[8], *_pos[9], *_pos[10], *_pos[11], weights); - prepos.horiz4[i] = Bernstein3D(*_pos[12], *_pos[13], *_pos[14], *_pos[15], weights); + Weight &wu = weights_u[i]; + prepos.horiz1[i] = Bernstein3D(*_pos[0], *_pos[1], *_pos[2], *_pos[3], wu.weights); + prepos.horiz2[i] = Bernstein3D(*_pos[4], *_pos[5], *_pos[6], *_pos[7], wu.weights); + prepos.horiz3[i] = Bernstein3D(*_pos[8], *_pos[9], *_pos[10], *_pos[11], wu.weights); + prepos.horiz4[i] = Bernstein3D(*_pos[12], *_pos[13], *_pos[14], *_pos[15], wu.weights); if (sampleColors) { - precol.horiz1[i] = Bernstein3D(*_col[0], *_col[1], *_col[2], *_col[3], weights); - precol.horiz2[i] = Bernstein3D(*_col[4], *_col[5], *_col[6], *_col[7], weights); - precol.horiz3[i] = Bernstein3D(*_col[8], *_col[9], *_col[10], *_col[11], weights); - precol.horiz4[i] = Bernstein3D(*_col[12], *_col[13], *_col[14], *_col[15], weights); + precol.horiz1[i] = Bernstein3D(*_col[0], *_col[1], *_col[2], *_col[3], wu.weights); + precol.horiz2[i] = Bernstein3D(*_col[4], *_col[5], *_col[6], *_col[7], wu.weights); + precol.horiz3[i] = Bernstein3D(*_col[8], *_col[9], *_col[10], *_col[11], wu.weights); + precol.horiz4[i] = Bernstein3D(*_col[12], *_col[13], *_col[14], *_col[15], wu.weights); } if (sampleTexcoords) { - pretex.horiz1[i] = Bernstein3D(*_tex[0], *_tex[1], *_tex[2], *_tex[3], weights); - pretex.horiz2[i] = Bernstein3D(*_tex[4], *_tex[5], *_tex[6], *_tex[7], weights); - pretex.horiz3[i] = Bernstein3D(*_tex[8], *_tex[9], *_tex[10], *_tex[11], weights); - pretex.horiz4[i] = Bernstein3D(*_tex[12], *_tex[13], *_tex[14], *_tex[15], weights); + pretex.horiz1[i] = Bernstein3D(*_tex[0], *_tex[1], *_tex[2], *_tex[3], wu.weights); + pretex.horiz2[i] = Bernstein3D(*_tex[4], *_tex[5], *_tex[6], *_tex[7], wu.weights); + pretex.horiz3[i] = Bernstein3D(*_tex[8], *_tex[9], *_tex[10], *_tex[11], wu.weights); + pretex.horiz4[i] = Bernstein3D(*_tex[12], *_tex[13], *_tex[14], *_tex[15], wu.weights); } if (computeNormals) { - Bernstein3DDerivative(u, derivs); - prederivU.horiz1[i] = Bernstein3D(*_pos[0], *_pos[1], *_pos[2], *_pos[3], derivs); - prederivU.horiz2[i] = Bernstein3D(*_pos[4], *_pos[5], *_pos[6], *_pos[7], derivs); - prederivU.horiz3[i] = Bernstein3D(*_pos[8], *_pos[9], *_pos[10], *_pos[11], derivs); - prederivU.horiz4[i] = Bernstein3D(*_pos[12], *_pos[13], *_pos[14], *_pos[15], derivs); + prederivU.horiz1[i] = Bernstein3D(*_pos[0], *_pos[1], *_pos[2], *_pos[3], wu.derivs); + prederivU.horiz2[i] = Bernstein3D(*_pos[4], *_pos[5], *_pos[6], *_pos[7], wu.derivs); + prederivU.horiz3[i] = Bernstein3D(*_pos[8], *_pos[9], *_pos[10], *_pos[11], wu.derivs); + prederivU.horiz4[i] = Bernstein3D(*_pos[12], *_pos[13], *_pos[14], *_pos[15], wu.derivs); } } for (int tile_v = 0; tile_v < tess_v + 1; ++tile_v) { for (int tile_u = 0; tile_u < tess_u + 1; ++tile_u) { - float u = ((float)tile_u / (float)tess_u); - float v = ((float)tile_v / (float)tess_v); SimpleVertex &vert = vertices[tile_v * (tess_u + 1) + tile_u]; - Bernstein3DBasis(v, weights); + Weight &wv = weights_v[tile_v]; if (computeNormals) { - Bernstein3DDerivative(v, derivs); - const Vec3f derivU = prederivU.Bernstein3D(tile_u, weights); - const Vec3f derivV = prepos.Bernstein3D(tile_u, derivs); + const Vec3f derivU = prederivU.Bernstein3D(tile_u, wv.weights); + const Vec3f derivV = prepos.Bernstein3D(tile_u, wv.derivs); vert.nrm = Cross(derivU, derivV).Normalized(); if (patch.patchFacing) @@ -532,21 +550,23 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te vert.nrm.SetZero(); } - vert.pos = prepos.Bernstein3D(tile_u, weights); + vert.pos = prepos.Bernstein3D(tile_u, wv.weights); if (!sampleTexcoords) { + float u = ((float)tile_u / (float)tess_u); + float v = ((float)tile_v / (float)tess_v); // Generate texcoord vert.uv[0] = u + patch_u * third; vert.uv[1] = v + patch_u * third; } else { // Sample UV from control points - const Vec2f res = pretex.Bernstein3D(tile_u, weights); + const Vec2f res = pretex.Bernstein3D(tile_u, wv.weights); vert.uv[0] = res.x; vert.uv[1] = res.y; } if (sampleColors) { - vert.color_32 = precol.Bernstein3D(tile_u, weights).ToRGBA(); + vert.color_32 = precol.Bernstein3D(tile_u, wv.weights).ToRGBA(); } else { vert.color_32 = patch.defcolor; } From 1b9af84270101f6b1243fea3aff57fc8765aaac3 Mon Sep 17 00:00:00 2001 From: xebra Date: Wed, 31 Jan 2018 20:24:00 +0900 Subject: [PATCH 023/347] [spline/bezier]minor fix --- GPU/Common/SplineCommon.cpp | 60 ++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 4bc4256f5e..4ce467430b 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -109,9 +109,7 @@ struct KnotDiv { float _3_2 = 1.0f; // Always 1 }; -static void spline_n_4(int i, float t, float *knot, const KnotDiv &div, float *splineVal, float *derivs) { - knot += i; - +static void spline_n_4(float t, float *knot, const KnotDiv &div, float *splineVal, float *derivs) { #ifdef _M_SSE const __m128 knot012 = _mm_loadu_ps(knot); const __m128 t012 = _mm_sub_ps(_mm_set_ps1(t), knot012); @@ -177,34 +175,34 @@ static void spline_n_4(int i, float t, float *knot, const KnotDiv &div, float *s // knot should be an array sized n + 5 (n + 1 + 1 + degree (cubic)) static void spline_knot(int n, int type, float *knots, KnotDiv *divs) { - // Basic theory (-2 to +3), optimized with KnotDiv (-2 to +0) - // for (int i = 0; i < n + 5; ++i) { - for (int i = 0; i < n + 2; ++i) { - knots[i] = (float)i - 2; - } + // Basic theory (-2 to +3), optimized with KnotDiv (-2 to +0) +// for (int i = 0; i < n + 5; ++i) { + for (int i = 0; i < n + 2; ++i) { + knots[i] = (float)i - 2; + } - // The first edge is open - if ((type & 1) != 0) { - knots[0] = 0; - knots[1] = 0; + // The first edge is open + if ((type & 1) != 0) { + knots[0] = 0; + knots[1] = 0; - divs[0]._3_0 = 1.0f; - divs[0]._4_1 = 1.0f / 2.0f; - divs[0]._3_1 = 1.0f; - if (n > 1) - divs[1]._3_0 = 1.0f / 2.0f; - } - // The last edge is open - if ((type & 2) != 0) { - // knots[n + 2] = (float)n; // Got rid of this line optimized with KnotDiv - // knots[n + 3] = (float)n; // Got rid of this line optimized with KnotDiv - // knots[n + 4] = (float)n; // Got rid of this line optimized with KnotDiv - divs[n - 1]._4_1 = 1.0f / 2.0f; - divs[n - 1]._5_2 = 1.0f; - divs[n - 1]._4_2 = 1.0f; - if (n > 1) - divs[n - 2]._5_2 = 1.0f / 2.0f; - } + divs[0]._3_0 = 1.0f; + divs[0]._4_1 = 1.0f / 2.0f; + divs[0]._3_1 = 1.0f; + if (n > 1) + divs[1]._3_0 = 1.0f / 2.0f; + } + // The last edge is open + if ((type & 2) != 0) { + // knots[n + 2] = (float)n; // Got rid of this line optimized with KnotDiv + // knots[n + 3] = (float)n; // Got rid of this line optimized with KnotDiv + // knots[n + 4] = (float)n; // Got rid of this line optimized with KnotDiv + divs[n - 1]._4_1 = 1.0f / 2.0f; + divs[n - 1]._5_2 = 1.0f; + divs[n - 1]._4_2 = 1.0f; + if (n > 1) + divs[n - 2]._5_2 = 1.0f / 2.0f; + } } bool CanUseHardwareTessellation(GEPatchPrimType prim) { @@ -335,8 +333,8 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp 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, divs_u[iu], u_weights, u_derivs); - spline_n_4(iv, v, knot_v, divs_v[iv], v_weights, v_derivs); + spline_n_4(u, knot_u + iu, divs_u[iu], u_weights, u_derivs); + spline_n_4(v, knot_v + iv, divs_v[iv], v_weights, v_derivs); // Handle degenerate patches. without this, spatch.points[] may read outside the number of initialized points. int patch_w = std::min(spatch.count_u - iu, 4); From 0c9680446ebfd48ffce5038ba8b4bb7bb518366a Mon Sep 17 00:00:00 2001 From: xebra Date: Wed, 31 Jan 2018 20:25:07 +0900 Subject: [PATCH 024/347] [spline/bezier]minor fix --- GPU/Common/SplineCommon.cpp | 64 ++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 4ce467430b..91219e759e 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -109,6 +109,38 @@ struct KnotDiv { float _3_2 = 1.0f; // Always 1 }; +// knot should be an array sized n + 5 (n + 1 + 1 + degree (cubic)) +static void spline_knot(int n, int type, float *knots, KnotDiv *divs) { + // Basic theory (-2 to +3), optimized with KnotDiv (-2 to +0) +// for (int i = 0; i < n + 5; ++i) { + for (int i = 0; i < n + 2; ++i) { + knots[i] = (float)i - 2; + } + + // The first edge is open + if ((type & 1) != 0) { + knots[0] = 0; + knots[1] = 0; + + divs[0]._3_0 = 1.0f; + divs[0]._4_1 = 1.0f / 2.0f; + divs[0]._3_1 = 1.0f; + if (n > 1) + divs[1]._3_0 = 1.0f / 2.0f; + } + // The last edge is open + if ((type & 2) != 0) { + // knots[n + 2] = (float)n; // Got rid of this line optimized with KnotDiv + // knots[n + 3] = (float)n; // Got rid of this line optimized with KnotDiv + // knots[n + 4] = (float)n; // Got rid of this line optimized with KnotDiv + divs[n - 1]._4_1 = 1.0f / 2.0f; + divs[n - 1]._5_2 = 1.0f; + divs[n - 1]._4_2 = 1.0f; + if (n > 1) + divs[n - 2]._5_2 = 1.0f / 2.0f; + } +} + static void spline_n_4(float t, float *knot, const KnotDiv &div, float *splineVal, float *derivs) { #ifdef _M_SSE const __m128 knot012 = _mm_loadu_ps(knot); @@ -173,38 +205,6 @@ static void spline_n_4(float t, float *knot, const KnotDiv &div, float *splineVa derivs[3] = 3 * (f352 - 0); } -// knot should be an array sized n + 5 (n + 1 + 1 + degree (cubic)) -static void spline_knot(int n, int type, float *knots, KnotDiv *divs) { - // Basic theory (-2 to +3), optimized with KnotDiv (-2 to +0) -// for (int i = 0; i < n + 5; ++i) { - for (int i = 0; i < n + 2; ++i) { - knots[i] = (float)i - 2; - } - - // The first edge is open - if ((type & 1) != 0) { - knots[0] = 0; - knots[1] = 0; - - divs[0]._3_0 = 1.0f; - divs[0]._4_1 = 1.0f / 2.0f; - divs[0]._3_1 = 1.0f; - if (n > 1) - divs[1]._3_0 = 1.0f / 2.0f; - } - // The last edge is open - if ((type & 2) != 0) { - // knots[n + 2] = (float)n; // Got rid of this line optimized with KnotDiv - // knots[n + 3] = (float)n; // Got rid of this line optimized with KnotDiv - // knots[n + 4] = (float)n; // Got rid of this line optimized with KnotDiv - divs[n - 1]._4_1 = 1.0f / 2.0f; - divs[n - 1]._5_2 = 1.0f; - divs[n - 1]._4_2 = 1.0f; - if (n > 1) - divs[n - 2]._5_2 = 1.0f / 2.0f; - } -} - bool CanUseHardwareTessellation(GEPatchPrimType prim) { if (g_Config.bHardwareTessellation && !g_Config.bSoftwareRendering) { return CanUseHardwareTransform(PatchPrimToPrim(prim)); From 15b409a6980dfe01b4a01c3b48207d7586f2fc97 Mon Sep 17 00:00:00 2001 From: xebra Date: Wed, 31 Jan 2018 20:59:41 +0900 Subject: [PATCH 025/347] [spline/bezier]Make a spline weights calculation class and precalculate all spline weights at the beginning. --- GPU/Common/SplineCommon.cpp | 244 +++++++++++++++++++----------------- 1 file changed, 130 insertions(+), 114 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 91219e759e..b3c97f5f5e 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -100,110 +100,137 @@ static T Bernstein3D(const T& p0, const T& p1, const T& p2, const T& p3, float w return p0 * w[0] + p1 * w[1] + p2 * w[2] + p3 * w[3]; } -struct KnotDiv { - float _3_0 = 1.0f / 3.0f; - float _4_1 = 1.0f / 3.0f; - float _5_2 = 1.0f / 3.0f; - float _3_1 = 1.0f / 2.0f; - float _4_2 = 1.0f / 2.0f; - float _3_2 = 1.0f; // Always 1 -}; +class Spline3DWeight { +private: + struct KnotDiv { + float _3_0 = 1.0f / 3.0f; + float _4_1 = 1.0f / 3.0f; + float _5_2 = 1.0f / 3.0f; + float _3_1 = 1.0f / 2.0f; + float _4_2 = 1.0f / 2.0f; + float _3_2 = 1.0f; // Always 1 + }; -// knot should be an array sized n + 5 (n + 1 + 1 + degree (cubic)) -static void spline_knot(int n, int type, float *knots, KnotDiv *divs) { - // Basic theory (-2 to +3), optimized with KnotDiv (-2 to +0) -// for (int i = 0; i < n + 5; ++i) { - for (int i = 0; i < n + 2; ++i) { - knots[i] = (float)i - 2; + // knot should be an array sized n + 5 (n + 1 + 1 + degree (cubic)) + void CalcKnots(int n, int type, float *knots, KnotDiv *divs) { + // Basic theory (-2 to +3), optimized with KnotDiv (-2 to +0) + // for (int i = 0; i < n + 5; ++i) { + for (int i = 0; i < n + 2; ++i) { + knots[i] = (float)i - 2; + } + + // The first edge is open + if ((type & 1) != 0) { + knots[0] = 0; + knots[1] = 0; + + divs[0]._3_0 = 1.0f; + divs[0]._4_1 = 1.0f / 2.0f; + divs[0]._3_1 = 1.0f; + if (n > 1) + divs[1]._3_0 = 1.0f / 2.0f; + } + // The last edge is open + if ((type & 2) != 0) { + // knots[n + 2] = (float)n; // Got rid of this line optimized with KnotDiv + // knots[n + 3] = (float)n; // Got rid of this line optimized with KnotDiv + // knots[n + 4] = (float)n; // Got rid of this line optimized with KnotDiv + divs[n - 1]._4_1 = 1.0f / 2.0f; + divs[n - 1]._5_2 = 1.0f; + divs[n - 1]._4_2 = 1.0f; + if (n > 1) + divs[n - 2]._5_2 = 1.0f / 2.0f; + } } - // The first edge is open - if ((type & 1) != 0) { - knots[0] = 0; - knots[1] = 0; - - divs[0]._3_0 = 1.0f; - divs[0]._4_1 = 1.0f / 2.0f; - divs[0]._3_1 = 1.0f; - if (n > 1) - divs[1]._3_0 = 1.0f / 2.0f; - } - // The last edge is open - if ((type & 2) != 0) { - // knots[n + 2] = (float)n; // Got rid of this line optimized with KnotDiv - // knots[n + 3] = (float)n; // Got rid of this line optimized with KnotDiv - // knots[n + 4] = (float)n; // Got rid of this line optimized with KnotDiv - divs[n - 1]._4_1 = 1.0f / 2.0f; - divs[n - 1]._5_2 = 1.0f; - divs[n - 1]._4_2 = 1.0f; - if (n > 1) - divs[n - 2]._5_2 = 1.0f / 2.0f; - } -} - -static void spline_n_4(float t, float *knot, const KnotDiv &div, float *splineVal, float *derivs) { + void CalcWeights(float t, const float *knots, const KnotDiv &div, Weight &w) { #ifdef _M_SSE - const __m128 knot012 = _mm_loadu_ps(knot); - const __m128 t012 = _mm_sub_ps(_mm_set_ps1(t), knot012); - const __m128 f30_41_52 = _mm_mul_ps(t012, _mm_loadu_ps(&div._3_0)); - const __m128 f52_31_42 = _mm_mul_ps(t012, _mm_loadu_ps(&div._5_2)); - const float &f32 = t012.m128_f32[2]; + const __m128 knot012 = _mm_loadu_ps(knots); + const __m128 t012 = _mm_sub_ps(_mm_set_ps1(t), knot012); + const __m128 f30_41_52 = _mm_mul_ps(t012, _mm_loadu_ps(&div._3_0)); + const __m128 f52_31_42 = _mm_mul_ps(t012, _mm_loadu_ps(&div._5_2)); + const float &f32 = t012.m128_f32[2]; - // Following comments are for explains order of the multiply. -// float a = (1-f30)*(1-f31); -// float c = (1-f41)*(1-f42); -// float b = ( f31 * f41); -// float d = ( f42 * f52); - const __m128 f30_41_31_42 = _mm_shuffle_ps(f30_41_52, f52_31_42, _MM_SHUFFLE(2, 1, 1, 0)); - const __m128 f31_42_41_52 = _mm_shuffle_ps(f52_31_42, f30_41_52, _MM_SHUFFLE(2, 1, 2, 1)); - const __m128 c1_1_0_0 = { 1, 1, 0, 0 }; - const __m128 acbd = _mm_mul_ps(_mm_sub_ps(c1_1_0_0, f30_41_31_42), _mm_sub_ps(c1_1_0_0, f31_42_41_52)); - const float &a = acbd.m128_f32[0]; - const float &b = acbd.m128_f32[2]; - const float &c = acbd.m128_f32[1]; - const float &d = acbd.m128_f32[3]; + // Following comments are for explains order of the multiply. + // float a = (1-f30)*(1-f31); + // float c = (1-f41)*(1-f42); + // float b = ( f31 * f41); + // float d = ( f42 * f52); + const __m128 f30_41_31_42 = _mm_shuffle_ps(f30_41_52, f52_31_42, _MM_SHUFFLE(2, 1, 1, 0)); + const __m128 f31_42_41_52 = _mm_shuffle_ps(f52_31_42, f30_41_52, _MM_SHUFFLE(2, 1, 2, 1)); + const __m128 c1_1_0_0 = { 1, 1, 0, 0 }; + const __m128 acbd = _mm_mul_ps(_mm_sub_ps(c1_1_0_0, f30_41_31_42), _mm_sub_ps(c1_1_0_0, f31_42_41_52)); + const float &a = acbd.m128_f32[0]; + const float &b = acbd.m128_f32[2]; + const float &c = acbd.m128_f32[1]; + const float &d = acbd.m128_f32[3]; - // For derivative - const float &f31 = f30_41_31_42.m128_f32[2]; - const float &f42 = f30_41_31_42.m128_f32[3]; + // For derivative + const float &f31 = f30_41_31_42.m128_f32[2]; + const float &f42 = f30_41_31_42.m128_f32[3]; #else - // TODO: Maybe compilers could be coaxed into vectorizing this code without the above explicitly... - float t0 = (t - knot[0]); - float t1 = (t - knot[1]); - float t2 = (t - knot[2]); + // TODO: Maybe compilers could be coaxed into vectorizing this code without the above explicitly... + float t0 = (t - knots[0]); + float t1 = (t - knots[1]); + float t2 = (t - knots[2]); - float f30 = t0 * div._3_0; - float f41 = t1 * div._4_1; - float f52 = t2 * div._5_2; - float f31 = t1 * div._3_1; - float f42 = t2 * div._4_2; - float f32 = t2 * div._3_2; + float f30 = t0 * div._3_0; + float f41 = t1 * div._4_1; + float f52 = t2 * div._5_2; + float f31 = t1 * div._3_1; + float f42 = t2 * div._4_2; + float f32 = t2 * div._3_2; - float a = (1-f30)*(1-f31); - float b = (f31*f41); - float c = (1-f41)*(1-f42); - float d = (f42*f52); + float a = (1 - f30) * (1 - f31); + float b = (f31 * f41); + float c = (1 - f41) * (1 - f42); + float d = (f42 * f52); #endif + w.weights[0] = a * (1 - f32); // (1-f30)*(1-f31)*(1-f32) + w.weights[1] = 1 - a - b + ((a + b + c - 1) * f32); + w.weights[2] = b + ((1 - b - c - d) * f32); + w.weights[3] = d * f32; // f32*f42*f52 - splineVal[0] = a-(a*f32); - splineVal[1] = 1-a-b+((a+b+c-1)*f32); - splineVal[2] = b+((1-b-c-d)*f32); - splineVal[3] = d*f32; + // Derivative + float i1 = (1 - f31) * (1 - f32); + float i2 = f31 * (1 - f32) + (1 - f42) * f32; + float i3 = f42 * f32; - // Derivative - float i1 = (1 - f31) * (1 - f32); - float i2 = f31 * (1 - f32) + (1 - f42) * f32; - float i3 = f42 * f32; + float f130 = i1 * div._3_0; + float f241 = i2 * div._4_1; + float f352 = i3 * div._5_2; - float f130 = i1 * div._3_0; - float f241 = i2 * div._4_1; - float f352 = i3 * div._5_2; + w.derivs[0] = 3 * (0 - f130); + w.derivs[1] = 3 * (f130 - f241); + w.derivs[2] = 3 * (f241 - f352); + w.derivs[3] = 3 * (f352 - 0); + } +public: + Weight *CalcWeightsAll(int count, int tess, int type) { + const int num_patches = count - 3; + Weight *weights = new Weight[tess * num_patches + 1]; - derivs[0] = 3 * (0 - f130); - derivs[1] = 3 * (f130 - f241); - derivs[2] = 3 * (f241 - f352); - derivs[3] = 3 * (f352 - 0); -} + // float *knots = new float[num_patches + 5]; + float *knots = new float[num_patches + 2]; // Optimized with KnotDiv, must use +5 in theory + KnotDiv *divs = new KnotDiv[num_patches]; + CalcKnots(num_patches, type, knots, divs); + + 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 index = i * tess + j; + const float t = (float)index * inv_tess; + CalcWeights(t, knots + i, divs[i], weights[index]); + } + } + + delete[] knots; + delete[] divs; + + return weights; + } +}; bool CanUseHardwareTessellation(GEPatchPrimType prim) { if (g_Config.bHardwareTessellation && !g_Config.bSoftwareRendering) { @@ -241,12 +268,13 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp // Full (mostly) correct tessellation of spline patches. // Not very fast. - float *knot_u = new float[spatch.count_u + 4]; - float *knot_v = new float[spatch.count_v + 4]; - KnotDiv *divs_u = new KnotDiv[spatch.count_u - 3]; - KnotDiv *divs_v = new KnotDiv[spatch.count_v - 3]; - spline_knot(spatch.count_u - 3, spatch.type_u, knot_u, divs_u); - spline_knot(spatch.count_v - 3, spatch.type_v, knot_v, divs_v); + Spline3DWeight splineWeight; + Weight *weights_u, *weights_v; + weights_u = splineWeight.CalcWeightsAll(spatch.count_u, spatch.tess_u, spatch.type_u); + if (spatch.count_u == spatch.count_v && spatch.tess_u == spatch.tess_v && spatch.type_u == spatch.type_v) + weights_v = weights_u; // Use same weights + else + weights_v = splineWeight.CalcWeightsAll(spatch.count_v, spatch.tess_v, spatch.type_v); // Increase tessellation based on the size. Should be approximately right? int patch_div_s = (spatch.count_u - 3) * spatch.tess_u; @@ -318,13 +346,6 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp 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]; - float u_derivs[4]; - float v_derivs[4]; - int iu = (int)u; int iv = (int)v; @@ -333,8 +354,8 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp 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(u, knot_u + iu, divs_u[iu], u_weights, u_derivs); - spline_n_4(v, knot_v + iv, divs_v[iv], v_weights, v_derivs); + const Weight &wu = weights_u[tile_u]; + const Weight &wv = weights_v[tile_v]; // Handle degenerate patches. without this, spatch.points[] may read outside the number of initialized points. int patch_w = std::min(spatch.count_u - iu, 4); @@ -342,8 +363,8 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp for (int ii = 0; ii < patch_w; ++ii) { for (int jj = 0; jj < patch_h; ++jj) { - float u_spline = u_weights[ii]; - float v_spline = v_weights[jj]; + float u_spline = wu.weights[ii]; + float v_spline = wv.weights[jj]; float f = u_spline * v_spline; if (f > 0.0f) { @@ -363,8 +384,8 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp vert_color += spatch.col[idx] * f; } if (origNrm) { - du += spatch.pos[idx] * (u_derivs[ii] * v_weights[jj]); - dv += spatch.pos[idx] * (u_weights[ii] * v_derivs[jj]); + du += spatch.pos[idx] * (wu.derivs[ii] * wv.weights[jj]); + dv += spatch.pos[idx] * (wu.weights[ii] * wv.derivs[jj]); } } } @@ -385,11 +406,6 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp } } - delete[] knot_u; - delete[] knot_v; - delete[] divs_u; - delete[] divs_v; - BuildIndex(indices, count, patch_div_s, patch_div_t, spatch.primType); } From 1e84a62e96ea485170417d8cd975313e3bf4e9d1 Mon Sep 17 00:00:00 2001 From: xebra Date: Wed, 31 Jan 2018 21:42:39 +0900 Subject: [PATCH 026/347] [spline/bezier]Implement weights cache system. --- GPU/Common/DrawEngineCommon.cpp | 1 + GPU/Common/DrawEngineCommon.h | 1 + GPU/Common/SplineCommon.cpp | 82 ++++++++++++++++++++++++--------- 3 files changed, 62 insertions(+), 22 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 966aedd6e1..abee27048b 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -48,6 +48,7 @@ DrawEngineCommon::~DrawEngineCommon() { decoderMap_.Iterate([&](const uint32_t vtype, VertexDecoder *decoder) { delete decoder; }); + ClearSplineBezierWeights(); } VertexDecoder *DrawEngineCommon::GetVertexDecoder(u32 vtype) { diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index aa5531d011..39c8647ce4 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -77,6 +77,7 @@ public: void SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, int cullMode, int *bytesRead); void SubmitSpline(const void *control_points, const void *indices, int tess_u, int tess_v, int count_u, int count_v, int type_u, int type_v, GEPatchPrimType prim_type, bool computeNormals, bool patchFacing, u32 vertType, int *bytesRead); void SubmitBezier(const void *control_points, const void *indices, int tess_u, int tess_v, int count_u, int count_v, GEPatchPrimType prim_type, bool computeNormals, bool patchFacing, u32 vertType, int *bytesRead); + void ClearSplineBezierWeights(); std::vector DebugGetVertexLoaderIDs(); std::string DebugGetVertexLoaderString(std::string id, DebugShaderStringType stringType); diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index b3c97f5f5e..fce216a19e 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -80,7 +80,8 @@ private: w.derivs[3] = 3 * t * t; } public: - Weight *CalcWeightsAll(int tess) { + Weight *CalcWeightsAll(u32 key) { + int tess = (int)key; Weight *weights = new Weight[tess + 1]; const float inv_u = 1.0f / (float)tess; for (int i = 0; i < tess + 1; ++i) { @@ -93,7 +94,7 @@ public: // http://en.wikipedia.org/wiki/Bernstein_polynomial template -static T Bernstein3D(const T& p0, const T& p1, const T& p2, const T& p3, float w[4]) { +static T Bernstein3D(const T& p0, const T& p1, const T& p2, const T& p3, const float w[4]) { if (w[0] == 1) return p0; if (w[3] == 1) return p3; // Linear combination @@ -206,7 +207,9 @@ private: w.derivs[3] = 3 * (f352 - 0); } public: - Weight *CalcWeightsAll(int count, int tess, int type) { + Weight *CalcWeightsAll(u32 key) { + int tess, count, type; + FromKey(key, tess, count, type); const int num_patches = count - 3; Weight *weights = new Weight[tess * num_patches + 1]; @@ -230,8 +233,53 @@ public: return weights; } + + u32 ToKey(int tess, int count, int type) { + return tess | (count << 8) | (type << 16); + } + + void FromKey(u32 key, int &tess, int &count, int &type) { + tess = key & 0xFF; count = (key >> 8) & 0xFF; type = (key >> 16) & 0xFF; + } }; +template +class WeightCache : public T { +private: + std::unordered_map weightsCache; +public: + Weight* operator [] (u32 key) { + Weight *&weights = weightsCache[key]; + if (!weights) + weights = CalcWeightsAll(key); + return weights; + } + + void Clear() { + for (auto it : weightsCache) + delete[] it.second; + weightsCache.clear(); + } +}; + +static WeightCache bezierWeightsCache; +static WeightCache splineWeightsCache; + +struct Weight2D { + const Weight *u, *v; + + template + Weight2D(WeightCache &cache, u32 key_u, u32 key_v) { + u = cache[key_u]; + v = (key_u != key_v) ? cache[key_v] : u; // Use same weights if u == v + } +}; + +void DrawEngineCommon::ClearSplineBezierWeights() { + bezierWeightsCache.Clear(); + splineWeightsCache.Clear(); +} + bool CanUseHardwareTessellation(GEPatchPrimType prim) { if (g_Config.bHardwareTessellation && !g_Config.bSoftwareRendering) { return CanUseHardwareTransform(PatchPrimToPrim(prim)); @@ -268,13 +316,9 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp // Full (mostly) correct tessellation of spline patches. // Not very fast. - Spline3DWeight splineWeight; - Weight *weights_u, *weights_v; - weights_u = splineWeight.CalcWeightsAll(spatch.count_u, spatch.tess_u, spatch.type_u); - if (spatch.count_u == spatch.count_v && spatch.tess_u == spatch.tess_v && spatch.type_u == spatch.type_v) - weights_v = weights_u; // Use same weights - else - weights_v = splineWeight.CalcWeightsAll(spatch.count_v, spatch.tess_v, spatch.type_v); + u32 key_u = splineWeightsCache.ToKey(spatch.tess_u, spatch.count_u, spatch.type_u); + u32 key_v = splineWeightsCache.ToKey(spatch.tess_v, spatch.count_v, spatch.type_v); + Weight2D weights(splineWeightsCache, key_u, key_v); // Increase tessellation based on the size. Should be approximately right? int patch_div_s = (spatch.count_u - 3) * spatch.tess_u; @@ -354,8 +398,8 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp if (iu >= spatch.count_u - 3) iu = spatch.count_u - 4; if (iv >= spatch.count_v - 3) iv = spatch.count_v - 4; - const Weight &wu = weights_u[tile_u]; - const Weight &wv = weights_v[tile_v]; + const Weight &wu = weights.u[tile_u]; + const Weight &wv = weights.v[tile_v]; // Handle degenerate patches. without this, spatch.points[] may read outside the number of initialized points. int patch_w = std::min(spatch.count_u - iu, 4); @@ -472,7 +516,7 @@ struct PrecomputedCurves { FreeAlignedMemory(horiz1); } - T Bernstein3D(int u, float w[4]) { + T Bernstein3D(int u, const float w[4]) { return ::Bernstein3D(horiz1[u], horiz2[u], horiz3[u], horiz4[u], w); } @@ -497,13 +541,7 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te const bool sampleColors = (origVertType & GE_VTYPE_COL_MASK) != 0; const bool sampleTexcoords = (origVertType & GE_VTYPE_TC_MASK) != 0; - Bezier3DWeight bezierWeight; - Weight *weights_u, *weights_v; - weights_u = bezierWeight.CalcWeightsAll(tess_u); - if (tess_u == tess_v) - weights_v = weights_u; // Use same weights - else - weights_v = bezierWeight.CalcWeightsAll(tess_u); + Weight2D weights(bezierWeightsCache, tess_u, tess_v); int num_patches_u = (patch.count_u - 1) / 3; int num_patches_v = (patch.count_v - 1) / 3; @@ -520,7 +558,7 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te _tex[point] = &patch.tex[idx]; } for (int i = 0; i < tess_u + 1; i++) { - Weight &wu = weights_u[i]; + const Weight &wu = weights.u[i]; prepos.horiz1[i] = Bernstein3D(*_pos[0], *_pos[1], *_pos[2], *_pos[3], wu.weights); prepos.horiz2[i] = Bernstein3D(*_pos[4], *_pos[5], *_pos[6], *_pos[7], wu.weights); prepos.horiz3[i] = Bernstein3D(*_pos[8], *_pos[9], *_pos[10], *_pos[11], wu.weights); @@ -552,7 +590,7 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te SimpleVertex &vert = vertices[tile_v * (tess_u + 1) + tile_u]; - Weight &wv = weights_v[tile_v]; + const Weight &wv = weights.v[tile_v]; if (computeNormals) { const Vec3f derivU = prederivU.Bernstein3D(tile_u, wv.weights); const Vec3f derivV = prepos.Bernstein3D(tile_u, wv.derivs); From 068cc37b2f27fabd76c1fd46c599c88b3455509c Mon Sep 17 00:00:00 2001 From: xebra Date: Thu, 1 Feb 2018 11:21:58 +0900 Subject: [PATCH 027/347] [spline/bezier]Improve bezier tessellator. --- GPU/Common/SplineCommon.cpp | 62 +++++++++++++++---------------------- 1 file changed, 25 insertions(+), 37 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index fce216a19e..1f0f7e7db9 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -94,11 +94,11 @@ public: // http://en.wikipedia.org/wiki/Bernstein_polynomial template -static T Bernstein3D(const T& p0, const T& p1, const T& p2, const T& p3, const float w[4]) { - if (w[0] == 1) return p0; - if (w[3] == 1) return p3; +static T Bernstein3D(const T *p, const float w[4]) { + if (w[0] == 1) return p[0]; + if (w[3] == 1) return p[3]; // Linear combination - return p0 * w[0] + p1 * w[1] + p2 * w[2] + p3 * w[3]; + return p[0] * w[0] + p[1] * w[1] + p[2] * w[2] + p[3] * w[3]; } class Spline3DWeight { @@ -507,23 +507,13 @@ void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, const SplinePatc template struct PrecomputedCurves { PrecomputedCurves(int count) { - horiz1 = (T *)AllocateAlignedMemory(count * 4 * sizeof(T), 16); - horiz2 = horiz1 + count * 1; - horiz3 = horiz1 + count * 2; - horiz4 = horiz1 + count * 3; - } - ~PrecomputedCurves() { - FreeAlignedMemory(horiz1); } T Bernstein3D(int u, const float w[4]) { - return ::Bernstein3D(horiz1[u], horiz2[u], horiz3[u], horiz4[u], w); + return ::Bernstein3D(horiz, w); } - T *horiz1; - T *horiz2; - T *horiz3; - T *horiz4; + T horiz[4]; }; static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType) { @@ -557,36 +547,34 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te _col[point] = &patch.col[idx]; _tex[point] = &patch.tex[idx]; } - for (int i = 0; i < tess_u + 1; i++) { - const Weight &wu = weights.u[i]; - prepos.horiz1[i] = Bernstein3D(*_pos[0], *_pos[1], *_pos[2], *_pos[3], wu.weights); - prepos.horiz2[i] = Bernstein3D(*_pos[4], *_pos[5], *_pos[6], *_pos[7], wu.weights); - prepos.horiz3[i] = Bernstein3D(*_pos[8], *_pos[9], *_pos[10], *_pos[11], wu.weights); - prepos.horiz4[i] = Bernstein3D(*_pos[12], *_pos[13], *_pos[14], *_pos[15], wu.weights); + for (int tile_u = 0; tile_u < tess_u + 1; ++tile_u) { + const Weight &wu = weights.u[tile_u]; + prepos.horiz[0] = Bernstein3D(_pos[0], wu.weights); + prepos.horiz[1] = Bernstein3D(_pos[4], wu.weights); + prepos.horiz[2] = Bernstein3D(_pos[8], wu.weights); + prepos.horiz[3] = Bernstein3D(_pos[12], wu.weights); if (sampleColors) { - precol.horiz1[i] = Bernstein3D(*_col[0], *_col[1], *_col[2], *_col[3], wu.weights); - precol.horiz2[i] = Bernstein3D(*_col[4], *_col[5], *_col[6], *_col[7], wu.weights); - precol.horiz3[i] = Bernstein3D(*_col[8], *_col[9], *_col[10], *_col[11], wu.weights); - precol.horiz4[i] = Bernstein3D(*_col[12], *_col[13], *_col[14], *_col[15], wu.weights); + precol.horiz[0] = Bernstein3D(_col[0], wu.weights); + precol.horiz[1] = Bernstein3D(_col[4], wu.weights); + precol.horiz[2] = Bernstein3D(_col[8], wu.weights); + precol.horiz[3] = Bernstein3D(_col[12], wu.weights); } if (sampleTexcoords) { - pretex.horiz1[i] = Bernstein3D(*_tex[0], *_tex[1], *_tex[2], *_tex[3], wu.weights); - pretex.horiz2[i] = Bernstein3D(*_tex[4], *_tex[5], *_tex[6], *_tex[7], wu.weights); - pretex.horiz3[i] = Bernstein3D(*_tex[8], *_tex[9], *_tex[10], *_tex[11], wu.weights); - pretex.horiz4[i] = Bernstein3D(*_tex[12], *_tex[13], *_tex[14], *_tex[15], wu.weights); + pretex.horiz[0] = Bernstein3D(_tex[0], wu.weights); + pretex.horiz[1] = Bernstein3D(_tex[4], wu.weights); + pretex.horiz[2] = Bernstein3D(_tex[8], wu.weights); + pretex.horiz[3] = Bernstein3D(_tex[12], wu.weights); } if (computeNormals) { - prederivU.horiz1[i] = Bernstein3D(*_pos[0], *_pos[1], *_pos[2], *_pos[3], wu.derivs); - prederivU.horiz2[i] = Bernstein3D(*_pos[4], *_pos[5], *_pos[6], *_pos[7], wu.derivs); - prederivU.horiz3[i] = Bernstein3D(*_pos[8], *_pos[9], *_pos[10], *_pos[11], wu.derivs); - prederivU.horiz4[i] = Bernstein3D(*_pos[12], *_pos[13], *_pos[14], *_pos[15], wu.derivs); + prederivU.horiz[0] = Bernstein3D(_pos[0], wu.derivs); + prederivU.horiz[1] = Bernstein3D(_pos[4], wu.derivs); + prederivU.horiz[2] = Bernstein3D(_pos[8], wu.derivs); + prederivU.horiz[3] = Bernstein3D(_pos[12], wu.derivs); } - } - for (int tile_v = 0; tile_v < tess_v + 1; ++tile_v) { - for (int tile_u = 0; tile_u < tess_u + 1; ++tile_u) { + for (int tile_v = 0; tile_v < tess_v + 1; ++tile_v) { SimpleVertex &vert = vertices[tile_v * (tess_u + 1) + tile_u]; From 4c6098d80123932fae0ab9af6e7a3a805d6b860c Mon Sep 17 00:00:00 2001 From: xebra Date: Thu, 1 Feb 2018 11:46:46 +0900 Subject: [PATCH 028/347] [spline/bezier]Improve bezier tessellator more. --- GPU/Common/SplineCommon.cpp | 70 ++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 1f0f7e7db9..f0133ff67f 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -92,15 +92,6 @@ public: } }; -// http://en.wikipedia.org/wiki/Bernstein_polynomial -template -static T Bernstein3D(const T *p, const float w[4]) { - if (w[0] == 1) return p[0]; - if (w[3] == 1) return p[3]; - // Linear combination - return p[0] * w[0] + p[1] * w[1] + p[2] * w[2] + p[3] * w[3]; -} - class Spline3DWeight { private: struct KnotDiv { @@ -509,8 +500,24 @@ struct PrecomputedCurves { PrecomputedCurves(int count) { } - T Bernstein3D(int u, const float w[4]) { - return ::Bernstein3D(horiz, w); + // http://en.wikipedia.org/wiki/Bernstein_polynomial + template + static T Bernstein3D(const T p[4], const float w[4]) { + if (w[0] == 1) return p[0]; + if (w[3] == 1) return p[3]; + // Linear combination + return p[0] * w[0] + p[1] * w[1] + p[2] * w[2] + p[3] * w[3]; + } + + void Bernstein3D_U(const T *const p[16], const float w[4]) { + horiz[0] = Bernstein3D(p[0], w); + horiz[1] = Bernstein3D(p[4], w); + horiz[2] = Bernstein3D(p[8], w); + horiz[3] = Bernstein3D(p[12], w); + } + + T Bernstein3D_V(const float w[4]) { + return Bernstein3D(horiz, w); } T horiz[4]; @@ -549,30 +556,13 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te } for (int tile_u = 0; tile_u < tess_u + 1; ++tile_u) { const Weight &wu = weights.u[tile_u]; - prepos.horiz[0] = Bernstein3D(_pos[0], wu.weights); - prepos.horiz[1] = Bernstein3D(_pos[4], wu.weights); - prepos.horiz[2] = Bernstein3D(_pos[8], wu.weights); - prepos.horiz[3] = Bernstein3D(_pos[12], wu.weights); - - if (sampleColors) { - precol.horiz[0] = Bernstein3D(_col[0], wu.weights); - precol.horiz[1] = Bernstein3D(_col[4], wu.weights); - precol.horiz[2] = Bernstein3D(_col[8], wu.weights); - precol.horiz[3] = Bernstein3D(_col[12], wu.weights); - } - if (sampleTexcoords) { - pretex.horiz[0] = Bernstein3D(_tex[0], wu.weights); - pretex.horiz[1] = Bernstein3D(_tex[4], wu.weights); - pretex.horiz[2] = Bernstein3D(_tex[8], wu.weights); - pretex.horiz[3] = Bernstein3D(_tex[12], wu.weights); - } - - if (computeNormals) { - prederivU.horiz[0] = Bernstein3D(_pos[0], wu.derivs); - prederivU.horiz[1] = Bernstein3D(_pos[4], wu.derivs); - prederivU.horiz[2] = Bernstein3D(_pos[8], wu.derivs); - prederivU.horiz[3] = Bernstein3D(_pos[12], wu.derivs); - } + prepos.Bernstein3D_U(_pos, wu.weights); + if (sampleColors) + precol.Bernstein3D_U(_col, wu.weights); + if (sampleTexcoords) + pretex.Bernstein3D_U(_tex, wu.weights); + if (computeNormals) + prederivU.Bernstein3D_U(_pos, wu.derivs); for (int tile_v = 0; tile_v < tess_v + 1; ++tile_v) { @@ -580,8 +570,8 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te const Weight &wv = weights.v[tile_v]; if (computeNormals) { - const Vec3f derivU = prederivU.Bernstein3D(tile_u, wv.weights); - const Vec3f derivV = prepos.Bernstein3D(tile_u, wv.derivs); + const Vec3f derivU = prederivU.Bernstein3D_V(wv.weights); + const Vec3f derivV = prepos.Bernstein3D_V(wv.derivs); vert.nrm = Cross(derivU, derivV).Normalized(); if (patch.patchFacing) @@ -590,7 +580,7 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te vert.nrm.SetZero(); } - vert.pos = prepos.Bernstein3D(tile_u, wv.weights); + vert.pos = prepos.Bernstein3D_V(wv.weights); if (!sampleTexcoords) { float u = ((float)tile_u / (float)tess_u); @@ -600,13 +590,13 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te vert.uv[1] = v + patch_u * third; } else { // Sample UV from control points - const Vec2f res = pretex.Bernstein3D(tile_u, wv.weights); + const Vec2f res = pretex.Bernstein3D_V(wv.weights); vert.uv[0] = res.x; vert.uv[1] = res.y; } if (sampleColors) { - vert.color_32 = precol.Bernstein3D(tile_u, wv.weights).ToRGBA(); + vert.color_32 = precol.Bernstein3D_V(wv.weights).ToRGBA(); } else { vert.color_32 = patch.defcolor; } From 30691535dc9f2daf17fd243e633e4b09797c4fc2 Mon Sep 17 00:00:00 2001 From: xebra Date: Thu, 1 Feb 2018 11:51:58 +0900 Subject: [PATCH 029/347] [spline/bezier]Fix bezier texcoord generation. --- GPU/Common/SplineCommon.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index f0133ff67f..083266ce31 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -524,7 +524,8 @@ struct PrecomputedCurves { }; static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType) { - const float third = 1.0f / 3.0f; + const float inv_u = 1.0f / (float)tess_u; + const float inv_v = 1.0f / (float)tess_v; // First compute all the vertices and put them in an array SimpleVertex *&vertices = (SimpleVertex*&)dest; @@ -583,16 +584,12 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te vert.pos = prepos.Bernstein3D_V(wv.weights); if (!sampleTexcoords) { - float u = ((float)tile_u / (float)tess_u); - float v = ((float)tile_v / (float)tess_v); // Generate texcoord - vert.uv[0] = u + patch_u * third; - vert.uv[1] = v + patch_u * third; + vert.uv[0] = patch_u + tile_u * inv_u; + vert.uv[1] = patch_v + tile_v * inv_v; } else { // Sample UV from control points - const Vec2f res = pretex.Bernstein3D_V(wv.weights); - vert.uv[0] = res.x; - vert.uv[1] = res.y; + pretex.Bernstein3D_V(wv.weights).Write(vert.uv); } if (sampleColors) { From f12d7966655f6545650b157a20a0855cb560a730 Mon Sep 17 00:00:00 2001 From: xebra Date: Thu, 1 Feb 2018 12:02:03 +0900 Subject: [PATCH 030/347] [spline/bezier]minor cleanup --- GPU/Common/SplineCommon.cpp | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 083266ce31..6241a08600 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -557,6 +557,7 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te } for (int tile_u = 0; tile_u < tess_u + 1; ++tile_u) { const Weight &wu = weights.u[tile_u]; + prepos.Bernstein3D_U(_pos, wu.weights); if (sampleColors) precol.Bernstein3D_U(_col, wu.weights); @@ -566,10 +567,23 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te prederivU.Bernstein3D_U(_pos, wu.derivs); for (int tile_v = 0; tile_v < tess_v + 1; ++tile_v) { + const Weight &wv = weights.v[tile_v]; SimpleVertex &vert = vertices[tile_v * (tess_u + 1) + tile_u]; - const Weight &wv = weights.v[tile_v]; + vert.pos = prepos.Bernstein3D_V(wv.weights); + if (sampleColors) { + vert.color_32 = precol.Bernstein3D_V(wv.weights).ToRGBA(); + } else { + vert.color_32 = patch.defcolor; + } + if (sampleTexcoords) { + pretex.Bernstein3D_V(wv.weights).Write(vert.uv); + } else { + // Generate texcoord + vert.uv[0] = patch_u + tile_u * inv_u; + vert.uv[1] = patch_v + tile_v * inv_v; + } if (computeNormals) { const Vec3f derivU = prederivU.Bernstein3D_V(wv.weights); const Vec3f derivV = prepos.Bernstein3D_V(wv.derivs); @@ -580,23 +594,6 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te } else { vert.nrm.SetZero(); } - - vert.pos = prepos.Bernstein3D_V(wv.weights); - - if (!sampleTexcoords) { - // Generate texcoord - vert.uv[0] = patch_u + tile_u * inv_u; - vert.uv[1] = patch_v + tile_v * inv_v; - } else { - // Sample UV from control points - pretex.Bernstein3D_V(wv.weights).Write(vert.uv); - } - - if (sampleColors) { - vert.color_32 = precol.Bernstein3D_V(wv.weights).ToRGBA(); - } else { - vert.color_32 = patch.defcolor; - } } } From 07888d7027aa30687c527033238282898ed6b4d6 Mon Sep 17 00:00:00 2001 From: xebra Date: Thu, 1 Feb 2018 12:27:29 +0900 Subject: [PATCH 031/347] [spline/bezier]Improve bezier tesselator more. --- GPU/Common/SplineCommon.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 6241a08600..205893acb1 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -497,7 +497,7 @@ void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, const SplinePatc template struct PrecomputedCurves { - PrecomputedCurves(int count) { + PrecomputedCurves(const T *const p[16]) : p(p) { } // http://en.wikipedia.org/wiki/Bernstein_polynomial @@ -509,7 +509,7 @@ struct PrecomputedCurves { return p[0] * w[0] + p[1] * w[1] + p[2] * w[2] + p[3] * w[3]; } - void Bernstein3D_U(const T *const p[16], const float w[4]) { + void Bernstein3D_U(const float w[4]) { horiz[0] = Bernstein3D(p[0], w); horiz[1] = Bernstein3D(p[4], w); horiz[2] = Bernstein3D(p[8], w); @@ -520,6 +520,7 @@ struct PrecomputedCurves { return Bernstein3D(horiz, w); } + const T *const *p; T horiz[4]; }; @@ -530,11 +531,6 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te // First compute all the vertices and put them in an array SimpleVertex *&vertices = (SimpleVertex*&)dest; - PrecomputedCurves prepos(tess_u + 1); - PrecomputedCurves precol(tess_u + 1); - PrecomputedCurves pretex(tess_u + 1); - PrecomputedCurves prederivU(tess_u + 1); - const bool computeNormals = patch.computeNormals; const bool sampleColors = (origVertType & GE_VTYPE_COL_MASK) != 0; const bool sampleTexcoords = (origVertType & GE_VTYPE_TC_MASK) != 0; @@ -555,16 +551,21 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te _col[point] = &patch.col[idx]; _tex[point] = &patch.tex[idx]; } + PrecomputedCurves prepos(_pos); + PrecomputedCurves precol(_col); + PrecomputedCurves pretex(_tex); + PrecomputedCurves prederivU(_pos); + for (int tile_u = 0; tile_u < tess_u + 1; ++tile_u) { const Weight &wu = weights.u[tile_u]; - prepos.Bernstein3D_U(_pos, wu.weights); + prepos.Bernstein3D_U(wu.weights); if (sampleColors) - precol.Bernstein3D_U(_col, wu.weights); + precol.Bernstein3D_U(wu.weights); if (sampleTexcoords) - pretex.Bernstein3D_U(_tex, wu.weights); + pretex.Bernstein3D_U(wu.weights); if (computeNormals) - prederivU.Bernstein3D_U(_pos, wu.derivs); + prederivU.Bernstein3D_U(wu.derivs); for (int tile_v = 0; tile_v < tess_v + 1; ++tile_v) { const Weight &wv = weights.v[tile_v]; From ca4e246680f42ef9d1052c6d23265e8726573089 Mon Sep 17 00:00:00 2001 From: xebra Date: Thu, 1 Feb 2018 13:37:53 +0900 Subject: [PATCH 032/347] [spline/bezier]Improve tessellator more generic. --- GPU/Common/SplineCommon.cpp | 88 +++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 42 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 205893acb1..979d33f806 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -495,33 +495,43 @@ void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, const SplinePatc } } -template -struct PrecomputedCurves { - PrecomputedCurves(const T *const p[16]) : p(p) { - } +// Tessellate single patch (4x4 control points) +template +class Tessellator { +private: + const T *const p[4]; // T p[v][u]; 4x4 control points + T u[4]; // Pre-tessellated U lines +public: + Tessellator(const T *p, const int idx[4]) : p{ p + idx[0], p + idx[1], p + idx[2], p + idx[3] } {} - // http://en.wikipedia.org/wiki/Bernstein_polynomial - template - static T Bernstein3D(const T p[4], const float w[4]) { - if (w[0] == 1) return p[0]; - if (w[3] == 1) return p[3]; - // Linear combination + // Linear combination + T Sample(const T p[4], const float w[4]) { return p[0] * w[0] + p[1] * w[1] + p[2] * w[2] + p[3] * w[3]; } - void Bernstein3D_U(const float w[4]) { - horiz[0] = Bernstein3D(p[0], w); - horiz[1] = Bernstein3D(p[4], w); - horiz[2] = Bernstein3D(p[8], w); - horiz[3] = Bernstein3D(p[12], w); + void SampleEdgeU(int idx) { + u[0] = p[0][idx]; + u[1] = p[1][idx]; + u[2] = p[2][idx]; + u[3] = p[3][idx]; } - T Bernstein3D_V(const float w[4]) { - return Bernstein3D(horiz, w); + void SampleU(const float weights[4]) { + if (weights[0] == 1.0f) { SampleEdgeU(0); return; } // weights = {1,0,0,0}, first edge is open. + if (weights[3] == 1.0f) { SampleEdgeU(3); return; } // weights = {0,0,0,1}, last edge is open. + + u[0] = Sample(p[0], weights); + u[1] = Sample(p[1], weights); + u[2] = Sample(p[2], weights); + u[3] = Sample(p[3], weights); } - const T *const *p; - T horiz[4]; + T SampleV(const float weights[4]) { + if (weights[0] == 1.0f) return u[0]; // weights = {1,0,0,0}, first edge is open. + if (weights[3] == 1.0f) return u[3]; // weights = {0,0,0,1}, last edge is open. + + return Sample(u, weights); + } }; static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType) { @@ -541,53 +551,47 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te int num_patches_v = (patch.count_v - 1) / 3; for (int patch_u = 0; patch_u < num_patches_u; ++patch_u) { for (int patch_v = 0; patch_v < num_patches_v; ++patch_v) { - // Precompute the horizontal curves to we only have to evaluate the vertical ones. - Vec3f *_pos[16]; - Vec4f *_col[16]; - Vec2f *_tex[16]; - for (int point = 0; point < 16; ++point) { - int idx = (patch_u * 3 + point % 4) + (patch_v * 3 + point / 4) * patch.count_u; - _pos[point] = &patch.pos[idx]; - _col[point] = &patch.col[idx]; - _tex[point] = &patch.tex[idx]; - } - PrecomputedCurves prepos(_pos); - PrecomputedCurves precol(_col); - PrecomputedCurves pretex(_tex); - PrecomputedCurves prederivU(_pos); + + // Prepare 4x4 control points to tessellate + const int idx = patch_v * 3 * patch.count_u + patch_u * 3; + const int idx_v[4] = { idx, idx + patch.count_u, idx + patch.count_u * 2, idx + patch.count_u * 3 }; + Tessellator tess_pos(patch.pos, idx_v); + Tessellator tess_col(patch.col, idx_v); + Tessellator tess_tex(patch.tex, idx_v); + Tessellator tess_nrm(patch.pos, idx_v); for (int tile_u = 0; tile_u < tess_u + 1; ++tile_u) { const Weight &wu = weights.u[tile_u]; - prepos.Bernstein3D_U(wu.weights); + tess_pos.SampleU(wu.weights); if (sampleColors) - precol.Bernstein3D_U(wu.weights); + tess_col.SampleU(wu.weights); if (sampleTexcoords) - pretex.Bernstein3D_U(wu.weights); + tess_tex.SampleU(wu.weights); if (computeNormals) - prederivU.Bernstein3D_U(wu.derivs); + tess_nrm.SampleU(wu.derivs); for (int tile_v = 0; tile_v < tess_v + 1; ++tile_v) { const Weight &wv = weights.v[tile_v]; SimpleVertex &vert = vertices[tile_v * (tess_u + 1) + tile_u]; - vert.pos = prepos.Bernstein3D_V(wv.weights); + vert.pos = tess_pos.SampleV(wv.weights); if (sampleColors) { - vert.color_32 = precol.Bernstein3D_V(wv.weights).ToRGBA(); + vert.color_32 = tess_col.SampleV(wv.weights).ToRGBA(); } else { vert.color_32 = patch.defcolor; } if (sampleTexcoords) { - pretex.Bernstein3D_V(wv.weights).Write(vert.uv); + tess_tex.SampleV(wv.weights).Write(vert.uv); } else { // Generate texcoord vert.uv[0] = patch_u + tile_u * inv_u; vert.uv[1] = patch_v + tile_v * inv_v; } if (computeNormals) { - const Vec3f derivU = prederivU.Bernstein3D_V(wv.weights); - const Vec3f derivV = prepos.Bernstein3D_V(wv.derivs); + const Vec3f derivU = tess_nrm.SampleV(wv.weights); + const Vec3f derivV = tess_pos.SampleV(wv.derivs); vert.nrm = Cross(derivU, derivV).Normalized(); if (patch.patchFacing) From b11f9e6acf44e8bb69672d93a8ef98675cc07753 Mon Sep 17 00:00:00 2001 From: xebra Date: Thu, 1 Feb 2018 14:09:02 +0900 Subject: [PATCH 033/347] [spline/bezier]Fix normal generation flag and some minor stuffs. --- GPU/Common/SplineCommon.cpp | 22 +++++++++------------- GPU/Common/SplineCommon.h | 2 -- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 979d33f806..74263e7b10 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -346,8 +346,6 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp // int max_idx = spatch.count_u * spatch.count_v; - bool computeNormals = spatch.computeNormals; - float one_over_patch_div_s = 1.0f / (float)(patch_div_s); float one_over_patch_div_t = 1.0f / (float)(patch_div_t); @@ -541,9 +539,9 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te // First compute all the vertices and put them in an array SimpleVertex *&vertices = (SimpleVertex*&)dest; - const bool computeNormals = patch.computeNormals; - const bool sampleColors = (origVertType & GE_VTYPE_COL_MASK) != 0; - const bool sampleTexcoords = (origVertType & GE_VTYPE_TC_MASK) != 0; + const bool sampleNrm = (origVertType & GE_VTYPE_NRM_MASK) != 0; + const bool sampleCol = (origVertType & GE_VTYPE_COL_MASK) != 0; + const bool sampleTex = (origVertType & GE_VTYPE_TC_MASK) != 0; Weight2D weights(bezierWeightsCache, tess_u, tess_v); @@ -564,11 +562,11 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te const Weight &wu = weights.u[tile_u]; tess_pos.SampleU(wu.weights); - if (sampleColors) + if (sampleCol) tess_col.SampleU(wu.weights); - if (sampleTexcoords) + if (sampleTex) tess_tex.SampleU(wu.weights); - if (computeNormals) + if (sampleNrm) tess_nrm.SampleU(wu.derivs); for (int tile_v = 0; tile_v < tess_v + 1; ++tile_v) { @@ -577,19 +575,19 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te SimpleVertex &vert = vertices[tile_v * (tess_u + 1) + tile_u]; vert.pos = tess_pos.SampleV(wv.weights); - if (sampleColors) { + if (sampleCol) { vert.color_32 = tess_col.SampleV(wv.weights).ToRGBA(); } else { vert.color_32 = patch.defcolor; } - if (sampleTexcoords) { + if (sampleTex) { tess_tex.SampleV(wv.weights).Write(vert.uv); } else { // Generate texcoord vert.uv[0] = patch_u + tile_u * inv_u; vert.uv[1] = patch_v + tile_v * inv_v; } - if (computeNormals) { + if (sampleNrm) { const Vec3f derivU = tess_nrm.SampleV(wv.weights); const Vec3f derivV = tess_pos.SampleV(wv.derivs); @@ -733,7 +731,6 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi patch.type_v = type_v; patch.count_u = count_u; patch.count_v = count_v; - patch.computeNormals = computeNormals; patch.primType = prim_type; patch.patchFacing = patchFacing; patch.defcolor = points[0]->color_32; @@ -839,7 +836,6 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi patch.count_u = count_u; patch.count_v = count_v; patch.primType = prim_type; - patch.computeNormals = computeNormals; patch.patchFacing = patchFacing; patch.defcolor = points[0]->color_32; patch.pos = (Vec3f *)managedBuf.Allocate(sizeof(Vec3f) * count_u * count_v); diff --git a/GPU/Common/SplineCommon.h b/GPU/Common/SplineCommon.h index e0411c1153..9cd99ebcb4 100644 --- a/GPU/Common/SplineCommon.h +++ b/GPU/Common/SplineCommon.h @@ -43,7 +43,6 @@ struct BezierPatch { int count_u; int count_v; GEPatchPrimType primType; - bool computeNormals; bool patchFacing; }; @@ -58,7 +57,6 @@ struct SplinePatchLocal { int count_v; int type_u; int type_v; - bool computeNormals; bool patchFacing; GEPatchPrimType primType; }; From f7ac70858d7fd41f9c49ce154915370db06fdbd4 Mon Sep 17 00:00:00 2001 From: xebra Date: Thu, 1 Feb 2018 15:09:41 +0900 Subject: [PATCH 034/347] [spline/bezier]Improve spline tessellation using same as bezier tessellation method.(performance improvements, at least 10 FPS or more) --- GPU/Common/SplineCommon.cpp | 140 ++++++++++++++---------------------- 1 file changed, 55 insertions(+), 85 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 74263e7b10..83cef33362 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -302,7 +302,7 @@ static void TessellateSplinePatchHardware(u8 *&dest, u16 *indices, int &count, c BuildIndex(indices, count, spatch.tess_u, spatch.tess_v, spatch.primType); } -template +template static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const SplinePatchLocal &spatch, u32 origVertType, int quality, int maxVertices) { // Full (mostly) correct tessellation of spline patches. // Not very fast. @@ -341,101 +341,69 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp // 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; + const float inv_u = 1.0f / (float)spatch.tess_u; + const float inv_v = 1.0f / (float)spatch.tess_v; - // int max_idx = spatch.count_u * spatch.count_v; + int num_patches_u = spatch.count_u - 3; + int num_patches_v = spatch.count_v - 3; + for (int patch_u = 0; patch_u < num_patches_u; ++patch_u) { + int tess_u = (patch_u - 1 == num_patches_u) ? spatch.tess_u + 1 : spatch.tess_u; + for (int patch_v = 0; patch_v < num_patches_v; ++patch_v) { + int tess_v = (patch_v - 1 == num_patches_v) ? spatch.tess_v + 1 : spatch.tess_v; - float one_over_patch_div_s = 1.0f / (float)(patch_div_s); - float one_over_patch_div_t = 1.0f / (float)(patch_div_t); + // Prepare 4x4 control points to tessellate + const int idx = patch_v * spatch.count_u + patch_u; + const int idx_v[4] = { idx, idx + spatch.count_u, idx + spatch.count_u * 2, idx + spatch.count_u * 3 }; + Tessellator tess_pos(spatch.pos, idx_v); + Tessellator tess_col(spatch.col, idx_v); + Tessellator tess_tex(spatch.tex, idx_v); + Tessellator tess_nrm(spatch.pos, idx_v); - for (int tile_v = 0; tile_v < patch_div_t + 1; tile_v++) { - 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) * one_over_patch_div_s; - if (u < 0.0f) - u = 0.0f; - SimpleVertex *vert = &vertices[tile_v * (patch_div_s + 1) + tile_u]; - Vec4f vert_color(0, 0, 0, 0); - Vec3f vert_pos; - vert_pos.SetZero(); - Vec3f du, dv; - Vec2f vert_tex; - if (origNrm) { - du.SetZero(); - dv.SetZero(); - } - if (origCol) { - vert_color.SetZero(); - } else { - vert->color_32 = spatch.defcolor; - } - if (origTc) { - vert_tex.SetZero(); - } else { - 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); - } + for (int tile_u = 0; tile_u < tess_u + 1; ++tile_u) { + int index_u = patch_u * spatch.tess_u + tile_u; + const Weight &wu = weights.u[index_u]; - int iu = (int)u; - int iv = (int)v; + // Pre-tessellate U lines + tess_pos.SampleU(wu.weights); + if (sampleCol) + tess_col.SampleU(wu.weights); + if (sampleTex) + tess_tex.SampleU(wu.weights); + if (sampleNrm) + tess_nrm.SampleU(wu.derivs); - // 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; + for (int tile_v = 0; tile_v < tess_v + 1; ++tile_v) { + int index_v = patch_v * spatch.tess_v + tile_v; + const Weight &wv = weights.v[index_v]; - const Weight &wu = weights.u[tile_u]; - const Weight &wv = weights.v[tile_v]; + SimpleVertex &vert = vertices[index_v * (patch_div_s + 1) + index_u]; - // Handle degenerate patches. without this, spatch.points[] may read outside the number of initialized points. - int patch_w = std::min(spatch.count_u - iu, 4); - int patch_h = std::min(spatch.count_v - iv, 4); + // Tessellate + vert.pos = tess_pos.SampleV(wv.weights); + if (sampleCol) { + vert.color_32 = tess_col.SampleV(wv.weights).ToRGBA(); + } else { + vert.color_32 = spatch.defcolor; + } + if (sampleTex) { + tess_tex.SampleV(wv.weights).Write(vert.uv); + } else { + // Generate texcoord + vert.uv[0] = patch_u + tile_u * inv_u; + vert.uv[1] = patch_v + tile_v * inv_v; + } + if (sampleNrm) { + const Vec3f derivU = tess_nrm.SampleV(wv.weights); + const Vec3f derivV = tess_pos.SampleV(wv.derivs); - for (int ii = 0; ii < patch_w; ++ii) { - for (int jj = 0; jj < patch_h; ++jj) { - float u_spline = wu.weights[ii]; - float v_spline = wv.weights[jj]; - float f = u_spline * v_spline; - - if (f > 0.0f) { - 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); - Crash(); - }*/ - vert_pos += spatch.pos[idx] * f; - if (origTc) { - vert_tex += spatch.tex[idx] * f; - } - if (origCol) { - vert_color += spatch.col[idx] * f; - } - if (origNrm) { - du += spatch.pos[idx] * (wu.derivs[ii] * wv.weights[jj]); - dv += spatch.pos[idx] * (wu.weights[ii] * wv.derivs[jj]); - } + vert.nrm = Cross(derivU, derivV).Normalized(useSSE4); + if (spatch.patchFacing) + vert.nrm *= -1.0f; + } else { + vert.nrm.SetZero(); } } } - vert->pos = vert_pos; - if (origNrm) { - vert->nrm = Cross(du, dv).Normalized(useSSE4); - } else { - vert->nrm.SetZero(); - vert->nrm.z = 1.0f; - } - if (origCol) { - vert->color_32 = vert_color.ToRGBA(); - } - if (origTc) { - vert_tex.Write(vert->uv); - } } } @@ -561,6 +529,7 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te for (int tile_u = 0; tile_u < tess_u + 1; ++tile_u) { const Weight &wu = weights.u[tile_u]; + // Pre-tessellate U lines tess_pos.SampleU(wu.weights); if (sampleCol) tess_col.SampleU(wu.weights); @@ -574,6 +543,7 @@ static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int te SimpleVertex &vert = vertices[tile_v * (tess_u + 1) + tile_u]; + // Tessellate vert.pos = tess_pos.SampleV(wv.weights); if (sampleCol) { vert.color_32 = tess_col.SampleV(wv.weights).ToRGBA(); From da1176f2b30b6040024a9b92ae5258f811be5102 Mon Sep 17 00:00:00 2001 From: xebra Date: Thu, 1 Feb 2018 20:33:17 +0900 Subject: [PATCH 035/347] [spline/bezier]Improve template parameter dispatch method. # Conflicts: # GPU/Common/SplineCommon.h --- GPU/Common/SplineCommon.cpp | 56 +++++++++++-------------------------- GPU/Common/SplineCommon.h | 37 ++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 39 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 83cef33362..592baf3695 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -410,53 +410,31 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp BuildIndex(indices, count, patch_div_s, patch_div_t, spatch.primType); } -template -static inline void SplinePatchFullQualityDispatch4(u8 *&dest, u16 *indices, int &count, const SplinePatchLocal &spatch, u32 origVertType, int quality, int maxVertices) { - if (cpu_info.bSSE4_1) - SplinePatchFullQuality(dest, indices, count, spatch, origVertType, quality, maxVertices); - else - SplinePatchFullQuality(dest, indices, count, spatch, origVertType, quality, maxVertices); -} - -template -static inline void SplinePatchFullQualityDispatch3(u8 *&dest, u16 *indices, int &count, const SplinePatchLocal &spatch, u32 origVertType, int quality, int maxVertices) { - bool origTc = (origVertType & GE_VTYPE_TC_MASK) != 0; - - if (origTc) - SplinePatchFullQualityDispatch4(dest, indices, count, spatch, origVertType, quality, maxVertices); - else - SplinePatchFullQualityDispatch4(dest, indices, count, spatch, origVertType, quality, maxVertices); -} - -template -static inline void SplinePatchFullQualityDispatch2(u8 *&dest, u16 *indices, int &count, const SplinePatchLocal &spatch, u32 origVertType, int quality, int maxVertices) { - bool origCol = (origVertType & GE_VTYPE_COL_MASK) != 0; - - if (origCol) - SplinePatchFullQualityDispatch3(dest, indices, count, spatch, origVertType, quality, maxVertices); - else - SplinePatchFullQualityDispatch3(dest, indices, count, spatch, origVertType, quality, maxVertices); -} - -static void SplinePatchFullQualityDispatch(u8 *&dest, u16 *indices, int &count, const SplinePatchLocal &spatch, u32 origVertType, int quality, int maxVertices) { - bool origNrm = (origVertType & GE_VTYPE_NRM_MASK) != 0; - - if (origNrm) - SplinePatchFullQualityDispatch2(dest, indices, count, spatch, origVertType, quality, maxVertices); - else - SplinePatchFullQualityDispatch2(dest, indices, count, spatch, origVertType, quality, maxVertices); -} +// Define class TemplateParameterDispatcherTess +TEMPLATE_PARAMETER_DISPATCHER(Tess, SplinePatchFullQuality); void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, const SplinePatchLocal &spatch, u32 origVertType, int maxVertexCount) { + using TessFunc = void(*)(u8 *&, u16 *, int &, const SplinePatchLocal &, u32, int, int); + constexpr int NumParams = 4; + static TemplateParameterDispatcherTess dispatcher; // Initialize only once + + const bool params[NumParams] = { + (origVertType & GE_VTYPE_NRM_MASK) != 0, + (origVertType & GE_VTYPE_COL_MASK) != 0, + (origVertType & GE_VTYPE_TC_MASK) != 0, + cpu_info.bSSE4_1, + }; + TessFunc func = dispatcher.GetFunc(params); + switch (g_Config.iSplineBezierQuality) { case LOW_QUALITY: - SplinePatchFullQualityDispatch(dest, indices, count, spatch, origVertType, 0, maxVertexCount); + (*func)(dest, indices, count, spatch, origVertType, 0, maxVertexCount); break; case MEDIUM_QUALITY: - SplinePatchFullQualityDispatch(dest, indices, count, spatch, origVertType, 2, maxVertexCount); + (*func)(dest, indices, count, spatch, origVertType, 2, maxVertexCount); break; case HIGH_QUALITY: - SplinePatchFullQualityDispatch(dest, indices, count, spatch, origVertType, 1, maxVertexCount); + (*func)(dest, indices, count, spatch, origVertType, 1, maxVertexCount); break; } } diff --git a/GPU/Common/SplineCommon.h b/GPU/Common/SplineCommon.h index 9cd99ebcb4..a0e208f463 100644 --- a/GPU/Common/SplineCommon.h +++ b/GPU/Common/SplineCommon.h @@ -69,3 +69,40 @@ enum SplineQuality { bool CanUseHardwareTessellation(GEPatchPrimType prim); void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, const SplinePatchLocal &spatch, u32 origVertType, int maxVertices); +void TessellateBezierPatch(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType, int maxVertices); + +#define TEMPLATE_PARAMETER_DISPATCHER(NAME, FUNCNAME) \ +template \ +class TemplateParameterDispatcher##NAME { \ + /* Store all combinations of template functions into an array */ \ + template \ + struct Initializer { \ + Initializer(Func funcs[]) { \ + Initializer _true(funcs); \ + Initializer _false(funcs); \ + } \ + }; \ + /* Specialized for terminates the recursive loop */ \ + template \ + struct Initializer<0, Index, Params...> { \ + Initializer(Func funcs[]) { \ + funcs[Index] = &FUNCNAME; \ + } \ + }; \ + \ +private: \ + Func funcs[1 << NumParams]; /* Function pointers array */ \ +public: \ + TemplateParameterDispatcher##NAME() { \ + Initializer::Initializer(funcs); \ + } \ + \ + Func GetFunc(const bool params[]) const { \ + /* Convert bool parameters to index of the array */ \ + int param = 0; \ + for (int i = 0; i < NumParams; ++i) \ + param |= params[i] << i; \ + \ + return funcs[param]; \ + } \ +}; From 24123e626847b9da677d9c52e5ccfac1a79c4b6e Mon Sep 17 00:00:00 2001 From: xebra Date: Fri, 2 Feb 2018 17:36:02 +0900 Subject: [PATCH 036/347] [spline/bezier]Fix about quality. --- GPU/Common/SplineCommon.cpp | 82 ++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 592baf3695..34b21dd936 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -30,6 +30,8 @@ #include "GPU/ge_constants.h" #include "GPU/GPUState.h" // only needed for UVScale stuff +#define HALF_CEIL(x) (x + 1) / 2 // Integer ceil = (int)ceil((float)x / 2.0f) + static void CopyQuadIndex(u16 *&indices, GEPatchPrimType type, const int idx0, const int idx1, const int idx2, const int idx3) { if (type == GE_PATCHPRIM_LINES) { *(indices++) = idx0; @@ -303,7 +305,7 @@ static void TessellateSplinePatchHardware(u8 *&dest, u16 *indices, int &count, c } template -static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const SplinePatchLocal &spatch, u32 origVertType, int quality, int maxVertices) { +static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const SplinePatchLocal &spatch) { // Full (mostly) correct tessellation of spline patches. // Not very fast. @@ -314,29 +316,6 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp // Increase tessellation based on the size. Should be approximately right? int patch_div_s = (spatch.count_u - 3) * spatch.tess_u; int patch_div_t = (spatch.count_v - 3) * spatch.tess_v; - if (quality == 0) { - // Low quality - patch_div_s = (spatch.count_u - 3) * 2; - patch_div_t = (spatch.count_v - 3) * 2; - } - if (quality > 1) { - // Don't cut below 2, though. - if (patch_div_s > 2) { - patch_div_s /= quality; - } - if (patch_div_t > 2) { - patch_div_t /= quality; - } - } - - // Downsample until it fits, in case crazy tessellation 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 < 1) patch_div_s = 1; - if (patch_div_t < 1) patch_div_t = 1; // First compute all the vertices and put them in an array SimpleVertex *&vertices = (SimpleVertex*&)dest; @@ -413,8 +392,8 @@ static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const Sp // Define class TemplateParameterDispatcherTess TEMPLATE_PARAMETER_DISPATCHER(Tess, SplinePatchFullQuality); -void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, const SplinePatchLocal &spatch, u32 origVertType, int maxVertexCount) { - using TessFunc = void(*)(u8 *&, u16 *, int &, const SplinePatchLocal &, u32, int, int); +void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, SplinePatchLocal &spatch, u32 origVertType, int maxVertices) { + using TessFunc = void(*)(u8 *&, u16 *, int &, const SplinePatchLocal &); constexpr int NumParams = 4; static TemplateParameterDispatcherTess dispatcher; // Initialize only once @@ -428,15 +407,26 @@ void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, const SplinePatc switch (g_Config.iSplineBezierQuality) { case LOW_QUALITY: - (*func)(dest, indices, count, spatch, origVertType, 0, maxVertexCount); + spatch.tess_u = 2; + spatch.tess_v = 2; break; case MEDIUM_QUALITY: - (*func)(dest, indices, count, spatch, origVertType, 2, maxVertexCount); - break; + // Don't cut below 2, though. + if (spatch.tess_u > 2) spatch.tess_u = HALF_CEIL(spatch.tess_u); + if (spatch.tess_v > 2) spatch.tess_v = HALF_CEIL(spatch.tess_v); + // Pass through case HIGH_QUALITY: - (*func)(dest, indices, count, spatch, origVertType, 1, maxVertexCount); + int num_patches_u = spatch.count_u - 3; + int num_patches_v = spatch.count_v - 3; + // Downsample until it fits, in case crazy tessellation factors are sent. + while ((num_patches_u * spatch.tess_u + 1) * (num_patches_v * spatch.tess_v + 1) > maxVertices) { + spatch.tess_u--; + spatch.tess_v--; + } break; } + + (*func)(dest, indices, count, spatch); } // Tessellate single patch (4x4 control points) @@ -577,18 +567,29 @@ static void TessellateBezierPatchHardware(u8 *&dest, u16 *indices, int &count, i BuildIndex(indices, count, tess_u, tess_v, primType); } -void TessellateBezierPatch(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType) { +void TessellateBezierPatch(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType, int maxVertices) { switch (g_Config.iSplineBezierQuality) { case LOW_QUALITY: - _BezierPatchHighQuality(dest, indices, count, 2, 2, patch, origVertType); + tess_u = 2; + tess_v = 2; break; case MEDIUM_QUALITY: - _BezierPatchHighQuality(dest, indices, count, std::max(tess_u / 2, 1), std::max(tess_v / 2, 1), patch, origVertType); - break; + // Don't cut below 2, though. + if (tess_u > 2) tess_u = HALF_CEIL(tess_u); + if (tess_v > 2) tess_v = HALF_CEIL(tess_v); + // Pass through case HIGH_QUALITY: - _BezierPatchHighQuality(dest, indices, count, tess_u, tess_v, patch, origVertType); + int num_patches_u = (patch.count_u - 1) / 3; + int num_patches_v = (patch.count_v - 1) / 3; + // Downsample until it fits, in case crazy tessellation factors are sent. + while ((tess_u + 1) * (tess_v + 1) * num_patches_u * num_patches_v > maxVertices) { + tess_u--; + tess_v--; + } break; } + + _BezierPatchHighQuality(dest, indices, count, tess_u, tess_v, patch, origVertType); } static void CopyControlPoints(const SimpleVertex *const *points, float *pos, float *tex, float *col, int posStride, int texStride, int colStride, int size, bool hasColor, bool hasTexCoords) { @@ -664,6 +665,10 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi ERROR_LOG(G3D, "Something went really wrong, vertex size: %i vs %i", vertexSize, (int)sizeof(SimpleVertex)); } + // If specified as 0, uses 1. + if (tess_u < 1) tess_u = 1; + if (tess_v < 1) tess_v = 1; + // Make an array of pointers to the control points, to get rid of indices. const SimpleVertex **points = (const SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * count_u * count_v); for (int idx = 0; idx < count_u * count_v; idx++) @@ -795,12 +800,7 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi patch.col[idx] = Vec4f::FromRGBA(points[idx]->color_32); } int maxVertices = SPLINE_BUFFER_SIZE / vertexSize; - // Downsample until it fits, in case crazy tessellation factors are sent. - while ((tess_u + 1) * (tess_v + 1) * num_patches_u * num_patches_v > maxVertices) { - tess_u /= 2; - tess_v /= 2; - } - TessellateBezierPatch(dest, inds, count, tess_u, tess_v, patch, origVertType); + TessellateBezierPatch(dest, inds, count, tess_u, tess_v, patch, origVertType, maxVertices); } u32 vertTypeWithIndex16 = (vertType & ~GE_VTYPE_IDX_MASK) | GE_VTYPE_IDX_16BIT; From 7d450782024076a120842fac8d7bd3b59f75639b Mon Sep 17 00:00:00 2001 From: xebra Date: Fri, 29 Jun 2018 00:26:23 +0900 Subject: [PATCH 037/347] [spline/bezier]minor cleanup --- GPU/Common/SplineCommon.cpp | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 34b21dd936..1a146b1a90 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -592,23 +592,6 @@ void TessellateBezierPatch(u8 *&dest, u16 *&indices, int &count, int tess_u, int _BezierPatchHighQuality(dest, indices, count, tess_u, tess_v, patch, origVertType); } -static void CopyControlPoints(const SimpleVertex *const *points, float *pos, float *tex, float *col, int posStride, int texStride, int colStride, int size, bool hasColor, bool hasTexCoords) { - for (int idx = 0; idx < size; idx++) { - memcpy(pos, points[idx]->pos.AsArray(), 3 * sizeof(float)); - pos += posStride; - if (hasTexCoords) { - memcpy(tex, points[idx]->uv, 2 * sizeof(float)); - tex += texStride; - } - if (hasColor) { - memcpy(col, Vec4f::FromRGBA(points[idx]->color_32).AsArray(), 4 * sizeof(float)); - col += colStride; - } - } - if (!hasColor) - memcpy(col, Vec4f::FromRGBA(points[0]->color_32).AsArray(), 4 * sizeof(float)); -} - class SimpleBufferManager { private: u8 *buf_; From 0cb63318bc5e80aeff247918ae9f431745527e51 Mon Sep 17 00:00:00 2001 From: xebra Date: Fri, 29 Jun 2018 00:51:31 +0900 Subject: [PATCH 038/347] [spline/bezier]Fix to build for GE debugger. --- GPU/Common/SplineCommon.h | 4 +- Windows/GEDebugger/VertexPreview.cpp | 64 ++++++++++++++++------------ 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/GPU/Common/SplineCommon.h b/GPU/Common/SplineCommon.h index a0e208f463..bc9fb06dce 100644 --- a/GPU/Common/SplineCommon.h +++ b/GPU/Common/SplineCommon.h @@ -67,9 +67,7 @@ enum SplineQuality { HIGH_QUALITY = 2, }; -bool CanUseHardwareTessellation(GEPatchPrimType prim); -void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, const SplinePatchLocal &spatch, u32 origVertType, int maxVertices); -void TessellateBezierPatch(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType, int maxVertices); +bool CanUseHardwareTessellation(GEPatchPrimType prim);void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, SplinePatchLocal &spatch, u32 origVertType, int maxVertices);void TessellateBezierPatch(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType, int maxVertices); #define TEMPLATE_PARAMETER_DISPATCHER(NAME, FUNCNAME) \ template \ diff --git a/Windows/GEDebugger/VertexPreview.cpp b/Windows/GEDebugger/VertexPreview.cpp index 8fa7daa050..d7ea8f1755 100644 --- a/Windows/GEDebugger/VertexPreview.cpp +++ b/Windows/GEDebugger/VertexPreview.cpp @@ -180,22 +180,28 @@ static void ExpandBezier(int &count, int op, const std::vector &si int num_patches_u = (count_u - 1) / 3; int num_patches_v = (count_v - 1) / 3; int total_patches = num_patches_u * num_patches_v; - std::vector patches; - patches.resize(total_patches); - for (int patch_u = 0; patch_u < num_patches_u; patch_u++) { - for (int patch_v = 0; patch_v < num_patches_v; patch_v++) { - BezierPatch &patch = patches[patch_u + patch_v * num_patches_u]; - for (int point = 0; point < 16; ++point) { - int idx = (patch_u * 3 + point % 4) + (patch_v * 3 + point / 4) * count_u; - patch.points[point] = &simpleVerts[0] + (!indices.empty() ? indices[idx] : idx); - } - patch.u_index = patch_u * 3; - patch.v_index = patch_v * 3; - patch.index = patch_v * num_patches_u + patch_u; - patch.primType = gstate.getPatchPrimitiveType(); - patch.computeNormals = false; - patch.patchFacing = false; - } + + std::vector points(count_u * count_v); + for (int idx = 0; idx < count_u * count_v; idx++) + points[idx] = &simpleVerts[0] + (!indices.empty() ? indices[idx] : idx); + + BezierPatch patch; + patch.count_u = count_u; + patch.count_v = count_v; + patch.primType = gstate.getPatchPrimitiveType(); + patch.patchFacing = false; + patch.defcolor = 0xFFFFFFFF; + + std::vector pos(patch.count_u * patch.count_v); + std::vector tex(patch.count_u * patch.count_v); + std::vector col(patch.count_u * patch.count_v); + patch.pos = pos.data(); + patch.tex = tex.data(); + patch.col = col.data(); + for (int idx = 0; idx < count_u * count_v; idx++) { + patch.pos[idx] = Vec3f(points[idx]->pos); + patch.tex[idx] = Vec2f(points[idx]->uv); + patch.col[idx] = Vec4f::FromRGBA(points[idx]->color_32); } generatedVerts.resize((tess_u + 1) * (tess_v + 1) * total_patches); @@ -204,15 +210,11 @@ static void ExpandBezier(int &count, int op, const std::vector &si count = 0; u8 *dest = (u8 *)&generatedVerts[0]; u16 *inds = &generatedInds[0]; - for (int patch_idx = 0; patch_idx < total_patches; ++patch_idx) { - const BezierPatch &patch = patches[patch_idx]; - TessellateBezierPatch(dest, inds, count, tess_u, tess_v, patch, gstate.vertType); - } + TessellateBezierPatch(dest, inds, count, tess_u, tess_v, patch, gstate.vertType, generatedVerts.size()); } static void ExpandSpline(int &count, int op, const std::vector &simpleVerts, const std::vector &indices, std::vector &generatedVerts, std::vector &generatedInds) { SplinePatchLocal patch; - patch.computeNormals = false; patch.primType = gstate.getPatchPrimitiveType(); patch.patchFacing = false; @@ -235,25 +237,33 @@ static void ExpandSpline(int &count, int op, const std::vector &si return; } - std::vector points; - points.resize(patch.count_u * patch.count_v); + std::vector points(patch.count_u * patch.count_v); // Make an array of pointers to the control points, to get rid of indices. for (int idx = 0; idx < patch.count_u * patch.count_v; idx++) { points[idx] = &simpleVerts[0] + (!indices.empty() ? indices[idx] : idx); } - patch.points = &points[0]; + std::vector pos(patch.count_u * patch.count_v); + std::vector tex(patch.count_u * patch.count_v); + std::vector col(patch.count_u * patch.count_v); + patch.pos = pos.data(); + patch.tex = tex.data(); + patch.col = col.data(); + for (int idx = 0; idx < patch.count_u * patch.count_v; idx++) { + patch.pos[idx] = Vec3f(points[idx]->pos); + patch.tex[idx] = Vec2f(points[idx]->uv); + patch.col[idx] = Vec4f::FromRGBA(points[idx]->color_32); + } int patch_div_s = (patch.count_u - 3) * patch.tess_u; int patch_div_t = (patch.count_v - 3) * patch.tess_v; - int maxVertexCount = (patch_div_s + 1) * (patch_div_t + 1); - generatedVerts.resize(maxVertexCount); + generatedVerts.resize((patch_div_s + 1) * (patch_div_t + 1)); generatedInds.resize(patch_div_s * patch_div_t * 6); count = 0; u8 *dest = (u8 *)&generatedVerts[0]; - TessellateSplinePatch(dest, &generatedInds[0], count, patch, gstate.vertType, maxVertexCount); + TessellateSplinePatch(dest, &generatedInds[0], count, patch, gstate.vertType, generatedVerts.size()); } void CGEDebugger::UpdatePrimPreview(u32 op, int which) { From 3add123587b5957c148a6e193380add7e1e2ed32 Mon Sep 17 00:00:00 2001 From: xebra Date: Fri, 29 Jun 2018 23:50:07 +0900 Subject: [PATCH 039/347] thin3d: Add support for texture subimage to GLRender. --- ext/native/thin3d/GLQueueRunner.cpp | 24 ++++++++++++++++++++++-- ext/native/thin3d/GLQueueRunner.h | 14 ++++++++++++++ ext/native/thin3d/GLRenderManager.h | 15 +++++++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/ext/native/thin3d/GLQueueRunner.cpp b/ext/native/thin3d/GLQueueRunner.cpp index 6d123518e3..d12ba97d49 100644 --- a/ext/native/thin3d/GLQueueRunner.cpp +++ b/ext/native/thin3d/GLQueueRunner.cpp @@ -306,14 +306,14 @@ void GLQueueRunner::RunInitSteps(const std::vector &steps, bool ski glBindTexture(tex->target, tex->texture); boundTexture = tex->texture; } - if (!step.texture_image.data) + if (!step.texture_image.data && step.texture_image.allocType != GLRAllocType::NONE) Crash(); // For things to show in RenderDoc, need to split into glTexImage2D(..., nullptr) and glTexSubImage. glTexImage2D(tex->target, step.texture_image.level, step.texture_image.internalFormat, step.texture_image.width, step.texture_image.height, 0, step.texture_image.format, step.texture_image.type, step.texture_image.data); allocatedTextures = true; if (step.texture_image.allocType == GLRAllocType::ALIGNED) { FreeAlignedMemory(step.texture_image.data); - } else { + } else if (step.texture_image.allocType == GLRAllocType::NEW) { delete[] step.texture_image.data; } CHECK_GL_ERROR_IF_DEBUG(); @@ -328,6 +328,26 @@ void GLQueueRunner::RunInitSteps(const std::vector &steps, bool ski CHECK_GL_ERROR_IF_DEBUG(); break; } + case GLRInitStepType::TEXTURE_SUBIMAGE: + { + GLRTexture *tex = step.texture_subimage.texture; + CHECK_GL_ERROR_IF_DEBUG(); + if (boundTexture != tex->texture) { + glBindTexture(tex->target, tex->texture); + boundTexture = tex->texture; + } + if (!step.texture_subimage.data) + Crash(); + // For things to show in RenderDoc, need to split into glTexImage2D(..., nullptr) and glTexSubImage. + glTexSubImage2D(tex->target, step.texture_subimage.level, step.texture_subimage.x, step.texture_subimage.y, step.texture_subimage.width, step.texture_subimage.height, step.texture_subimage.format, step.texture_subimage.type, step.texture_subimage.data); + if (step.texture_subimage.allocType == GLRAllocType::ALIGNED) { + FreeAlignedMemory(step.texture_subimage.data); + } else if (step.texture_subimage.allocType == GLRAllocType::NEW) { + delete[] step.texture_subimage.data; + } + CHECK_GL_ERROR_IF_DEBUG(); + break; + } case GLRInitStepType::TEXTURE_FINALIZE: { CHECK_GL_ERROR_IF_DEBUG(); diff --git a/ext/native/thin3d/GLQueueRunner.h b/ext/native/thin3d/GLQueueRunner.h index 5f1432e52d..03420f6689 100644 --- a/ext/native/thin3d/GLQueueRunner.h +++ b/ext/native/thin3d/GLQueueRunner.h @@ -20,6 +20,7 @@ struct GLOffset2D { }; enum class GLRAllocType { + NONE, NEW, ALIGNED, }; @@ -196,6 +197,7 @@ enum class GLRInitStepType : uint8_t { CREATE_FRAMEBUFFER, TEXTURE_IMAGE, + TEXTURE_SUBIMAGE, TEXTURE_FINALIZE, BUFFER_SUBDATA, }; @@ -250,6 +252,18 @@ struct GLRInitStep { bool linearFilter; uint8_t *data; // owned, delete[]-d } texture_image; + struct { + GLRTexture *texture; + GLenum format; + GLenum type; + int level; + int x; + int y; + int width; + int height; + GLRAllocType allocType; + uint8_t *data; // owned, delete[]-d + } texture_subimage; struct { GLRTexture *texture; int maxLevel; diff --git a/ext/native/thin3d/GLRenderManager.h b/ext/native/thin3d/GLRenderManager.h index 4c3c32b13d..12bfea9dd7 100644 --- a/ext/native/thin3d/GLRenderManager.h +++ b/ext/native/thin3d/GLRenderManager.h @@ -530,6 +530,21 @@ public: initSteps_.push_back(step); } + void TextureSubImage(GLRTexture *texture, int level, int x, int y, int width, int height, GLenum format, GLenum type, uint8_t *data, GLRAllocType allocType = GLRAllocType::NEW) { + GLRInitStep step{ GLRInitStepType::TEXTURE_SUBIMAGE }; + step.texture_subimage.texture = texture; + step.texture_subimage.data = data; + step.texture_subimage.format = format; + step.texture_subimage.type = type; + step.texture_subimage.level = level; + step.texture_subimage.x = x; + step.texture_subimage.y = y; + step.texture_subimage.width = width; + step.texture_subimage.height = height; + step.texture_subimage.allocType = allocType; + initSteps_.push_back(step); + } + void FinalizeTexture(GLRTexture *texture, int maxLevels, bool genMips) { GLRInitStep step{ GLRInitStepType::TEXTURE_FINALIZE }; step.texture_finalize.texture = texture; From 1b076f83244d9cbe88e1e393ac68aacabcd8a365 Mon Sep 17 00:00:00 2001 From: xebra Date: Sat, 30 Jun 2018 00:21:30 +0900 Subject: [PATCH 040/347] [spline/bezier]Improve HW tess on Opengl to combine 3 textures into a single texture and use it. --- GPU/GLES/DrawEngineGLES.cpp | 31 ++++++++------------------ GPU/GLES/DrawEngineGLES.h | 6 ++--- GPU/GLES/ShaderManagerGLES.cpp | 12 +++++----- GPU/GLES/ShaderManagerGLES.h | 7 +++--- GPU/GLES/VertexShaderGeneratorGLES.cpp | 14 ++++++------ 5 files changed, 29 insertions(+), 41 deletions(-) diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index ed0ff62d74..3d0a077a00 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -661,41 +661,28 @@ void DrawEngineGLES::TessellationDataTransferGLES::SendDataToShader(const Simple int sizeColor = hasColor ? size : 1; float *pos = new float[size * 4]; - float *tex = nullptr; - if (hasTexCoord) - tex = new float[size * 4]; + float *tex = hasTexCoord ? new float[size * 4] : nullptr; float *col = new float[sizeColor * 4]; int stride = 4; CopyControlPoints(pos, tex, col, stride, stride, stride, points, size, vertType); // Removed the 1D texture support, it's unlikely to be relevant for performance. - - // Position + // Control Points if (data_tex[0]) renderManager_->DeleteTexture(data_tex[0]); data_tex[0] = renderManager_->CreateTexture(GL_TEXTURE_2D); - renderManager_->TextureImage(data_tex[0], 0, size, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT, (u8 *)pos, GLRAllocType::NEW, false); + renderManager_->TextureImage(data_tex[0], 0, size, 3, GL_RGBA32F, GL_RGBA, GL_FLOAT, (u8 *)nullptr, GLRAllocType::NONE, false); renderManager_->FinalizeTexture(data_tex[0], 0, false); - renderManager_->BindTexture(TEX_SLOT_SPLINE_POS, data_tex[0]); + renderManager_->BindTexture(TEX_SLOT_SPLINE_POINTS, data_tex[0]); + // Position + renderManager_->TextureSubImage(data_tex[0], 0, 0, 0, size, 1, GL_RGBA, GL_FLOAT, (u8 *)pos, GLRAllocType::NEW); // Texcoord - if (hasTexCoord) { - if (data_tex[1]) - renderManager_->DeleteTexture(data_tex[1]); - data_tex[1] = renderManager_->CreateTexture(GL_TEXTURE_2D); - renderManager_->TextureImage(data_tex[1], 0, size, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT, (u8 *)tex, GLRAllocType::NEW, false); - renderManager_->FinalizeTexture(data_tex[1], 0, false); - renderManager_->BindTexture(TEX_SLOT_SPLINE_TEX, data_tex[1]); - } - + if (hasTexCoord) + renderManager_->TextureSubImage(data_tex[0], 0, 0, 1, size, 1, GL_RGBA, GL_FLOAT, (u8 *)tex, GLRAllocType::NEW); // Color - if (data_tex[2]) - renderManager_->DeleteTexture(data_tex[2]); - data_tex[2] = renderManager_->CreateTexture(GL_TEXTURE_2D); - renderManager_->TextureImage(data_tex[2], 0, sizeColor, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT, (u8 *)col, GLRAllocType::NEW, false); - renderManager_->FinalizeTexture(data_tex[2], 0, false); - renderManager_->BindTexture(TEX_SLOT_SPLINE_COL, data_tex[2]); + renderManager_->TextureSubImage(data_tex[0], 0, 0, 2, sizeColor, 1, GL_RGBA, GL_FLOAT, (u8 *)col, GLRAllocType::NEW); } void DrawEngineGLES::TessellationDataTransferGLES::EndFrame() { diff --git a/GPU/GLES/DrawEngineGLES.h b/GPU/GLES/DrawEngineGLES.h index a0646c9ab6..19df863133 100644 --- a/GPU/GLES/DrawEngineGLES.h +++ b/GPU/GLES/DrawEngineGLES.h @@ -46,9 +46,9 @@ enum { TEX_SLOT_SHADERBLEND_SRC = 1, TEX_SLOT_ALPHATEST = 2, TEX_SLOT_CLUT = 3, - TEX_SLOT_SPLINE_POS = 4, - TEX_SLOT_SPLINE_TEX = 5, - TEX_SLOT_SPLINE_COL = 6, + TEX_SLOT_SPLINE_POINTS = 4, + TEX_SLOT_SPLINE_WEIGHTS_U = 5, + TEX_SLOT_SPLINE_WEIGHTS_V = 6, }; diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index bee0fad708..fbe7e8a746 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -159,9 +159,9 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs, // We need to fetch these unconditionally, gstate_c.spline or bezier will not be set if we // create this shader at load time from the shader cache. - queries.push_back({ &u_tess_pos_tex, "u_tess_pos_tex" }); - queries.push_back({ &u_tess_tex_tex, "u_tess_tex_tex" }); - queries.push_back({ &u_tess_col_tex, "u_tess_col_tex" }); + queries.push_back({ &u_tess_points, "u_tess_points" }); + queries.push_back({ &u_tess_weights_u, "u_tess_weights_u" }); + queries.push_back({ &u_tess_weights_v, "u_tess_weights_v" }); queries.push_back({ &u_spline_count_u, "u_spline_count_u" }); queries.push_back({ &u_spline_count_v, "u_spline_count_v" }); queries.push_back({ &u_spline_type_u, "u_spline_type_u" }); @@ -176,9 +176,9 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs, initialize.push_back({ &u_fbotex, 0, 1 }); initialize.push_back({ &u_testtex, 0, 2 }); initialize.push_back({ &u_pal, 0, 3 }); // CLUT - initialize.push_back({ &u_tess_pos_tex, 0, 4 }); // Texture unit 4 - initialize.push_back({ &u_tess_tex_tex, 0, 5 }); // Texture unit 5 - initialize.push_back({ &u_tess_col_tex, 0, 6 }); // Texture unit 6 + initialize.push_back({ &u_tess_points, 0, 4 }); // Control Points + initialize.push_back({ &u_tess_weights_u, 0, 5 }); + initialize.push_back({ &u_tess_weights_v, 0, 6 }); program = render->CreateProgram(shaders, semantics, queries, initialize, gstate_c.featureFlags & GPU_SUPPORTS_DUALSOURCE_BLEND); diff --git a/GPU/GLES/ShaderManagerGLES.h b/GPU/GLES/ShaderManagerGLES.h index 5dbfe43b4e..ab551db593 100644 --- a/GPU/GLES/ShaderManagerGLES.h +++ b/GPU/GLES/ShaderManagerGLES.h @@ -117,9 +117,10 @@ public: int u_lightspecular[4]; // attenuation int u_lightambient[4]; // attenuation - int u_tess_pos_tex; - int u_tess_tex_tex; - int u_tess_col_tex; + // Spline Tessellation + int u_tess_points; // Control Points + int u_tess_weights_u; + int u_tess_weights_v; int u_spline_count_u; int u_spline_count_v; int u_spline_type_u; diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index bc55cafe45..0c06553f84 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -379,9 +379,9 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, if (doBezier || doSpline) { *uniformMask |= DIRTY_BEZIERSPLINE; - WRITE(p, "uniform sampler2D u_tess_pos_tex;\n"); - WRITE(p, "uniform sampler2D u_tess_tex_tex;\n"); - WRITE(p, "uniform sampler2D u_tess_col_tex;\n"); + WRITE(p, "uniform sampler2D u_tess_points;\n"); // Control Points + WRITE(p, "uniform sampler2D u_tess_weights_u;\n"); + WRITE(p, "uniform sampler2D u_tess_weights_v;\n"); WRITE(p, "uniform int u_spline_count_u;\n"); @@ -506,11 +506,11 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, 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) * u_spline_count_u + (j + u%s);\n", doBezier ? " * 3" : "", doBezier ? " * 3" : ""); - WRITE(p, " _pos[i * 4 + j] = %s(u_tess_pos_tex, ivec2(index, 0), 0).xyz;\n", texelFetch); + 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_tex_tex, ivec2(index, 0), 0).xy;\n", texelFetch); + 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_col_tex, ivec2(index, 0), 0).rgba;\n", texelFetch); + WRITE(p, " _col[i * 4 + j] = %s(u_tess_points, ivec2(index, 2), 0).rgba;\n", texelFetch); WRITE(p, " }\n"); WRITE(p, " }\n"); WRITE(p, " vec2 tess_pos = position.xy;\n"); @@ -539,7 +539,7 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, if (hasColorTess) WRITE(p, " vec4 col = tess_sample(_col, weights);\n"); else - WRITE(p, " vec4 col = %s(u_tess_col_tex, ivec2(0, 0), 0).rgba;\n", texelFetch); + WRITE(p, " vec4 col = %s(u_tess_points, ivec2(0, 2), 0).rgba;\n", texelFetch); } if (hasNormal) { // Curved surface is probably always need to compute normal(not sampling from control points) From e5976f588b738392fe0e1166f38f38125a79647c Mon Sep 17 00:00:00 2001 From: xebra Date: Mon, 5 Feb 2018 01:47:58 +0900 Subject: [PATCH 041/347] [spline/bezier]Unify software tessellation of bezier and spline. # Conflicts: # GPU/Common/SplineCommon.cpp --- GPU/Common/SplineCommon.cpp | 393 +++++++++++++----------------------- GPU/Common/SplineCommon.h | 130 ++++++++++-- 2 files changed, 249 insertions(+), 274 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 1a146b1a90..558570f3ea 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -30,8 +30,6 @@ #include "GPU/ge_constants.h" #include "GPU/GPUState.h" // only needed for UVScale stuff -#define HALF_CEIL(x) (x + 1) / 2 // Integer ceil = (int)ceil((float)x / 2.0f) - static void CopyQuadIndex(u16 *&indices, GEPatchPrimType type, const int idx0, const int idx1, const int idx2, const int idx3) { if (type == GE_PATCHPRIM_LINES) { *(indices++) = idx0; @@ -50,7 +48,7 @@ static void CopyQuadIndex(u16 *&indices, GEPatchPrimType type, const int idx0, c } } -static void BuildIndex(u16 *indices, int &count, int num_u, int num_v, GEPatchPrimType prim_type, int total = 0) { +static void BuildIndex(u16 *indices, int &count, int num_u, int num_v, GEPatchPrimType prim_type, int total) { for (int v = 0; v < num_v; ++v) { for (int u = 0; u < num_u; ++u) { int idx0 = v * (num_u + 1) + u + total; // Top left @@ -92,6 +90,10 @@ public: } return weights; } + + u32 ToKey(int tess, int count, int type) { + return tess; + } }; class Spline3DWeight { @@ -304,131 +306,6 @@ static void TessellateSplinePatchHardware(u8 *&dest, u16 *indices, int &count, c BuildIndex(indices, count, spatch.tess_u, spatch.tess_v, spatch.primType); } -template -static void SplinePatchFullQuality(u8 *&dest, u16 *indices, int &count, const SplinePatchLocal &spatch) { - // Full (mostly) correct tessellation of spline patches. - // Not very fast. - - u32 key_u = splineWeightsCache.ToKey(spatch.tess_u, spatch.count_u, spatch.type_u); - u32 key_v = splineWeightsCache.ToKey(spatch.tess_v, spatch.count_v, spatch.type_v); - Weight2D weights(splineWeightsCache, key_u, key_v); - - // Increase tessellation based on the size. Should be approximately right? - int patch_div_s = (spatch.count_u - 3) * spatch.tess_u; - int patch_div_t = (spatch.count_v - 3) * spatch.tess_v; - - // First compute all the vertices and put them in an array - SimpleVertex *&vertices = (SimpleVertex*&)dest; - - const float inv_u = 1.0f / (float)spatch.tess_u; - const float inv_v = 1.0f / (float)spatch.tess_v; - - int num_patches_u = spatch.count_u - 3; - int num_patches_v = spatch.count_v - 3; - for (int patch_u = 0; patch_u < num_patches_u; ++patch_u) { - int tess_u = (patch_u - 1 == num_patches_u) ? spatch.tess_u + 1 : spatch.tess_u; - for (int patch_v = 0; patch_v < num_patches_v; ++patch_v) { - int tess_v = (patch_v - 1 == num_patches_v) ? spatch.tess_v + 1 : spatch.tess_v; - - // Prepare 4x4 control points to tessellate - const int idx = patch_v * spatch.count_u + patch_u; - const int idx_v[4] = { idx, idx + spatch.count_u, idx + spatch.count_u * 2, idx + spatch.count_u * 3 }; - Tessellator tess_pos(spatch.pos, idx_v); - Tessellator tess_col(spatch.col, idx_v); - Tessellator tess_tex(spatch.tex, idx_v); - Tessellator tess_nrm(spatch.pos, idx_v); - - for (int tile_u = 0; tile_u < tess_u + 1; ++tile_u) { - int index_u = patch_u * spatch.tess_u + tile_u; - const Weight &wu = weights.u[index_u]; - - // Pre-tessellate U lines - tess_pos.SampleU(wu.weights); - if (sampleCol) - tess_col.SampleU(wu.weights); - if (sampleTex) - tess_tex.SampleU(wu.weights); - if (sampleNrm) - tess_nrm.SampleU(wu.derivs); - - for (int tile_v = 0; tile_v < tess_v + 1; ++tile_v) { - int index_v = patch_v * spatch.tess_v + tile_v; - const Weight &wv = weights.v[index_v]; - - SimpleVertex &vert = vertices[index_v * (patch_div_s + 1) + index_u]; - - // Tessellate - vert.pos = tess_pos.SampleV(wv.weights); - if (sampleCol) { - vert.color_32 = tess_col.SampleV(wv.weights).ToRGBA(); - } else { - vert.color_32 = spatch.defcolor; - } - if (sampleTex) { - tess_tex.SampleV(wv.weights).Write(vert.uv); - } else { - // Generate texcoord - vert.uv[0] = patch_u + tile_u * inv_u; - vert.uv[1] = patch_v + tile_v * inv_v; - } - if (sampleNrm) { - const Vec3f derivU = tess_nrm.SampleV(wv.weights); - const Vec3f derivV = tess_pos.SampleV(wv.derivs); - - vert.nrm = Cross(derivU, derivV).Normalized(useSSE4); - if (spatch.patchFacing) - vert.nrm *= -1.0f; - } else { - vert.nrm.SetZero(); - } - } - } - } - } - - BuildIndex(indices, count, patch_div_s, patch_div_t, spatch.primType); -} - -// Define class TemplateParameterDispatcherTess -TEMPLATE_PARAMETER_DISPATCHER(Tess, SplinePatchFullQuality); - -void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, SplinePatchLocal &spatch, u32 origVertType, int maxVertices) { - using TessFunc = void(*)(u8 *&, u16 *, int &, const SplinePatchLocal &); - constexpr int NumParams = 4; - static TemplateParameterDispatcherTess dispatcher; // Initialize only once - - const bool params[NumParams] = { - (origVertType & GE_VTYPE_NRM_MASK) != 0, - (origVertType & GE_VTYPE_COL_MASK) != 0, - (origVertType & GE_VTYPE_TC_MASK) != 0, - cpu_info.bSSE4_1, - }; - TessFunc func = dispatcher.GetFunc(params); - - switch (g_Config.iSplineBezierQuality) { - case LOW_QUALITY: - spatch.tess_u = 2; - spatch.tess_v = 2; - break; - case MEDIUM_QUALITY: - // Don't cut below 2, though. - if (spatch.tess_u > 2) spatch.tess_u = HALF_CEIL(spatch.tess_u); - if (spatch.tess_v > 2) spatch.tess_v = HALF_CEIL(spatch.tess_v); - // Pass through - case HIGH_QUALITY: - int num_patches_u = spatch.count_u - 3; - int num_patches_v = spatch.count_v - 3; - // Downsample until it fits, in case crazy tessellation factors are sent. - while ((num_patches_u * spatch.tess_u + 1) * (num_patches_v * spatch.tess_v + 1) > maxVertices) { - spatch.tess_u--; - spatch.tess_v--; - } - break; - } - - (*func)(dest, indices, count, spatch); -} - // Tessellate single patch (4x4 control points) template class Tessellator { @@ -468,85 +345,6 @@ public: } }; -static void _BezierPatchHighQuality(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType) { - const float inv_u = 1.0f / (float)tess_u; - const float inv_v = 1.0f / (float)tess_v; - - // First compute all the vertices and put them in an array - SimpleVertex *&vertices = (SimpleVertex*&)dest; - - const bool sampleNrm = (origVertType & GE_VTYPE_NRM_MASK) != 0; - const bool sampleCol = (origVertType & GE_VTYPE_COL_MASK) != 0; - const bool sampleTex = (origVertType & GE_VTYPE_TC_MASK) != 0; - - Weight2D weights(bezierWeightsCache, tess_u, tess_v); - - int num_patches_u = (patch.count_u - 1) / 3; - int num_patches_v = (patch.count_v - 1) / 3; - for (int patch_u = 0; patch_u < num_patches_u; ++patch_u) { - for (int patch_v = 0; patch_v < num_patches_v; ++patch_v) { - - // Prepare 4x4 control points to tessellate - const int idx = patch_v * 3 * patch.count_u + patch_u * 3; - const int idx_v[4] = { idx, idx + patch.count_u, idx + patch.count_u * 2, idx + patch.count_u * 3 }; - Tessellator tess_pos(patch.pos, idx_v); - Tessellator tess_col(patch.col, idx_v); - Tessellator tess_tex(patch.tex, idx_v); - Tessellator tess_nrm(patch.pos, idx_v); - - for (int tile_u = 0; tile_u < tess_u + 1; ++tile_u) { - const Weight &wu = weights.u[tile_u]; - - // Pre-tessellate U lines - tess_pos.SampleU(wu.weights); - if (sampleCol) - tess_col.SampleU(wu.weights); - if (sampleTex) - tess_tex.SampleU(wu.weights); - if (sampleNrm) - tess_nrm.SampleU(wu.derivs); - - for (int tile_v = 0; tile_v < tess_v + 1; ++tile_v) { - const Weight &wv = weights.v[tile_v]; - - SimpleVertex &vert = vertices[tile_v * (tess_u + 1) + tile_u]; - - // Tessellate - vert.pos = tess_pos.SampleV(wv.weights); - if (sampleCol) { - vert.color_32 = tess_col.SampleV(wv.weights).ToRGBA(); - } else { - vert.color_32 = patch.defcolor; - } - if (sampleTex) { - tess_tex.SampleV(wv.weights).Write(vert.uv); - } else { - // Generate texcoord - vert.uv[0] = patch_u + tile_u * inv_u; - vert.uv[1] = patch_v + tile_v * inv_v; - } - if (sampleNrm) { - const Vec3f derivU = tess_nrm.SampleV(wv.weights); - const Vec3f derivV = tess_pos.SampleV(wv.derivs); - - vert.nrm = Cross(derivU, derivV).Normalized(); - if (patch.patchFacing) - vert.nrm *= -1.0f; - } else { - vert.nrm.SetZero(); - } - } - } - - int patch_index = patch_v * num_patches_u + patch_u; - int total = patch_index * (tess_u + 1) * (tess_v + 1); - BuildIndex(indices + count, count, tess_u, tess_v, patch.primType, total); - - dest += (tess_u + 1) * (tess_v + 1) * sizeof(SimpleVertex); - } - } -} - // Prepare mesh of one patch for "Instanced Tessellation". static void TessellateBezierPatchHardware(u8 *&dest, u16 *indices, int &count, int tess_u, int tess_v, GEPatchPrimType primType) { SimpleVertex *&vertices = (SimpleVertex*&)dest; @@ -567,31 +365,6 @@ static void TessellateBezierPatchHardware(u8 *&dest, u16 *indices, int &count, i BuildIndex(indices, count, tess_u, tess_v, primType); } -void TessellateBezierPatch(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType, int maxVertices) { - switch (g_Config.iSplineBezierQuality) { - case LOW_QUALITY: - tess_u = 2; - tess_v = 2; - break; - case MEDIUM_QUALITY: - // Don't cut below 2, though. - if (tess_u > 2) tess_u = HALF_CEIL(tess_u); - if (tess_v > 2) tess_v = HALF_CEIL(tess_v); - // Pass through - case HIGH_QUALITY: - int num_patches_u = (patch.count_u - 1) / 3; - int num_patches_v = (patch.count_v - 1) / 3; - // Downsample until it fits, in case crazy tessellation factors are sent. - while ((tess_u + 1) * (tess_v + 1) * num_patches_u * num_patches_v > maxVertices) { - tess_u--; - tess_v--; - } - break; - } - - _BezierPatchHighQuality(dest, indices, count, tess_u, tess_v, patch, origVertType); -} - class SimpleBufferManager { private: u8 *buf_; @@ -612,6 +385,129 @@ public: } }; +template +class SubdivisionSurface { +private: + Vec3f *pos; + Vec4f *col; + Vec2f *tex; + u32_le defcolor; + const Patch &patch; + const Weight2D &weights; +public: + SubdivisionSurface(SimpleBufferManager &managedBuf, const SimpleVertex *const *points, const Patch &patch, const Weight2D &weights) + : patch(patch), weights(weights) + { + int size = patch.count_u * patch.count_v; + pos = (Vec3f *)managedBuf.Allocate(sizeof(Vec3f) * size); + tex = (Vec2f *)managedBuf.Allocate(sizeof(Vec2f) * size); + col = (Vec4f *)managedBuf.Allocate(sizeof(Vec4f) * size); + for (int idx = 0; idx < size; ++idx) { + pos[idx] = Vec3f(points[idx]->pos); + tex[idx] = Vec2f(points[idx]->uv); + col[idx] = Vec4f::FromRGBA(points[idx]->color_32); + } + defcolor = points[0]->color_32; + } + + template + void Tessellate(SimpleVertex *vertices, u16 *indices, int &count) { + const float inv_u = 1.0f / (float)patch.tess_u; + 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); + for (int patch_v = 0; patch_v < patch.num_patches_v; ++patch_v) { + const int tess_v = patch.GetTessV(patch_v); + + // Prepare 4x4 control points to tessellate + const int idx = patch.GetPointIndex(patch_u, patch_v); + const int idx_v[4] = { idx, idx + patch.count_u, idx + patch.count_u * 2, idx + patch.count_u * 3 }; + Tessellator tess_pos(pos, idx_v); + Tessellator tess_col(col, idx_v); + Tessellator tess_tex(tex, idx_v); + Tessellator tess_nrm(pos, idx_v); + + for (int tile_u = 0; tile_u < tess_u; ++tile_u) { + const int index_u = patch.GetIndexU(patch_u, tile_u); + const Weight &wu = weights.u[index_u]; + + // Pre-tessellate U lines + tess_pos.SampleU(wu.weights); + if (sampleCol) + tess_col.SampleU(wu.weights); + if (sampleTex) + tess_tex.SampleU(wu.weights); + if (sampleNrm) + tess_nrm.SampleU(wu.derivs); + + for (int tile_v = 0; tile_v < tess_v; ++tile_v) { + const int index_v = patch.GetIndexV(patch_v, tile_v); + const Weight &wv = weights.v[index_v]; + + SimpleVertex &vert = vertices[patch.GetIndex(index_u, index_v, patch_u, patch_v)]; + + // Tessellate + vert.pos = tess_pos.SampleV(wv.weights); + if (sampleCol) { + vert.color_32 = tess_col.SampleV(wv.weights).ToRGBA(); + } else { + vert.color_32 = defcolor; + } + if (sampleTex) { + tess_tex.SampleV(wv.weights).Write(vert.uv); + } else { + // Generate texcoord + vert.uv[0] = patch_u + tile_u * inv_u; + vert.uv[1] = patch_v + tile_v * inv_v; + } + if (sampleNrm) { + const Vec3f derivU = tess_nrm.SampleV(wv.weights); + const Vec3f derivV = tess_pos.SampleV(wv.derivs); + + vert.nrm = Cross(derivU, derivV).Normalized(useSSE4); + if (patch.patchFacing) + vert.nrm *= -1.0f; + } else { + vert.nrm.SetZero(); + } + } + } + } + } + + patch.BuildIndex(indices, count); + } + + // Define class TemplateParameterDispatcherTess + TEMPLATE_PARAMETER_DISPATCHER(Tess, SubdivisionSurface::Tessellate); + + void Tessellate(SimpleVertex *vertices, u16 *indices, int &count, u32 origVertType) { + using TessFunc = void(SubdivisionSurface::*)(SimpleVertex *, u16 *, int &); + constexpr int NumParams = 4; + static TemplateParameterDispatcherTess dispatcher; // Initialize only once + + const bool params[NumParams] = { + (origVertType & GE_VTYPE_NRM_MASK) != 0, + (origVertType & GE_VTYPE_COL_MASK) != 0, + (origVertType & GE_VTYPE_TC_MASK) != 0, + cpu_info.bSSE4_1, + }; + TessFunc func = dispatcher.GetFunc(params); + (this->*func)(vertices, indices, count); + } +}; + +template +static void SoftwareTessellation(SimpleVertex *vertices, u16 *indices, int &count, const Patch &patch, int origVertType, const SimpleVertex *const *points, SimpleBufferManager &managedBuf, Cache &weightsCache) { + u32 key_u = weightsCache.ToKey(patch.tess_u, patch.count_u, patch.type_u); + u32 key_v = weightsCache.ToKey(patch.tess_v, patch.count_v, patch.type_v); + Weight2D weights(weightsCache, key_u, key_v); + + SubdivisionSurface surface(managedBuf, points, patch, weights); + surface.Tessellate(vertices, indices, count, origVertType); +} + // This maps GEPatchPrimType to GEPrimitiveType. const GEPrimitiveType primType[] = { GE_PRIM_TRIANGLES, GE_PRIM_LINES, GE_PRIM_POINTS, GE_PRIM_POINTS }; @@ -667,25 +563,18 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi patch.type_v = type_v; patch.count_u = count_u; patch.count_v = count_v; + patch.num_patches_u = count_u - 3; + patch.num_patches_v = count_v - 3; patch.primType = prim_type; patch.patchFacing = patchFacing; - patch.defcolor = points[0]->color_32; if (CanUseHardwareTessellation(prim_type)) { tessDataTransfer->SendDataToShader(points, count_u * count_v, origVertType); TessellateSplinePatchHardware(dest, quadIndices_, count, patch); numPatches = (count_u - 3) * (count_v - 3); } else { - patch.pos = (Vec3f *)managedBuf.Allocate(sizeof(Vec3f) * count_u * count_v); - patch.tex = (Vec2f *)managedBuf.Allocate(sizeof(Vec2f) * count_u * count_v); - patch.col = (Vec4f *)managedBuf.Allocate(sizeof(Vec4f) * count_u * count_v); - for (int idx = 0; idx < count_u * count_v; idx++) { - patch.pos[idx] = Vec3f(points[idx]->pos); - patch.tex[idx] = Vec2f(points[idx]->uv); - patch.col[idx] = Vec4f::FromRGBA(points[idx]->color_32); - } - int maxVertexCount = SPLINE_BUFFER_SIZE / vertexSize; - TessellateSplinePatch(dest, quadIndices_, count, patch, origVertType, maxVertexCount); + patch.Init(SPLINE_BUFFER_SIZE / vertexSize); + SoftwareTessellation((SimpleVertex *)splineBuffer, quadIndices_, count, patch, origVertType, points, managedBuf, splineWeightsCache); } u32 vertTypeWithIndex16 = (vertType & ~GE_VTYPE_IDX_MASK) | GE_VTYPE_IDX_16BIT; @@ -769,21 +658,17 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi numPatches = num_patches_u * num_patches_v; } else { BezierPatch patch; + patch.tess_u = tess_u; + patch.tess_v = tess_v; patch.count_u = count_u; patch.count_v = count_v; + patch.num_patches_u = (count_u - 1) / 3; + patch.num_patches_v = (count_v - 1) / 3; patch.primType = prim_type; patch.patchFacing = patchFacing; - patch.defcolor = points[0]->color_32; - patch.pos = (Vec3f *)managedBuf.Allocate(sizeof(Vec3f) * count_u * count_v); - patch.tex = (Vec2f *)managedBuf.Allocate(sizeof(Vec2f) * count_u * count_v); - patch.col = (Vec4f *)managedBuf.Allocate(sizeof(Vec4f) * count_u * count_v); - for (int idx = 0; idx < count_u * count_v; idx++) { - patch.pos[idx] = Vec3f(points[idx]->pos); - patch.tex[idx] = Vec2f(points[idx]->uv); - patch.col[idx] = Vec4f::FromRGBA(points[idx]->color_32); - } - int maxVertices = SPLINE_BUFFER_SIZE / vertexSize; - TessellateBezierPatch(dest, inds, count, tess_u, tess_v, patch, origVertType, maxVertices); + + patch.Init(SPLINE_BUFFER_SIZE / vertexSize); + SoftwareTessellation((SimpleVertex *)splineBuffer, quadIndices_, count, patch, origVertType, points, managedBuf, bezierWeightsCache); } u32 vertTypeWithIndex16 = (vertType & ~GE_VTYPE_IDX_MASK) | GE_VTYPE_IDX_16BIT; diff --git a/GPU/Common/SplineCommon.h b/GPU/Common/SplineCommon.h index bc9fb06dce..cb0b2897fd 100644 --- a/GPU/Common/SplineCommon.h +++ b/GPU/Common/SplineCommon.h @@ -22,6 +22,8 @@ #include "GPU/Math3D.h" #include "GPU/ge_constants.h" +#define HALF_CEIL(x) (x + 1) / 2 // Integer ceil = (int)ceil((float)x / 2.0f) + // PSP compatible format so we can use the end of the pipeline in beziers etc struct SimpleVertex { float uv[2]; @@ -33,38 +35,126 @@ struct SimpleVertex { Vec3Packedf pos; }; +void BuildIndex(u16 *indices, int &count, int num_u, int num_v, GEPatchPrimType prim_type, int total = 0); + +enum SplineQuality { + LOW_QUALITY = 0, + MEDIUM_QUALITY = 1, + HIGH_QUALITY = 2, +}; + // We decode all vertices into a common format for easy interpolation and stuff. // Not fast but can be optimized later. struct BezierPatch { - Vec3f *pos; - Vec4f *col; - Vec2f *tex; - u32_le defcolor; - int count_u; - int count_v; - GEPatchPrimType primType; - bool patchFacing; -}; - -struct SplinePatchLocal { - Vec3f *pos; - Vec4f *col; - Vec2f *tex; - u32_le defcolor; int tess_u; int tess_v; int count_u; int count_v; int type_u; int type_v; - bool patchFacing; + int num_patches_u; + int num_patches_v; GEPatchPrimType primType; + bool patchFacing; + + void Init(int maxVertices) { + switch (g_Config.iSplineBezierQuality) { + case LOW_QUALITY: + tess_u = 2; + tess_v = 2; + break; + case MEDIUM_QUALITY: + // Don't cut below 2, though. + if (tess_u > 2) tess_u = HALF_CEIL(tess_u); + if (tess_v > 2) tess_v = HALF_CEIL(tess_v); + // Pass through + case HIGH_QUALITY: + // Downsample until it fits, in case crazy tessellation factors are sent. + while ((tess_u + 1) * (tess_v + 1) * num_patches_u * num_patches_v > maxVertices) { + tess_u--; + tess_v--; + } + break; + } + } + + int GetTessU(int patch_u) const { return tess_u + 1; } + int GetTessV(int patch_v) const { return tess_v + 1; } + + int GetPointIndex(int patch_u, int patch_v) const { return patch_v * 3 * count_u + patch_u * 3;} + + int GetIndexU(int patch_u, int tile_u) const { return tile_u; } + int GetIndexV(int patch_v, int tile_v) const { return tile_v; } + + int GetPatchIndex(int patch_u, int patch_v) const { return patch_v * num_patches_u + patch_u;} + int GetIndex(int index_u, int index_v, int patch_u, int patch_v) const { + return index_v * (tess_u + 1) + index_u + (tess_u + 1) * (tess_v + 1) * GetPatchIndex(patch_u, patch_v); + } + + void BuildIndex(u16 *indices, int &count) const { + for (int patch_u = 0; patch_u < num_patches_u; ++patch_u) { + for (int patch_v = 0; patch_v < num_patches_v; ++patch_v) { + int patch_index = patch_v * num_patches_u + patch_u; + int total = patch_index * (tess_u + 1) * (tess_v + 1); + ::BuildIndex(indices + count, count, tess_u, tess_v, primType, total); + } + } + } }; -enum SplineQuality { - LOW_QUALITY = 0, - MEDIUM_QUALITY = 1, - HIGH_QUALITY = 2, +struct SplinePatchLocal { + int tess_u; + int tess_v; + int count_u; + int count_v; + int type_u; + int type_v; + int num_patches_u; + int num_patches_v; + int num_divisions_u; + int num_divisions_v; + bool patchFacing; + GEPatchPrimType primType; + + void Init(int maxVertices) { + switch (g_Config.iSplineBezierQuality) { + case LOW_QUALITY: + tess_u = 2; + tess_v = 2; + break; + case MEDIUM_QUALITY: + // Don't cut below 2, though. + if (tess_u > 2) tess_u = HALF_CEIL(tess_u); + if (tess_v > 2) tess_v = HALF_CEIL(tess_v); + // Pass through + case HIGH_QUALITY: + // Downsample until it fits, in case crazy tessellation factors are sent. + while ((num_patches_u * tess_u + 1) * (num_patches_v * tess_v + 1) > maxVertices) { + tess_u--; + tess_v--; + } + break; + } + + num_divisions_u = num_patches_u * tess_u; + 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 GetPointIndex(int patch_u, int patch_v) const { return patch_v * count_u + patch_u;} + + int GetIndexU(int patch_u, int tile_u) const { return patch_u * tess_u + tile_u; } + int GetIndexV(int patch_v, int tile_v) const { return patch_v * tess_v + tile_v; } + + int GetIndex(int index_u, int index_v, int patch_u, int patch_v) const { + return index_v * (num_divisions_u + 1) + index_u; + } + + void BuildIndex(u16 *indices, int &count) const { + ::BuildIndex(indices, count, num_divisions_u, num_divisions_v, primType); + } }; bool CanUseHardwareTessellation(GEPatchPrimType prim);void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, SplinePatchLocal &spatch, u32 origVertType, int maxVertices);void TessellateBezierPatch(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType, int maxVertices); From 3c0fb44f2e3510fd373dcb43d9d3e4d7ad4d2a99 Mon Sep 17 00:00:00 2001 From: xebra Date: Wed, 11 Jul 2018 01:09:20 +0900 Subject: [PATCH 042/347] [spline/bezier]Improve hwtess to use cached weights. --- GPU/Common/DrawEngineCommon.h | 9 +- GPU/Common/ShaderUniforms.cpp | 2 +- GPU/Common/SplineCommon.cpp | 119 ++++++-------- GPU/Common/SplineCommon.h | 40 ++++- GPU/D3D11/DrawEngineD3D11.cpp | 55 +++++-- GPU/D3D11/DrawEngineD3D11.h | 16 +- GPU/Directx9/DrawEngineDX9.cpp | 2 +- GPU/Directx9/DrawEngineDX9.h | 2 +- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 174 +++++--------------- GPU/GLES/DrawEngineGLES.cpp | 24 ++- GPU/GLES/DrawEngineGLES.h | 5 +- GPU/GLES/ShaderManagerGLES.cpp | 21 ++- GPU/GLES/ShaderManagerGLES.h | 6 +- GPU/GLES/VertexShaderGeneratorGLES.cpp | 163 +++++-------------- GPU/GPUCommon.cpp | 23 +-- GPU/GPUState.h | 8 +- GPU/Vulkan/DrawEngineVulkan.cpp | 70 +++++--- GPU/Vulkan/DrawEngineVulkan.h | 19 +-- GPU/Vulkan/VertexShaderGeneratorVulkan.cpp | 180 ++++++--------------- 19 files changed, 386 insertions(+), 552 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 39c8647ce4..de8a467f4a 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -27,6 +27,7 @@ #include "GPU/Common/GPUDebugInterface.h" #include "GPU/Common/IndexGenerator.h" #include "GPU/Common/VertexDecoderCommon.h" +#include "GPU/Common/SplineCommon.h" class VertexDecoder; @@ -173,17 +174,11 @@ protected: // Hardware tessellation int numPatches; class TessellationDataTransfer { - protected: - // TODO: These aren't used by all backends. - int prevSize; - int prevSizeTex; - int prevSizeCol; public: virtual ~TessellationDataTransfer() {} void CopyControlPoints(float *pos, float *tex, float *col, int posStride, int texStride, int colStride, const SimpleVertex *const *points, int size, u32 vertType); // Send spline/bezier's control points to vertex shader through floating point texture. - virtual void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType) = 0; - virtual void EndFrame() {} + virtual void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) = 0; }; TessellationDataTransfer *tessDataTransfer; }; diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index e0f6719502..6fcdfa311e 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -240,7 +240,7 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView } if (dirtyUniforms & DIRTY_BEZIERSPLINE) { - ub->spline_counts = BytesToUint32(gstate_c.spline_count_u, gstate_c.spline_count_v, gstate_c.spline_type_u, gstate_c.spline_type_v); + ub->spline_counts = BytesToUint32(gstate_c.spline_num_patches_u, gstate_c.spline_num_patches_v, gstate_c.spline_tess_u, gstate_c.spline_tess_v); } if (dirtyUniforms & DIRTY_DEPAL) { diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 558570f3ea..ea8776ccb8 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -22,7 +22,6 @@ #include "Common/CPUDetect.h" #include "Common/MemoryUtil.h" -#include "Core/Config.h" #include "GPU/Common/GPUStateUtils.h" #include "GPU/Common/SplineCommon.h" @@ -60,32 +59,28 @@ static void BuildIndex(u16 *indices, int &count, int num_u, int num_v, GEPatchPr } } -struct Weight { - float weights[4], derivs[4]; -}; - class Bezier3DWeight { private: void CalcWeights(float t, Weight &w) { // Bernstein 3D basis polynomial - w.weights[0] = (1 - t) * (1 - t) * (1 - t); - w.weights[1] = 3 * t * (1 - t) * (1 - t); - w.weights[2] = 3 * t * t * (1 - t); - w.weights[3] = t * t * t; + w.basis[0] = (1 - t) * (1 - t) * (1 - t); + w.basis[1] = 3 * t * (1 - t) * (1 - t); + w.basis[2] = 3 * t * t * (1 - t); + w.basis[3] = t * t * t; // Derivative - w.derivs[0] = -3 * (1 - t) * (1 - t); - w.derivs[1] = 9 * t * t - 12 * t + 3; - w.derivs[2] = 3 * (2 - 3 * t) * t; - w.derivs[3] = 3 * t * t; + w.deriv[0] = -3 * (1 - t) * (1 - t); + w.deriv[1] = 9 * t * t - 12 * t + 3; + w.deriv[2] = 3 * (2 - 3 * t) * t; + w.deriv[3] = 3 * t * t; } public: Weight *CalcWeightsAll(u32 key) { int tess = (int)key; Weight *weights = new Weight[tess + 1]; - const float inv_u = 1.0f / (float)tess; + const float inv_tess = 1.0f / (float)tess; for (int i = 0; i < tess + 1; ++i) { - const float t = (float)i * inv_u; + const float t = (float)i * inv_tess; CalcWeights(t, weights[i]); } return weights; @@ -182,10 +177,10 @@ private: float c = (1 - f41) * (1 - f42); float d = (f42 * f52); #endif - w.weights[0] = a * (1 - f32); // (1-f30)*(1-f31)*(1-f32) - w.weights[1] = 1 - a - b + ((a + b + c - 1) * f32); - w.weights[2] = b + ((1 - b - c - d) * f32); - w.weights[3] = d * f32; // f32*f42*f52 + w.basis[0] = a * (1 - f32); // (1-f30)*(1-f31)*(1-f32) + w.basis[1] = 1 - a - b + ((a + b + c - 1) * f32); + w.basis[2] = b + ((1 - b - c - d) * f32); + w.basis[3] = d * f32; // f32*f42*f52 // Derivative float i1 = (1 - f31) * (1 - f32); @@ -196,10 +191,10 @@ private: float f241 = i2 * div._4_1; float f352 = i3 * div._5_2; - w.derivs[0] = 3 * (0 - f130); - w.derivs[1] = 3 * (f130 - f241); - w.derivs[2] = 3 * (f241 - f352); - w.derivs[3] = 3 * (f352 - 0); + w.deriv[0] = 3 * (0 - f130); + w.deriv[1] = 3 * (f130 - f241); + w.deriv[2] = 3 * (f241 - f352); + w.deriv[3] = 3 * (f352 - 0); } public: Weight *CalcWeightsAll(u32 key) { @@ -238,38 +233,9 @@ public: } }; -template -class WeightCache : public T { -private: - std::unordered_map weightsCache; -public: - Weight* operator [] (u32 key) { - Weight *&weights = weightsCache[key]; - if (!weights) - weights = CalcWeightsAll(key); - return weights; - } - - void Clear() { - for (auto it : weightsCache) - delete[] it.second; - weightsCache.clear(); - } -}; - static WeightCache bezierWeightsCache; static WeightCache splineWeightsCache; -struct Weight2D { - const Weight *u, *v; - - template - Weight2D(WeightCache &cache, u32 key_u, u32 key_v) { - u = cache[key_u]; - v = (key_u != key_v) ? cache[key_v] : u; // Use same weights if u == v - } -}; - void DrawEngineCommon::ClearSplineBezierWeights() { bezierWeightsCache.Clear(); splineWeightsCache.Clear(); @@ -293,13 +259,11 @@ static void TessellateSplinePatchHardware(u8 *&dest, u16 *indices, int &count, c for (int tile_v = 0; tile_v < spatch.tess_v + 1; ++tile_v) { for (int tile_u = 0; tile_u < spatch.tess_u + 1; ++tile_u) { SimpleVertex &vert = vertices[tile_v * (spatch.tess_u + 1) + tile_u]; - vert.pos.x = (float)tile_u * inv_u; - vert.pos.y = (float)tile_v * inv_v; - - // TODO: Move to shader uniform and unify this method spline and bezier if necessary. - // For compute normal - vert.nrm.x = inv_u; - vert.nrm.y = inv_v; + vert.pos.x = (float)tile_u; + vert.pos.y = (float)tile_v; + // For texcoord generation + vert.nrm.x = (float)tile_u * inv_u; + vert.nrm.y = (float)tile_v * inv_v; } } @@ -357,8 +321,11 @@ static void TessellateBezierPatchHardware(u8 *&dest, u16 *indices, int &count, i for (int tile_u = 0; tile_u < tess_u + 1; ++tile_u) { SimpleVertex &vert = vertices[tile_v * (tess_u + 1) + tile_u]; - vert.pos.x = (float)tile_u * inv_u; - vert.pos.y = (float)tile_v * inv_v; + vert.pos.x = (float)tile_u; + vert.pos.y = (float)tile_v; + // For texcoord generation + vert.nrm.x = (float)tile_u * inv_u; + vert.nrm.y = (float)tile_v * inv_v; } } @@ -433,13 +400,13 @@ public: const Weight &wu = weights.u[index_u]; // Pre-tessellate U lines - tess_pos.SampleU(wu.weights); + tess_pos.SampleU(wu.basis); if (sampleCol) - tess_col.SampleU(wu.weights); + tess_col.SampleU(wu.basis); if (sampleTex) - tess_tex.SampleU(wu.weights); + tess_tex.SampleU(wu.basis); if (sampleNrm) - tess_nrm.SampleU(wu.derivs); + tess_nrm.SampleU(wu.deriv); for (int tile_v = 0; tile_v < tess_v; ++tile_v) { const int index_v = patch.GetIndexV(patch_v, tile_v); @@ -448,22 +415,22 @@ public: SimpleVertex &vert = vertices[patch.GetIndex(index_u, index_v, patch_u, patch_v)]; // Tessellate - vert.pos = tess_pos.SampleV(wv.weights); + vert.pos = tess_pos.SampleV(wv.basis); if (sampleCol) { - vert.color_32 = tess_col.SampleV(wv.weights).ToRGBA(); + vert.color_32 = tess_col.SampleV(wv.basis).ToRGBA(); } else { vert.color_32 = defcolor; } if (sampleTex) { - tess_tex.SampleV(wv.weights).Write(vert.uv); + tess_tex.SampleV(wv.basis).Write(vert.uv); } else { // Generate texcoord vert.uv[0] = patch_u + tile_u * inv_u; vert.uv[1] = patch_v + tile_v * inv_v; } if (sampleNrm) { - const Vec3f derivU = tess_nrm.SampleV(wv.weights); - const Vec3f derivV = tess_pos.SampleV(wv.derivs); + const Vec3f derivU = tess_nrm.SampleV(wv.basis); + const Vec3f derivV = tess_pos.SampleV(wv.deriv); vert.nrm = Cross(derivU, derivV).Normalized(useSSE4); if (patch.patchFacing) @@ -569,7 +536,12 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi patch.patchFacing = patchFacing; if (CanUseHardwareTessellation(prim_type)) { - tessDataTransfer->SendDataToShader(points, count_u * count_v, origVertType); + const u32 key_u = splineWeightsCache.ToKey(tess_u, count_u, type_u); + const u32 key_v = splineWeightsCache.ToKey(tess_v, count_v, type_v); + Weight2D weights(splineWeightsCache, key_u, key_v); + weights.size_u = (count_u - 3) * tess_u + 1; + weights.size_v = (count_v - 3) * tess_v + 1; + tessDataTransfer->SendDataToShader(points, count_u * count_v, origVertType, weights); TessellateSplinePatchHardware(dest, quadIndices_, count, patch); numPatches = (count_u - 3) * (count_v - 3); } else { @@ -653,7 +625,10 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi int num_patches_u = (count_u - 1) / 3; int num_patches_v = (count_v - 1) / 3; if (CanUseHardwareTessellation(prim_type)) { - tessDataTransfer->SendDataToShader(points, count_u * count_v, origVertType); + Weight2D weights(bezierWeightsCache, tess_u, tess_v); + weights.size_u = tess_u + 1; + weights.size_v = tess_v + 1; + tessDataTransfer->SendDataToShader(points, count_u * count_v, origVertType, weights); TessellateBezierPatchHardware(dest, inds, count, tess_u, tess_v, prim_type); numPatches = num_patches_u * num_patches_v; } else { diff --git a/GPU/Common/SplineCommon.h b/GPU/Common/SplineCommon.h index cb0b2897fd..b15bd4d2e2 100644 --- a/GPU/Common/SplineCommon.h +++ b/GPU/Common/SplineCommon.h @@ -16,11 +16,13 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #pragma once +#include #include "Common/CommonTypes.h" #include "Common/Swap.h" #include "GPU/Math3D.h" #include "GPU/ge_constants.h" +#include "Core/Config.h" #define HALF_CEIL(x) (x + 1) / 2 // Integer ceil = (int)ceil((float)x / 2.0f) @@ -157,7 +159,43 @@ struct SplinePatchLocal { } }; -bool CanUseHardwareTessellation(GEPatchPrimType prim);void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, SplinePatchLocal &spatch, u32 origVertType, int maxVertices);void TessellateBezierPatch(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType, int maxVertices); +struct Weight { + float basis[4], deriv[4]; +}; + +template +class WeightCache : public T { +private: + std::unordered_map weightsCache; +public: + Weight* operator [] (u32 key) { + Weight *&weights = weightsCache[key]; + if (!weights) + weights = CalcWeightsAll(key); + return weights; + } + + void Clear() { + for (auto it : weightsCache) + delete[] it.second; + weightsCache.clear(); + } +}; + +struct Weight2D { + const Weight *u, *v; + int size_u, size_v; + + template + Weight2D(WeightCache &cache, u32 key_u, u32 key_v) { + u = cache[key_u]; + v = (key_u != key_v) ? cache[key_v] : u; // Use same weights if u == v + } +}; + +bool CanUseHardwareTessellation(GEPatchPrimType prim); +void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, SplinePatchLocal &spatch, u32 origVertType, int maxVertices); +void TessellateBezierPatch(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType, int maxVertices); #define TEMPLATE_PARAMETER_DISPATCHER(NAME, FUNCNAME) \ template \ diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 63b753d1ea..1a77479851 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -692,7 +692,7 @@ rotateVBO: GPUDebug::NotifyDraw(); } -void DrawEngineD3D11::TessellationDataTransferD3D11::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType) { +void DrawEngineD3D11::TessellationDataTransferD3D11::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) { struct TessData { float pos[3]; float pad1; float uv[2]; float pad2[2]; @@ -701,19 +701,19 @@ void DrawEngineD3D11::TessellationDataTransferD3D11::SendDataToShader(const Simp if (prevSize < size) { prevSize = size; - if (buf) { - buf->Release(); - view->Release(); + if (buf[0]) { + buf[0]->Release(); + view[0]->Release(); } desc.ByteWidth = size * sizeof(TessData); desc.StructureByteStride = sizeof(TessData); - device_->CreateBuffer(&desc, nullptr, &buf); - device_->CreateShaderResourceView(buf, 0, &view); - context_->VSSetShaderResources(0, 1, &view); + device_->CreateBuffer(&desc, nullptr, &buf[0]); + device_->CreateShaderResourceView(buf[0], nullptr, &view[0]); + context_->VSSetShaderResources(0, 1, &view[0]); } D3D11_MAPPED_SUBRESOURCE map; - context_->Map(buf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + context_->Map(buf[0], 0, D3D11_MAP_WRITE_DISCARD, 0, &map); uint8_t *data = (uint8_t *)map.pData; float *pos = (float *)(data); @@ -725,5 +725,42 @@ void DrawEngineD3D11::TessellationDataTransferD3D11::SendDataToShader(const Simp CopyControlPoints(pos, tex, col, stride, stride, stride, points, size, vertType); - context_->Unmap(buf, 0); + context_->Unmap(buf[0], 0); + + + // Weights U + if (prevSizeWeights[0] < weights.size_u) { + prevSizeWeights[0] = weights.size_u; + if (buf[1]) { + buf[1]->Release(); + view[1]->Release(); + } + desc.ByteWidth = weights.size_u * sizeof(Weight); + desc.StructureByteStride = sizeof(Weight); + + device_->CreateBuffer(&desc, nullptr, &buf[1]); + device_->CreateShaderResourceView(buf[1], nullptr, &view[1]); + context_->VSSetShaderResources(1, 1, &view[1]); + } + context_->Map(buf[1], 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, weights.u, weights.size_u * sizeof(Weight)); + context_->Unmap(buf[1], 0); + + // Weights V + if (prevSizeWeights[1] < weights.size_v) { + prevSizeWeights[1] = weights.size_v; + if (buf[2]) { + buf[2]->Release(); + view[2]->Release(); + } + desc.ByteWidth = weights.size_v * sizeof(Weight); + desc.StructureByteStride = sizeof(Weight); + + device_->CreateBuffer(&desc, nullptr, &buf[2]); + device_->CreateShaderResourceView(buf[2], nullptr, &view[2]); + context_->VSSetShaderResources(2, 1, &view[2]); + } + context_->Map(buf[2], 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, weights.v, weights.size_v * sizeof(Weight)); + context_->Unmap(buf[2], 0); } diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h index e64296dba1..c910e2d365 100644 --- a/GPU/D3D11/DrawEngineD3D11.h +++ b/GPU/D3D11/DrawEngineD3D11.h @@ -203,9 +203,11 @@ private: private: ID3D11DeviceContext *context_; ID3D11Device *device_; - ID3D11Buffer *buf; - ID3D11ShaderResourceView *view; + ID3D11Buffer *buf[3]; + ID3D11ShaderResourceView *view[3]; D3D11_BUFFER_DESC desc; + int prevSize = 0; + int prevSizeWeights[2] = {}; public: TessellationDataTransferD3D11(ID3D11DeviceContext *context, ID3D11Device *device) : TessellationDataTransfer(), context_(context), device_(device), buf(), view(), desc() { @@ -215,12 +217,14 @@ private: desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; } ~TessellationDataTransferD3D11() { - if (buf) { - buf->Release(); - view->Release(); + for (int i = 0; i < 3; ++i) { + if (buf[i]) { + buf[i]->Release(); + view[i]->Release(); + } } } - void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType) override; + void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) override; }; }; diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index f3f373f314..b7ad1027a9 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -624,7 +624,7 @@ rotateVBO: GPUDebug::NotifyDraw(); } -void DrawEngineDX9::TessellationDataTransferDX9::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType) { +void DrawEngineDX9::TessellationDataTransferDX9::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) { } } // namespace diff --git a/GPU/Directx9/DrawEngineDX9.h b/GPU/Directx9/DrawEngineDX9.h index 1c7c082e7d..be54128be2 100644 --- a/GPU/Directx9/DrawEngineDX9.h +++ b/GPU/Directx9/DrawEngineDX9.h @@ -166,7 +166,7 @@ private: } ~TessellationDataTransferDX9() { } - void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType) override; + void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) override; }; }; diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 51df62a015..62ad03c781 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -271,82 +271,32 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage WRITE(p, " float3 pos; float pad1;\n"); WRITE(p, " float2 tex; float2 pad2;\n"); WRITE(p, " float4 col;\n"); - WRITE(p, "};"); + WRITE(p, "};\n"); WRITE(p, "StructuredBuffer tess_data : register(t0);\n"); + + WRITE(p, "struct TessWeight {\n"); + WRITE(p, " float4 basis;\n"); + WRITE(p, " float4 deriv;\n"); + WRITE(p, "};\n"); + WRITE(p, "StructuredBuffer tess_weights_u : register(t1);\n"); + WRITE(p, "StructuredBuffer tess_weights_v : register(t2);\n"); } const char *init[3] = { "0.0, 0.0", "0.0, 0.0, 0.0", "0.0, 0.0, 0.0, 0.0" }; for (int i = 2; i <= 4; i++) { // Define 3 types float2, float3, float4 - WRITE(p, "float%d tess_sample(in float%d points[16], in float2 weights[4]) {\n", i, i); + WRITE(p, "float%d tess_sample(in float%d points[16], float4 weights_u, float4 weights_v) {\n", i, i); WRITE(p, " float%d pos = float%d(%s);\n", i, i, init[i - 2]); - WRITE(p, " for (int i = 0; i < 4; ++i) {\n"); - WRITE(p, " for (int j = 0; j < 4; ++j) {\n"); - WRITE(p, " float f = weights[j].x * weights[i].y;\n"); + WRITE(p, " for (int v = 0; v < 4; ++v) {\n"); + WRITE(p, " for (int u = 0; u < 4; ++u) {\n"); + WRITE(p, " float f = weights_u[u] * weights_v[v];\n"); WRITE(p, " if (f != 0.0)\n"); - WRITE(p, " pos = pos + f * points[i * 4 + j];\n"); + WRITE(p, " pos = pos + f * points[v * 4 + u];\n"); WRITE(p, " }\n"); WRITE(p, " }\n"); WRITE(p, " return pos;\n"); WRITE(p, "}\n"); } - if (doSpline) { - WRITE(p, "void spline_knot(int2 num_patches, int2 type, out float2 knot[6], int2 patch_pos) {\n"); - WRITE(p, " for (int i = 0; i < 6; ++i) {\n"); - WRITE(p, " knot[i] = float2(i + patch_pos.x - 2, i + patch_pos.y - 2);\n"); - WRITE(p, " }\n"); - // WRITE(p, " if ((type.x & 1) != 0) {\n"); - WRITE(p, " if ((type.x == 1) || (type.x == 3)) {\n"); - WRITE(p, " if (patch_pos.x <= 2)\n"); - WRITE(p, " knot[0].x = 0.0;\n"); - WRITE(p, " if (patch_pos.x <= 1)\n"); - WRITE(p, " knot[1].x = 0.0;\n"); - WRITE(p, " }\n"); - // WRITE(p, " if ((type.x & 2) != 0) {\n"); - WRITE(p, " if ((type.x == 2) || (type.x == 3)) {\n"); - WRITE(p, " if (patch_pos.x >= (num_patches.x - 2))\n"); - WRITE(p, " knot[5].x = num_patches.x;\n"); - WRITE(p, " if (patch_pos.x == (num_patches.x - 1))\n"); - WRITE(p, " knot[4].x = num_patches.x;\n"); - WRITE(p, " }\n"); - // WRITE(p, " if ((type.y & 1) != 0) {\n"); - WRITE(p, " if ((type.y == 1) || (type.y == 3)) {\n"); - WRITE(p, " if (patch_pos.y <= 2)\n"); - WRITE(p, " knot[0].y = 0.0;\n"); - WRITE(p, " if (patch_pos.y <= 1)\n"); - WRITE(p, " knot[1].y = 0.0;\n"); - WRITE(p, " }\n"); - // WRITE(p, " if ((type.y & 2) != 0) {\n"); - WRITE(p, " if ((type.y == 2) || (type.y == 3)) {\n"); - WRITE(p, " if (patch_pos.y >= (num_patches.y - 2))\n"); - WRITE(p, " knot[5].y = num_patches.y;\n"); - WRITE(p, " if (patch_pos.y == (num_patches.y - 1))\n"); - WRITE(p, " knot[4].y = num_patches.y;\n"); - WRITE(p, " }\n"); - WRITE(p, "}\n"); - - WRITE(p, "void spline_weight(float2 t, in float2 knot[6], out float2 weights[4]) {\n"); - // TODO: Maybe compilers could be coaxed into vectorizing this code without the above explicitly... - WRITE(p, " float2 t0 = (t - knot[0]);\n"); - WRITE(p, " float2 t1 = (t - knot[1]);\n"); - WRITE(p, " float2 t2 = (t - knot[2]);\n"); - // TODO: All our knots are integers so we should be able to get rid of these divisions (How?) - WRITE(p, " float2 f30 = t0 / (knot[3] - knot[0]);\n"); - WRITE(p, " float2 f41 = t1 / (knot[4] - knot[1]);\n"); - WRITE(p, " float2 f52 = t2 / (knot[5] - knot[2]);\n"); - WRITE(p, " float2 f31 = t1 / (knot[3] - knot[1]);\n"); - WRITE(p, " float2 f42 = t2 / (knot[4] - knot[2]);\n"); - WRITE(p, " float2 f32 = t2 / (knot[3] - knot[2]);\n"); - WRITE(p, " float2 a = (1.0 - f30)*(1.0 - f31);\n"); - WRITE(p, " float2 b = (f31*f41);\n"); - WRITE(p, " float2 c = (1.0 - f41)*(1.0 - f42);\n"); - WRITE(p, " float2 d = (f42*f52);\n"); - WRITE(p, " weights[0] = a - (a*f32);\n"); - WRITE(p, " weights[1] = 1.0 - a - b + ((a + b + c - 1.0)*f32);\n"); - WRITE(p, " weights[2] = b + ((1.0 - b - c - d)*f32);\n"); - WRITE(p, " weights[3] = d*f32;\n"); - WRITE(p, "}\n"); - } } WRITE(p, "VS_OUT main(VS_IN In) {\n"); @@ -398,20 +348,29 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage if (!enableBones) { // Hardware tessellation if (doSpline || doBezier) { - WRITE(p, " uint u_spline_count_u = u_spline_counts & 0xFF;\n"); - WRITE(p, " uint u_spline_count_v = (u_spline_counts >> 8) & 0xFF;\n"); - WRITE(p, " uint num_patches_u = %s;\n", doBezier ? "(u_spline_count_u - 1) / 3u" : "u_spline_count_u - 3"); - WRITE(p, " float2 tess_pos = In.position.xy;\n"); - WRITE(p, " int u = In.instanceId %% num_patches_u;\n"); - WRITE(p, " int v = In.instanceId / num_patches_u;\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"); + + 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, " 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, " 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) * u_spline_count_u + (%i + u%s);\n", i, doBezier ? " * 3" : "", j, doBezier ? " * 3" : ""); + 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); @@ -419,77 +378,32 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage WRITE(p, " _col[%i] = tess_data[index].col;\n", i * 4 + j); } } - WRITE(p, " float2 weights[4];\n"); - if (doBezier) { - // Bernstein 3D - WRITE(p, " weights[0] = (1.0 - tess_pos) * (1.0 - tess_pos) * (1.0 - tess_pos);\n"); - WRITE(p, " weights[1] = 3.0 * tess_pos * (1.0 - tess_pos) * (1.0 - tess_pos);\n"); - WRITE(p, " weights[2] = 3.0 * tess_pos * tess_pos * (1.0 - tess_pos);\n"); - WRITE(p, " weights[3] = tess_pos * tess_pos * tess_pos;\n"); - } else if (doSpline) { - WRITE(p, " int2 spline_num_patches = int2(u_spline_count_u - 3, u_spline_count_v - 3);\n"); - WRITE(p, " int u_spline_type_u = (u_spline_counts >> 16) & 0xFF;\n"); - WRITE(p, " int u_spline_type_v = (u_spline_counts >> 24) & 0xFF;\n"); - WRITE(p, " int2 spline_type = int2(u_spline_type_u, u_spline_type_v);\n"); - WRITE(p, " float2 knots[6];\n"); - WRITE(p, " spline_knot(spline_num_patches, spline_type, knots, patch_pos);\n"); - WRITE(p, " spline_weight(tess_pos + patch_pos, knots, weights);\n"); - } - WRITE(p, " float3 pos = tess_sample(_pos, weights);\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"); + + // 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, weights);\n"); + WRITE(p, " float2 tex = tess_sample(_tex, basis_u, basis_v);\n"); else - WRITE(p, " float2 tex = tess_pos + patch_pos;\n"); + WRITE(p, " float2 tex = In.normal.xy + float2(patch_pos);\n"); } if (hasColor) { if (hasColorTess) - WRITE(p, " float4 col = tess_sample(_col, weights);\n"); + WRITE(p, " float4 col = tess_sample(_col, basis_u, basis_v);\n"); else WRITE(p, " float4 col = tess_data[0].col;\n"); } if (hasNormal) { - // Curved surface is probably always need to compute normal(not sampling from control points) - if (doBezier) { - // Bernstein derivative - WRITE(p, " float2 bernderiv[4];\n"); - WRITE(p, " bernderiv[0] = -3.0 * (tess_pos - 1.0) * (tess_pos - 1.0); \n"); - WRITE(p, " bernderiv[1] = 9.0 * tess_pos * tess_pos - 12.0 * tess_pos + 3.0; \n"); - WRITE(p, " bernderiv[2] = 3.0 * (2.0 - 3.0 * tess_pos) * tess_pos; \n"); - WRITE(p, " bernderiv[3] = 3.0 * tess_pos * tess_pos; \n"); + // 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"); - WRITE(p, " float2 bernderiv_u[4];\n"); - WRITE(p, " float2 bernderiv_v[4];\n"); - WRITE(p, " for (int i = 0; i < 4; i++) {\n"); - WRITE(p, " bernderiv_u[i] = float2(bernderiv[i].x, weights[i].y);\n"); - WRITE(p, " bernderiv_v[i] = float2(weights[i].x, bernderiv[i].y);\n"); - WRITE(p, " }\n"); - - WRITE(p, " float3 du = tess_sample(_pos, bernderiv_u);\n"); - WRITE(p, " float3 dv = tess_sample(_pos, bernderiv_v);\n"); - } else if (doSpline) { - WRITE(p, " float2 tess_next_u = float2(In.normal.x, 0.0);\n"); - WRITE(p, " float2 tess_next_v = float2(0.0, In.normal.y);\n"); - // Right - WRITE(p, " float2 tess_pos_r = tess_pos + tess_next_u;\n"); - WRITE(p, " spline_weight(tess_pos_r + patch_pos, knots, weights);\n"); - WRITE(p, " float3 pos_r = tess_sample(_pos, weights);\n"); - // Left - WRITE(p, " float2 tess_pos_l = tess_pos - tess_next_u;\n"); - WRITE(p, " spline_weight(tess_pos_l + patch_pos, knots, weights);\n"); - WRITE(p, " float3 pos_l = tess_sample(_pos, weights);\n"); - // Down - WRITE(p, " float2 tess_pos_d = tess_pos + tess_next_v;\n"); - WRITE(p, " spline_weight(tess_pos_d + patch_pos, knots, weights);\n"); - WRITE(p, " float3 pos_d = tess_sample(_pos, weights);\n"); - // Up - WRITE(p, " float2 tess_pos_u = tess_pos - tess_next_v;\n"); - WRITE(p, " spline_weight(tess_pos_u + patch_pos, knots, weights);\n"); - WRITE(p, " float3 pos_u = tess_sample(_pos, weights);\n"); - - WRITE(p, " float3 du = pos_r - pos_l;\n"); - WRITE(p, " float3 dv = pos_d - pos_u;\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"); } diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 3d0a077a00..6fd3d68ced 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -87,7 +87,8 @@ DrawEngineGLES::DrawEngineGLES(Draw::DrawContext *draw) : vai_(256), draw_(draw) InitDeviceObjects(); - tessDataTransfer = new TessellationDataTransferGLES(render_); + tessDataTransferGLES = new TessellationDataTransferGLES(render_); + tessDataTransfer = tessDataTransferGLES; } DrawEngineGLES::~DrawEngineGLES() { @@ -166,7 +167,7 @@ void DrawEngineGLES::EndFrame() { FrameData &frameData = frameData_[render_->GetCurFrame()]; render_->EndPushBuffer(frameData.pushIndex); render_->EndPushBuffer(frameData.pushVertex); - tessDataTransfer->EndFrame(); + tessDataTransferGLES->EndFrame(); } struct GlTypeInfo { @@ -655,7 +656,7 @@ bool DrawEngineGLES::IsCodePtrVertexDecoder(const u8 *ptr) const { return decJitCache_->IsInSpace(ptr); } -void DrawEngineGLES::TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType) { +void DrawEngineGLES::TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) { bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0; bool hasTexCoord = (vertType & GE_VTYPE_TC_MASK) != 0; int sizeColor = hasColor ? size : 1; @@ -683,6 +684,23 @@ void DrawEngineGLES::TessellationDataTransferGLES::SendDataToShader(const Simple renderManager_->TextureSubImage(data_tex[0], 0, 0, 1, size, 1, GL_RGBA, GL_FLOAT, (u8 *)tex, GLRAllocType::NEW); // Color renderManager_->TextureSubImage(data_tex[0], 0, 0, 2, sizeColor, 1, GL_RGBA, GL_FLOAT, (u8 *)col, GLRAllocType::NEW); + + // Weight U + if (data_tex[1]) + renderManager_->DeleteTexture(data_tex[1]); + data_tex[1] = renderManager_->CreateTexture(GL_TEXTURE_2D); + renderManager_->TextureImage(data_tex[1], 0, weights.size_u * 2, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT, (uint8_t *)weights.u, GLRAllocType::NONE, false); + renderManager_->FinalizeTexture(data_tex[1], 0, false); + renderManager_->BindTexture(TEX_SLOT_SPLINE_WEIGHTS_U, data_tex[1]); + + // Weight V + if (data_tex[2]) + renderManager_->DeleteTexture(data_tex[2]); + data_tex[2] = renderManager_->CreateTexture(GL_TEXTURE_2D); + renderManager_->TextureImage(data_tex[2], 0, weights.size_v * 2, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT, (uint8_t *)weights.v, GLRAllocType::NONE, false); + renderManager_->FinalizeTexture(data_tex[2], 0, false); + renderManager_->BindTexture(TEX_SLOT_SPLINE_WEIGHTS_V, data_tex[2]); + } void DrawEngineGLES::TessellationDataTransferGLES::EndFrame() { diff --git a/GPU/GLES/DrawEngineGLES.h b/GPU/GLES/DrawEngineGLES.h index 19df863133..07707a435b 100644 --- a/GPU/GLES/DrawEngineGLES.h +++ b/GPU/GLES/DrawEngineGLES.h @@ -218,7 +218,8 @@ private: ~TessellationDataTransferGLES() { EndFrame(); } - void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType) override; - void EndFrame() override; // Queues textures for deletion. + void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) override; + void EndFrame(); // Queues textures for deletion. }; + TessellationDataTransferGLES *tessDataTransferGLES; }; diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index fbe7e8a746..1df6f865cf 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -162,10 +162,8 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs, queries.push_back({ &u_tess_points, "u_tess_points" }); queries.push_back({ &u_tess_weights_u, "u_tess_weights_u" }); queries.push_back({ &u_tess_weights_v, "u_tess_weights_v" }); - queries.push_back({ &u_spline_count_u, "u_spline_count_u" }); - queries.push_back({ &u_spline_count_v, "u_spline_count_v" }); - queries.push_back({ &u_spline_type_u, "u_spline_type_u" }); - queries.push_back({ &u_spline_type_v, "u_spline_type_v" }); + queries.push_back({ &u_spline_tess, "u_spline_tess" }); + queries.push_back({ &u_spline_num_patches, "u_spline_num_patches" }); queries.push_back({ &u_depal, "u_depal" }); attrMask = vs->GetAttrMask(); @@ -567,13 +565,14 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid) { } if (dirty & DIRTY_BEZIERSPLINE) { - render_->SetUniformI1(&u_spline_count_u, gstate_c.spline_count_u); - if (u_spline_count_v != -1) - render_->SetUniformI1(&u_spline_count_v, gstate_c.spline_count_v); - if (u_spline_type_u != -1) - render_->SetUniformI1(&u_spline_type_u, gstate_c.spline_type_u); - if (u_spline_type_v != -1) - render_->SetUniformI1(&u_spline_type_v, gstate_c.spline_type_v); + if (u_spline_tess != -1) { + int tess[] = { gstate_c.spline_tess_u, gstate_c.spline_tess_v }; + render_->SetUniformI(&u_spline_tess, 2, tess); + } + if (u_spline_num_patches != -1) { + int num_patches[] = { gstate_c.spline_num_patches_u, gstate_c.spline_num_patches_v }; + render_->SetUniformI(&u_spline_num_patches, 2, num_patches); + } } } diff --git a/GPU/GLES/ShaderManagerGLES.h b/GPU/GLES/ShaderManagerGLES.h index ab551db593..b335099f74 100644 --- a/GPU/GLES/ShaderManagerGLES.h +++ b/GPU/GLES/ShaderManagerGLES.h @@ -121,10 +121,8 @@ public: int u_tess_points; // Control Points int u_tess_weights_u; int u_tess_weights_v; - int u_spline_count_u; - int u_spline_count_v; - int u_spline_type_u; - int u_spline_type_v; + int u_spline_tess; + int u_spline_num_patches; }; // Real public interface diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index 0c06553f84..d7f8a39f45 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -383,79 +383,23 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, WRITE(p, "uniform sampler2D u_tess_weights_u;\n"); WRITE(p, "uniform sampler2D u_tess_weights_v;\n"); - WRITE(p, "uniform int u_spline_count_u;\n"); + WRITE(p, "uniform ivec2 u_spline_num_patches;\n"); + WRITE(p, "uniform ivec2 u_spline_tess;\n"); for (int i = 2; i <= 4; i++) { // Define 3 types vec2, vec3, vec4 - WRITE(p, "vec%d tess_sample(in vec%d points[16], in vec2 weights[4]) {\n", i, i); + WRITE(p, "vec%d tess_sample(in vec%d points[16], vec4 weights_u, vec4 weights_v) {\n", i, i); WRITE(p, " vec%d pos = vec%d(0.0);\n", i, i); - WRITE(p, " for (int i = 0; i < 4; ++i) {\n"); - WRITE(p, " for (int j = 0; j < 4; ++j) {\n"); - WRITE(p, " float f = weights[j].x * weights[i].y;\n"); + WRITE(p, " for (int v = 0; v < 4; ++v) {\n"); + WRITE(p, " for (int u = 0; u < 4; ++u) {\n"); + WRITE(p, " float f = weights_u[u] * weights_v[v];\n"); WRITE(p, " if (f != 0.0)\n"); - WRITE(p, " pos = pos + f * points[i * 4 + j];\n"); + WRITE(p, " pos += f * points[v * 4 + u];\n"); WRITE(p, " }\n"); WRITE(p, " }\n"); WRITE(p, " return pos;\n"); WRITE(p, "}\n"); } - if (doSpline) { - WRITE(p, "uniform int u_spline_count_v;\n"); - WRITE(p, "uniform int u_spline_type_u;\n"); - WRITE(p, "uniform int u_spline_type_v;\n"); - - WRITE(p, "void spline_knot(ivec2 num_patches, ivec2 type, out vec2 knot[6], ivec2 patch_pos) {\n"); - WRITE(p, " for (int i = 0; i < 6; ++i) {\n"); - WRITE(p, " knot[i] = vec2(float(i + patch_pos.x - 2), float(i + patch_pos.y - 2));\n"); - WRITE(p, " }\n"); - WRITE(p, " if ((type.x & 1) != 0) {\n"); - WRITE(p, " if (patch_pos.x <= 2)\n"); - WRITE(p, " knot[0].x = 0.0;\n"); - WRITE(p, " if (patch_pos.x <= 1)\n"); - WRITE(p, " knot[1].x = 0.0;\n"); - WRITE(p, " }\n"); - WRITE(p, " if ((type.x & 2) != 0) {\n"); - WRITE(p, " if (patch_pos.x >= (num_patches.x - 2))\n"); - WRITE(p, " knot[5].x = float(num_patches.x);\n"); - WRITE(p, " if (patch_pos.x == (num_patches.x - 1))\n"); - WRITE(p, " knot[4].x = float(num_patches.x);\n"); - WRITE(p, " }\n"); - WRITE(p, " if ((type.y & 1) != 0) {\n"); - WRITE(p, " if (patch_pos.y <= 2)\n"); - WRITE(p, " knot[0].y = 0.0;\n"); - WRITE(p, " if (patch_pos.y <= 1)\n"); - WRITE(p, " knot[1].y = 0.0;\n"); - WRITE(p, " }\n"); - WRITE(p, " if ((type.y & 2) != 0) {\n"); - WRITE(p, " if (patch_pos.y >= (num_patches.y - 2))\n"); - WRITE(p, " knot[5].y = float(num_patches.y);\n"); - WRITE(p, " if (patch_pos.y == (num_patches.y - 1))\n"); - WRITE(p, " knot[4].y = float(num_patches.y);\n"); - WRITE(p, " }\n"); - WRITE(p, "}\n"); - - WRITE(p, "void spline_weight(vec2 t, in vec2 knot[6], out vec2 weights[4]) {\n"); - // TODO: Maybe compilers could be coaxed into vectorizing this code without the above explicitly... - WRITE(p, " vec2 t0 = (t - knot[0]);\n"); - WRITE(p, " vec2 t1 = (t - knot[1]);\n"); - WRITE(p, " vec2 t2 = (t - knot[2]);\n"); - // TODO: All our knots are integers so we should be able to get rid of these divisions (How?) - WRITE(p, " vec2 f30 = t0 / (knot[3] - knot[0]);\n"); - WRITE(p, " vec2 f41 = t1 / (knot[4] - knot[1]);\n"); - WRITE(p, " vec2 f52 = t2 / (knot[5] - knot[2]);\n"); - WRITE(p, " vec2 f31 = t1 / (knot[3] - knot[1]);\n"); - WRITE(p, " vec2 f42 = t2 / (knot[4] - knot[2]);\n"); - WRITE(p, " vec2 f32 = t2 / (knot[3] - knot[2]);\n"); - WRITE(p, " vec2 a = (1.0 - f30)*(1.0 - f31);\n"); - WRITE(p, " vec2 b = (f31*f41);\n"); - WRITE(p, " vec2 c = (1.0 - f41)*(1.0 - f42);\n"); - WRITE(p, " vec2 d = (f42*f52);\n"); - WRITE(p, " weights[0] = a - (a*f32);\n"); - WRITE(p, " weights[1] = vec2(1.0) - a - b + ((a + b + c - vec2(1.0))*f32);\n"); - WRITE(p, " weights[2] = b + ((vec2(1.0) - b - c - d)*f32);\n"); - WRITE(p, " weights[3] = d*f32;\n"); - WRITE(p, "}\n"); - } } WRITE(p, "void main() {\n"); @@ -496,16 +440,25 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, 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, " 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, " 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, " int num_patches_u = %s;\n", doBezier ? "(u_spline_count_u - 1) / 3" : "u_spline_count_u - 3"); - WRITE(p, " int u = int(mod(float(gl_InstanceID), float(num_patches_u)));\n"); - WRITE(p, " int v = gl_InstanceID / num_patches_u;\n"); - WRITE(p, " ivec2 patch_pos = ivec2(u, v);\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) * u_spline_count_u + (j + u%s);\n", doBezier ? " * 3" : "", doBezier ? " * 3" : ""); + 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); @@ -513,76 +466,32 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, WRITE(p, " _col[i * 4 + j] = %s(u_tess_points, ivec2(index, 2), 0).rgba;\n", texelFetch); WRITE(p, " }\n"); WRITE(p, " }\n"); - WRITE(p, " vec2 tess_pos = position.xy;\n"); - WRITE(p, " vec2 weights[4];\n"); - if (doBezier) { - // Bernstein 3D - WRITE(p, " weights[0] = (1.0 - tess_pos) * (1.0 - tess_pos) * (1.0 - tess_pos);\n"); - WRITE(p, " weights[1] = 3.0 * tess_pos * (1.0 - tess_pos) * (1.0 - tess_pos);\n"); - WRITE(p, " weights[2] = 3.0 * tess_pos * tess_pos * (1.0 - tess_pos);\n"); - WRITE(p, " weights[3] = tess_pos * tess_pos * tess_pos;\n"); - } else { // Spline - WRITE(p, " ivec2 spline_num_patches = ivec2(u_spline_count_u - 3, u_spline_count_v - 3);\n"); - WRITE(p, " ivec2 spline_type = ivec2(u_spline_type_u, u_spline_type_v);\n"); - WRITE(p, " vec2 knots[6];\n"); - WRITE(p, " spline_knot(spline_num_patches, spline_type, knots, patch_pos);\n"); - WRITE(p, " spline_weight(tess_pos + vec2(patch_pos), knots, weights);\n"); - } - WRITE(p, " vec3 pos = tess_sample(_pos, weights);\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)"); + + // 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, weights);\n"); + WRITE(p, " vec2 tex = tess_sample(_tex, basis_u, basis_v);\n"); else - WRITE(p, " vec2 tex = tess_pos + vec2(patch_pos);\n"); + WRITE(p, " vec2 tex = normal.xy + vec2(patch_pos);\n"); } if (hasColor) { if (hasColorTess) - WRITE(p, " vec4 col = tess_sample(_col, weights);\n"); + 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) { - // Curved surface is probably always need to compute normal(not sampling from control points) - if (doBezier) { - // Bernstein derivative - WRITE(p, " vec2 bernderiv[4];\n"); - WRITE(p, " bernderiv[0] = -3.0 * (tess_pos - 1.0) * (tess_pos - 1.0); \n"); - WRITE(p, " bernderiv[1] = 9.0 * tess_pos * tess_pos - 12.0 * tess_pos + 3.0; \n"); - WRITE(p, " bernderiv[2] = 3.0 * (2.0 - 3.0 * tess_pos) * tess_pos; \n"); - WRITE(p, " bernderiv[3] = 3.0 * tess_pos * tess_pos; \n"); + // 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)"); - WRITE(p, " vec2 bernderiv_u[4];\n"); - WRITE(p, " vec2 bernderiv_v[4];\n"); - WRITE(p, " for (int i = 0; i < 4; i++) {\n"); - WRITE(p, " bernderiv_u[i] = vec2(bernderiv[i].x, weights[i].y);\n"); - WRITE(p, " bernderiv_v[i] = vec2(weights[i].x, bernderiv[i].y);\n"); - WRITE(p, " }\n"); - - WRITE(p, " vec3 du = tess_sample(_pos, bernderiv_u);\n"); - WRITE(p, " vec3 dv = tess_sample(_pos, bernderiv_v);\n"); - } else { // Spline - WRITE(p, " vec2 tess_next_u = vec2(normal.x, 0.0);\n"); - WRITE(p, " vec2 tess_next_v = vec2(0.0, normal.y);\n"); - // Right - WRITE(p, " vec2 tess_pos_r = tess_pos + tess_next_u;\n"); - WRITE(p, " spline_weight(tess_pos_r + vec2(patch_pos), knots, weights);\n"); - WRITE(p, " vec3 pos_r = tess_sample(_pos, weights);\n"); - // Left - WRITE(p, " vec2 tess_pos_l = tess_pos - tess_next_u;\n"); - WRITE(p, " spline_weight(tess_pos_l + vec2(patch_pos), knots, weights);\n"); - WRITE(p, " vec3 pos_l = tess_sample(_pos, weights);\n"); - // Down - WRITE(p, " vec2 tess_pos_d = tess_pos + tess_next_v;\n"); - WRITE(p, " spline_weight(tess_pos_d + vec2(patch_pos), knots, weights);\n"); - WRITE(p, " vec3 pos_d = tess_sample(_pos, weights);\n"); - // Up - WRITE(p, " vec2 tess_pos_u = tess_pos - tess_next_v;\n"); - WRITE(p, " spline_weight(tess_pos_u + vec2(patch_pos), knots, weights);\n"); - WRITE(p, " vec3 pos_u = tess_sample(_pos, weights);\n"); - - WRITE(p, " vec3 du = pos_r - pos_l;\n"); - WRITE(p, " vec3 dv = pos_d - pos_u;\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"); } diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index a0ecf7dc4d..2bdd7d4d7d 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1760,9 +1760,10 @@ void GPUCommon::Execute_Bezier(u32 op, u32 diff) { if (CanUseHardwareTessellation(patchPrim)) { gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); gstate_c.bezier = true; - if (gstate_c.spline_count_u != bz_ucount) { + int num_patches_u = (bz_ucount - 1) / 3; + if (gstate_c.spline_num_patches_u != num_patches_u) { gstate_c.Dirty(DIRTY_BEZIERSPLINE); - gstate_c.spline_count_u = bz_ucount; + gstate_c.spline_num_patches_u = num_patches_u; } } @@ -1824,14 +1825,18 @@ void GPUCommon::Execute_Spline(u32 op, u32 diff) { if (CanUseHardwareTessellation(patchPrim)) { gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); gstate_c.spline = true; - bool countsChanged = gstate_c.spline_count_u != sp_ucount || gstate_c.spline_count_v != sp_vcount; - bool typesChanged = gstate_c.spline_type_u != sp_utype || gstate_c.spline_type_v != sp_vtype; - if (countsChanged || typesChanged) { + int tess_u = gstate.getPatchDivisionU(); + int tess_v = gstate.getPatchDivisionV(); + int num_patches_u = sp_ucount - 3; + int num_patches_v = sp_vcount - 3; + bool divsChanged = gstate_c.spline_tess_u != tess_u || gstate_c.spline_tess_v != tess_v; + bool patchesChanged = gstate_c.spline_num_patches_u != num_patches_u || gstate_c.spline_num_patches_v != num_patches_v; + if (divsChanged || patchesChanged) { gstate_c.Dirty(DIRTY_BEZIERSPLINE); - gstate_c.spline_count_u = sp_ucount; - gstate_c.spline_count_v = sp_vcount; - gstate_c.spline_type_u = sp_utype; - gstate_c.spline_type_v = sp_vtype; + gstate_c.spline_tess_u = tess_u; + gstate_c.spline_tess_v = tess_v; + gstate_c.spline_num_patches_u = num_patches_u; + gstate_c.spline_num_patches_v = num_patches_v; } } diff --git a/GPU/GPUState.h b/GPU/GPUState.h index a73023927f..ce5d7116d3 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -602,10 +602,10 @@ struct GPUStateCache { bool bezier; bool spline; - int spline_count_u; - int spline_count_v; - int spline_type_u; - int spline_type_v; + int spline_tess_u; + int spline_tess_v; + int spline_num_patches_u; + int spline_num_patches_v; bool useShaderDepal; GEBufferFormat depalFramebufferFormat; diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index e100513f2b..c8b2c43da1 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -69,6 +69,8 @@ enum { DRAW_BINDING_DYNUBO_LIGHT = 4, DRAW_BINDING_DYNUBO_BONE = 5, DRAW_BINDING_TESS_STORAGE_BUF = 6, + DRAW_BINDING_TESS_STORAGE_BUF_WU = 7, + DRAW_BINDING_TESS_STORAGE_BUF_WV = 8, }; enum { @@ -96,7 +98,7 @@ DrawEngineVulkan::DrawEngineVulkan(VulkanContext *vulkan, Draw::DrawContext *dra void DrawEngineVulkan::InitDeviceObjects() { // All resources we need for PSP drawing. Usually only bindings 0 and 2-4 are populated. - VkDescriptorSetLayoutBinding bindings[7]{}; + VkDescriptorSetLayoutBinding bindings[9]{}; bindings[0].descriptorCount = 1; bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; bindings[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; @@ -126,6 +128,14 @@ void DrawEngineVulkan::InitDeviceObjects() { bindings[6].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; bindings[6].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; bindings[6].binding = DRAW_BINDING_TESS_STORAGE_BUF; + bindings[7].descriptorCount = 1; + bindings[7].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + bindings[7].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + bindings[7].binding = DRAW_BINDING_TESS_STORAGE_BUF_WU; + bindings[8].descriptorCount = 1; + bindings[8].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + bindings[8].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + bindings[8].binding = DRAW_BINDING_TESS_STORAGE_BUF_WV; VkDevice device = vulkan_->GetDevice(); @@ -167,7 +177,8 @@ void DrawEngineVulkan::InitDeviceObjects() { vertexCache_ = new VulkanPushBuffer(vulkan_, VERTEX_CACHE_SIZE); - tessDataTransfer = new TessellationDataTransferVulkan(vulkan_); + tessDataTransferVulkan = new TessellationDataTransferVulkan(vulkan_); + tessDataTransfer = tessDataTransferVulkan; } DrawEngineVulkan::~DrawEngineVulkan() { @@ -202,7 +213,7 @@ void DrawEngineVulkan::FrameData::Destroy(VulkanContext *vulkan) { void DrawEngineVulkan::DestroyDeviceObjects() { delete tessDataTransfer; - tessDataTransfer = nullptr; + tessDataTransfer = tessDataTransferVulkan = nullptr; for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) { frame_[i].Destroy(vulkan_); @@ -258,7 +269,7 @@ void DrawEngineVulkan::BeginFrame() { frame->pushIndex->Begin(vulkan_); // TODO: How can we make this nicer... - ((TessellationDataTransferVulkan *)tessDataTransfer)->SetPushBuffer(frame->pushUBO); + tessDataTransferVulkan->SetPushBuffer(frame->pushUBO); DirtyAllUBOs(); @@ -470,23 +481,32 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView n++; } - // Tessellation data buffer. Make sure this is declared outside the if to avoid optimizer - // shenanigans. - VkDescriptorBufferInfo tess_buf{}; + // Tessellation data buffer. if (tess) { - VkBuffer buf; - VkDeviceSize offset; - VkDeviceSize range; - ((TessellationDataTransferVulkan *)tessDataTransfer)->GetBufferAndOffset(&buf, &offset, &range); - assert(buf); - tess_buf.buffer = buf; - tess_buf.offset = offset; - tess_buf.range = range; - tessOffset_ = offset; + const VkDescriptorBufferInfo *bufInfo = tessDataTransferVulkan->GetBufferInfo(); + // Control Points writes[n].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writes[n].pNext = nullptr; writes[n].dstBinding = DRAW_BINDING_TESS_STORAGE_BUF; - writes[n].pBufferInfo = &tess_buf; + writes[n].pBufferInfo = &bufInfo[0]; + writes[n].descriptorCount = 1; + writes[n].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + writes[n].dstSet = desc; + n++; + // Weights U + writes[n].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writes[n].pNext = nullptr; + writes[n].dstBinding = DRAW_BINDING_TESS_STORAGE_BUF_WU; + writes[n].pBufferInfo = &bufInfo[1]; + writes[n].descriptorCount = 1; + writes[n].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + writes[n].dstSet = desc; + n++; + // Weights V + writes[n].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writes[n].pNext = nullptr; + writes[n].dstBinding = DRAW_BINDING_TESS_STORAGE_BUF_WV; + writes[n].pBufferInfo = &bufInfo[2]; writes[n].descriptorCount = 1; writes[n].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; writes[n].dstSet = desc; @@ -1001,7 +1021,7 @@ DrawEngineVulkan::TessellationDataTransferVulkan::TessellationDataTransferVulkan DrawEngineVulkan::TessellationDataTransferVulkan::~TessellationDataTransferVulkan() { } -void DrawEngineVulkan::TessellationDataTransferVulkan::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType) { +void DrawEngineVulkan::TessellationDataTransferVulkan::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) { // SSBOs that are not simply float1 or float2 need to be padded up to a float4 size. vec3 members // also need to be 16-byte aligned, hence the padding. struct TessData { @@ -1011,8 +1031,8 @@ void DrawEngineVulkan::TessellationDataTransferVulkan::SendDataToShader(const Si }; int ssboAlignment = vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).limits.minStorageBufferOffsetAlignment; - uint8_t *data = (uint8_t *)push_->PushAligned(size * sizeof(TessData), &offset_, &buf_, ssboAlignment); - range_ = size * sizeof(TessData); + uint8_t *data = (uint8_t *)push_->PushAligned(size * sizeof(TessData), (uint32_t *)&bufInfo_[0].offset, &bufInfo_[0].buffer, ssboAlignment); + bufInfo_[0].range = size * sizeof(TessData); float *pos = (float *)(data); float *tex = (float *)(data + offsetof(TessData, uv)); @@ -1020,4 +1040,14 @@ void DrawEngineVulkan::TessellationDataTransferVulkan::SendDataToShader(const Si int stride = sizeof(TessData) / sizeof(float); CopyControlPoints(pos, tex, col, stride, stride, stride, points, size, vertType); + + // Weights U + data = (uint8_t *)push_->PushAligned(weights.size_u * sizeof(Weight), (uint32_t *)&bufInfo_[1].offset, &bufInfo_[1].buffer, ssboAlignment); + memcpy(data, weights.u, weights.size_u * sizeof(Weight)); + bufInfo_[1].range = weights.size_u * sizeof(Weight); + + // Weights V + data = (uint8_t *)push_->PushAligned(weights.size_v * sizeof(Weight), (uint32_t *)&bufInfo_[2].offset, &bufInfo_[2].buffer, ssboAlignment); + memcpy(data, weights.v, weights.size_v * sizeof(Weight)); + bufInfo_[2].range = weights.size_v * sizeof(Weight); } diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index a9837f44a3..8cb4c82350 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -284,24 +284,13 @@ private: ~TessellationDataTransferVulkan(); void SetPushBuffer(VulkanPushBuffer *push) { push_ = push; } - void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType) override; - - void GetBufferAndOffset(VkBuffer *buf, VkDeviceSize *offset, VkDeviceSize *range) { - *buf = buf_; - *offset = (VkDeviceSize)offset_; - *range = (VkDeviceSize)range_; - - buf_ = 0; - offset_ = 0; - range_ = 0; - } - + void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) override; + const VkDescriptorBufferInfo *GetBufferInfo() { return bufInfo_; } private: VulkanContext *vulkan_; VulkanPushBuffer *push_; // Updated each frame. - uint32_t offset_ = 0; - uint32_t range_ = 0; - VkBuffer buf_ = VK_NULL_HANDLE; + VkDescriptorBufferInfo bufInfo_[3] = {}; }; + TessellationDataTransferVulkan *tessDataTransferVulkan; }; diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index cf8fb819a2..6598e4000a 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -219,78 +219,36 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { WRITE(p, " vec4 pos;\n"); WRITE(p, " vec4 uv;\n"); WRITE(p, " vec4 color;\n"); - WRITE(p, "};"); + WRITE(p, "};\n"); WRITE(p, "layout (std430, set = 0, binding = 6) readonly buffer s_tess_data {\n"); - WRITE(p, " TessData data[];"); + WRITE(p, " TessData data[];\n"); WRITE(p, "} tess_data;\n"); + WRITE(p, "layout (std430) struct TessWeight {\n"); + WRITE(p, " vec4 basis;\n"); + WRITE(p, " vec4 deriv;\n"); + WRITE(p, "};\n"); + WRITE(p, "layout (std430, set = 0, binding = 7) buffer s_tess_weights_u {\n"); + WRITE(p, " TessWeight data[];\n"); + WRITE(p, "} tess_weights_u;\n"); + WRITE(p, "layout (std430, set = 0, binding = 8) buffer s_tess_weights_v {\n"); + WRITE(p, " TessWeight data[];\n"); + WRITE(p, "} tess_weights_v;\n"); + for (int i = 2; i <= 4; i++) { // Define 3 types vec2, vec3, vec4 - WRITE(p, "vec%d tess_sample(in vec%d points[16], in vec2 weights[4]) {\n", i, i); - WRITE(p, " vec%d pos = vec%d(0);\n", i, i); - WRITE(p, " for (int i = 0; i < 4; ++i) {\n"); - WRITE(p, " for (int j = 0; j < 4; ++j) {\n"); - WRITE(p, " float f = weights[j].x * weights[i].y;\n"); - WRITE(p, " if (f != 0)\n"); - WRITE(p, " pos = pos + f * points[i * 4 + j];\n"); + WRITE(p, "vec%d tess_sample(in vec%d points[16], vec4 weights_u, vec4 weights_v) {\n", i, i); + WRITE(p, " vec%d pos = vec%d(0.0);\n", i, i); + WRITE(p, " for (int v = 0; v < 4; ++v) {\n"); + WRITE(p, " for (int u = 0; u < 4; ++u) {\n"); + WRITE(p, " float f = weights_u[u] * weights_v[v];\n"); + WRITE(p, " if (f != 0.0)\n"); + WRITE(p, " pos += f * points[v * 4 + u];\n"); WRITE(p, " }\n"); WRITE(p, " }\n"); WRITE(p, " return pos;\n"); WRITE(p, "}\n"); } - if (doSpline) { - WRITE(p, "void spline_knot(ivec2 num_patches, ivec2 type, out vec2 knot[6], ivec2 patch_pos) {\n"); - WRITE(p, " for (int i = 0; i < 6; ++i) {\n"); - WRITE(p, " knot[i] = vec2(i + patch_pos.x - 2, i + patch_pos.y - 2);\n"); - WRITE(p, " }\n"); - WRITE(p, " if ((type.x & 1) != 0) {\n"); - WRITE(p, " if (patch_pos.x <= 2)\n"); - WRITE(p, " knot[0].x = 0;\n"); - WRITE(p, " if (patch_pos.x <= 1)\n"); - WRITE(p, " knot[1].x = 0;\n"); - WRITE(p, " }\n"); - WRITE(p, " if ((type.x & 2) != 0) {\n"); - WRITE(p, " if (patch_pos.x >= (num_patches.x - 2))\n"); - WRITE(p, " knot[5].x = num_patches.x;\n"); - WRITE(p, " if (patch_pos.x == (num_patches.x - 1))\n"); - WRITE(p, " knot[4].x = num_patches.x;\n"); - WRITE(p, " }\n"); - WRITE(p, " if ((type.y & 1) != 0) {\n"); - WRITE(p, " if (patch_pos.y <= 2)\n"); - WRITE(p, " knot[0].y = 0;\n"); - WRITE(p, " if (patch_pos.y <= 1)\n"); - WRITE(p, " knot[1].y = 0;\n"); - WRITE(p, " }\n"); - WRITE(p, " if ((type.y & 2) != 0) {\n"); - WRITE(p, " if (patch_pos.y >= (num_patches.y - 2))\n"); - WRITE(p, " knot[5].y = num_patches.y;\n"); - WRITE(p, " if (patch_pos.y == (num_patches.y - 1))\n"); - WRITE(p, " knot[4].y = num_patches.y;\n"); - WRITE(p, " }\n"); - WRITE(p, "}\n"); - - WRITE(p, "void spline_weight(vec2 t, in vec2 knot[6], out vec2 weights[4]) {\n"); - // TODO: Maybe compilers could be coaxed into vectorizing this code without the above explicitly... - WRITE(p, " vec2 t0 = (t - knot[0]);\n"); - WRITE(p, " vec2 t1 = (t - knot[1]);\n"); - WRITE(p, " vec2 t2 = (t - knot[2]);\n"); - // TODO: All our knots are integers so we should be able to get rid of these divisions (How?) - WRITE(p, " vec2 f30 = t0 / (knot[3] - knot[0]);\n"); - WRITE(p, " vec2 f41 = t1 / (knot[4] - knot[1]);\n"); - WRITE(p, " vec2 f52 = t2 / (knot[5] - knot[2]);\n"); - WRITE(p, " vec2 f31 = t1 / (knot[3] - knot[1]);\n"); - WRITE(p, " vec2 f42 = t2 / (knot[4] - knot[2]);\n"); - WRITE(p, " vec2 f32 = t2 / (knot[3] - knot[2]);\n"); - WRITE(p, " vec2 a = (1 - f30)*(1 - f31);\n"); - WRITE(p, " vec2 b = (f31*f41);\n"); - WRITE(p, " vec2 c = (1 - f41)*(1 - f42);\n"); - WRITE(p, " vec2 d = (f42*f52);\n"); - WRITE(p, " weights[0] = a - (a*f32);\n"); - WRITE(p, " weights[1] = 1 - a - b + ((a + b + c - 1)*f32);\n"); - WRITE(p, " weights[2] = b + ((1 - b - c - d)*f32);\n"); - WRITE(p, " weights[3] = d*f32;\n"); - WRITE(p, "}\n"); - } } WRITE(p, "void main() {\n"); @@ -330,15 +288,25 @@ 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, " 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, " 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, " int spline_count_u = int(base.spline_counts & 0xff);\n"); - WRITE(p, " int spline_count_v = int((base.spline_counts >> 8) & 0xff);\n"); - WRITE(p, " int num_patches_u = %s;\n", doBezier ? "(spline_count_u - 1) / 3" : "spline_count_u - 3"); - WRITE(p, " int u = int(mod(gl_InstanceIndex, num_patches_u));\n"); - WRITE(p, " int v = gl_InstanceIndex / num_patches_u;\n"); - WRITE(p, " ivec2 patch_pos = ivec2(u, v);\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" : ""); @@ -349,78 +317,32 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { WRITE(p, " _col[i * 4 + j] = tess_data.data[idx].color;\n"); WRITE(p, " }\n"); WRITE(p, " }\n"); - WRITE(p, " vec2 tess_pos = position.xy;\n"); - WRITE(p, " vec2 weights[4];\n"); - if (doBezier) { - // Bernstein 3D - WRITE(p, " weights[0] = (1 - tess_pos) * (1 - tess_pos) * (1 - tess_pos);\n"); - WRITE(p, " weights[1] = 3 * tess_pos * (1 - tess_pos) * (1 - tess_pos);\n"); - WRITE(p, " weights[2] = 3 * tess_pos * tess_pos * (1 - tess_pos);\n"); - WRITE(p, " weights[3] = tess_pos * tess_pos * tess_pos;\n"); - } else { // Spline - WRITE(p, " ivec2 spline_num_patches = ivec2(spline_count_u - 3, spline_count_v - 3);\n"); - WRITE(p, " int spline_type_u = int((base.spline_counts >> 16) & 0xff);\n"); - WRITE(p, " int spline_type_v = int((base.spline_counts >> 24) & 0xff);\n"); - WRITE(p, " ivec2 spline_type = ivec2(spline_type_u, spline_type_v);\n"); - WRITE(p, " vec2 knots[6];\n"); - WRITE(p, " spline_knot(spline_num_patches, spline_type, knots, patch_pos);\n"); - WRITE(p, " spline_weight(tess_pos + patch_pos, knots, weights);\n"); - } - WRITE(p, " vec3 pos = tess_sample(_pos, weights);\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"); + + // 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, weights);\n"); + WRITE(p, " vec2 tex = tess_sample(_tex, basis_u, basis_v);\n"); else - WRITE(p, " vec2 tex = tess_pos + patch_pos;\n"); + WRITE(p, " vec2 tex = normal.xy + vec2(patch_pos);\n"); } if (hasColor) { if (hasColorTess) - WRITE(p, " vec4 col = tess_sample(_col, weights);\n"); + 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) { - // Curved surface is probably always need to compute normal(not sampling from control points) - if (doBezier) { - // Bernstein derivative - WRITE(p, " vec2 bernderiv[4];\n"); - WRITE(p, " bernderiv[0] = -3 * (tess_pos - 1) * (tess_pos - 1); \n"); - WRITE(p, " bernderiv[1] = 9 * tess_pos * tess_pos - 12 * tess_pos + 3; \n"); - WRITE(p, " bernderiv[2] = 3 * (2 - 3 * tess_pos) * tess_pos; \n"); - WRITE(p, " bernderiv[3] = 3 * tess_pos * tess_pos; \n"); + // 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"); - WRITE(p, " vec2 bernderiv_u[4];\n"); - WRITE(p, " vec2 bernderiv_v[4];\n"); - WRITE(p, " for (int i = 0; i < 4; i++) {\n"); - WRITE(p, " bernderiv_u[i] = vec2(bernderiv[i].x, weights[i].y);\n"); - WRITE(p, " bernderiv_v[i] = vec2(weights[i].x, bernderiv[i].y);\n"); - WRITE(p, " }\n"); - - WRITE(p, " vec3 du = tess_sample(_pos, bernderiv_u);\n"); - WRITE(p, " vec3 dv = tess_sample(_pos, bernderiv_v);\n"); - } else { // Spline - WRITE(p, " vec2 tess_next_u = vec2(normal.x, 0);\n"); - WRITE(p, " vec2 tess_next_v = vec2(0, normal.y);\n"); - // Right - WRITE(p, " vec2 tess_pos_r = tess_pos + tess_next_u;\n"); - WRITE(p, " spline_weight(tess_pos_r + patch_pos, knots, weights);\n"); - WRITE(p, " vec3 pos_r = tess_sample(_pos, weights);\n"); - // Left - WRITE(p, " vec2 tess_pos_l = tess_pos - tess_next_u;\n"); - WRITE(p, " spline_weight(tess_pos_l + patch_pos, knots, weights);\n"); - WRITE(p, " vec3 pos_l = tess_sample(_pos, weights);\n"); - // Down - WRITE(p, " vec2 tess_pos_d = tess_pos + tess_next_v;\n"); - WRITE(p, " spline_weight(tess_pos_d + patch_pos, knots, weights);\n"); - WRITE(p, " vec3 pos_d = tess_sample(_pos, weights);\n"); - // Up - WRITE(p, " vec2 tess_pos_u = tess_pos - tess_next_v;\n"); - WRITE(p, " spline_weight(tess_pos_u + patch_pos, knots, weights);\n"); - WRITE(p, " vec3 pos_u = tess_sample(_pos, weights);\n"); - - WRITE(p, " vec3 du = pos_r - pos_l;\n"); - WRITE(p, " vec3 dv = pos_d - pos_u;\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"); } From a48a5b32f087d22b56368cf3ff6866eaf00db2d0 Mon Sep 17 00:00:00 2001 From: xebra Date: Fri, 13 Jul 2018 18:35:44 +0900 Subject: [PATCH 043/347] [spline/bezier]Unify hardware tessellation of bezier and spline. --- GPU/Common/DrawEngineCommon.cpp | 2 +- GPU/Common/DrawEngineCommon.h | 13 ++-- GPU/Common/SplineCommon.cpp | 126 +++++++++++++------------------- GPU/D3D11/DrawEngineD3D11.cpp | 55 ++++++++------ GPU/D3D11/DrawEngineD3D11.h | 45 +++++------- GPU/Directx9/DrawEngineDX9.cpp | 8 +- GPU/Directx9/DrawEngineDX9.h | 18 ++--- GPU/GLES/DrawEngineGLES.cpp | 6 +- GPU/GLES/DrawEngineGLES.h | 28 +++---- GPU/Vulkan/DrawEngineVulkan.cpp | 11 +-- GPU/Vulkan/DrawEngineVulkan.h | 28 +++---- 11 files changed, 153 insertions(+), 187 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index abee27048b..0d2a8de032 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -741,7 +741,7 @@ void DrawEngineCommon::SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, } } -void DrawEngineCommon::TessellationDataTransfer::CopyControlPoints(float *pos, float *tex, float *col, int posStride, int texStride, int colStride, const SimpleVertex *const *points, int size, u32 vertType) { +void TessellationDataTransfer::CopyControlPoints(float *pos, float *tex, float *col, int posStride, int texStride, int colStride, const SimpleVertex *const *points, int size, u32 vertType) { bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0; bool hasTexCoord = (vertType & GE_VTYPE_TC_MASK) != 0; diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index de8a467f4a..9211905606 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -53,6 +53,12 @@ inline uint32_t GetVertTypeID(uint32_t vertType, int uvGenMode) { struct SimpleVertex; +class TessellationDataTransfer { +public: + void CopyControlPoints(float *pos, float *tex, float *col, int posStride, int texStride, int colStride, const SimpleVertex *const *points, int size, u32 vertType); + virtual void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) = 0; +}; + class DrawEngineCommon { public: DrawEngineCommon(); @@ -173,12 +179,5 @@ protected: // Hardware tessellation int numPatches; - class TessellationDataTransfer { - public: - virtual ~TessellationDataTransfer() {} - void CopyControlPoints(float *pos, float *tex, float *col, int posStride, int texStride, int colStride, const SimpleVertex *const *points, int size, u32 vertType); - // Send spline/bezier's control points to vertex shader through floating point texture. - virtual void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) = 0; - }; TessellationDataTransfer *tessDataTransfer; }; diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index ea8776ccb8..7e07807228 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -89,6 +89,10 @@ public: u32 ToKey(int tess, int count, int type) { return tess; } + + int CalcSize(int tess, int count) { + return tess + 1; + } }; class Spline3DWeight { @@ -231,6 +235,10 @@ public: void FromKey(u32 key, int &tess, int &count, int &type) { tess = key & 0xFF; count = (key >> 8) & 0xFF; type = (key >> 16) & 0xFF; } + + int CalcSize(int tess, int count) { + return (count - 3) * tess + 1; + } }; static WeightCache bezierWeightsCache; @@ -248,28 +256,6 @@ bool CanUseHardwareTessellation(GEPatchPrimType prim) { return false; } -// Prepare mesh of one patch for "Instanced Tessellation". -static void TessellateSplinePatchHardware(u8 *&dest, u16 *indices, int &count, const SplinePatchLocal &spatch) { - SimpleVertex *&vertices = (SimpleVertex*&)dest; - - float inv_u = 1.0f / (float)spatch.tess_u; - float inv_v = 1.0f / (float)spatch.tess_v; - - // Generating simple input vertices for the spline-computing vertex shader. - for (int tile_v = 0; tile_v < spatch.tess_v + 1; ++tile_v) { - for (int tile_u = 0; tile_u < spatch.tess_u + 1; ++tile_u) { - SimpleVertex &vert = vertices[tile_v * (spatch.tess_u + 1) + tile_u]; - vert.pos.x = (float)tile_u; - vert.pos.y = (float)tile_v; - // For texcoord generation - vert.nrm.x = (float)tile_u * inv_u; - vert.nrm.y = (float)tile_v * inv_v; - } - } - - BuildIndex(indices, count, spatch.tess_u, spatch.tess_v, spatch.primType); -} - // Tessellate single patch (4x4 control points) template class Tessellator { @@ -309,29 +295,6 @@ public: } }; -// Prepare mesh of one patch for "Instanced Tessellation". -static void TessellateBezierPatchHardware(u8 *&dest, u16 *indices, int &count, int tess_u, int tess_v, GEPatchPrimType primType) { - SimpleVertex *&vertices = (SimpleVertex*&)dest; - - float inv_u = 1.0f / (float)tess_u; - float inv_v = 1.0f / (float)tess_v; - - // Generating simple input vertices for the bezier-computing vertex shader. - for (int tile_v = 0; tile_v < tess_v + 1; ++tile_v) { - for (int tile_u = 0; tile_u < tess_u + 1; ++tile_u) { - SimpleVertex &vert = vertices[tile_v * (tess_u + 1) + tile_u]; - - vert.pos.x = (float)tile_u; - vert.pos.y = (float)tile_v; - // For texcoord generation - vert.nrm.x = (float)tile_u * inv_u; - vert.nrm.y = (float)tile_v * inv_v; - } - } - - BuildIndex(indices, count, tess_u, tess_v, primType); -} - class SimpleBufferManager { private: u8 *buf_; @@ -466,7 +429,8 @@ public: }; template -static void SoftwareTessellation(SimpleVertex *vertices, u16 *indices, int &count, const Patch &patch, int origVertType, const SimpleVertex *const *points, SimpleBufferManager &managedBuf, Cache &weightsCache) { +static void SoftwareTessellation(SimpleVertex *vertices, u16 *indices, int &count, const Patch &patch, u32 origVertType, + const SimpleVertex *const *points, SimpleBufferManager &managedBuf, Cache &weightsCache) { u32 key_u = weightsCache.ToKey(patch.tess_u, patch.count_u, patch.type_u); u32 key_v = weightsCache.ToKey(patch.tess_v, patch.count_v, patch.type_v); Weight2D weights(weightsCache, key_u, key_v); @@ -475,8 +439,31 @@ static void SoftwareTessellation(SimpleVertex *vertices, u16 *indices, int &coun surface.Tessellate(vertices, indices, count, origVertType); } -// This maps GEPatchPrimType to GEPrimitiveType. -const GEPrimitiveType primType[] = { GE_PRIM_TRIANGLES, GE_PRIM_LINES, GE_PRIM_POINTS, GE_PRIM_POINTS }; +template +static void HardwareTessellation(SimpleVertex *vertices, u16 *indices, int &count, const Patch &patch, u32 origVertType, + const SimpleVertex *const *points, Cache &weightsCache, TessellationDataTransfer *tessDataTransfer) { + u32 key_u = weightsCache.ToKey(patch.tess_u, patch.count_u, patch.type_u); + u32 key_v = weightsCache.ToKey(patch.tess_v, patch.count_v, patch.type_v); + Weight2D weights(weightsCache, key_u, key_v); + weights.size_u = weightsCache.CalcSize(patch.tess_u, patch.count_u); + weights.size_v = weightsCache.CalcSize(patch.tess_v, patch.count_v); + tessDataTransfer->SendDataToShader(points, patch.count_u * patch.count_v, origVertType, weights); + + // Generating simple input vertices for the spline-computing vertex shader. + float inv_u = 1.0f / (float)patch.tess_u; + float inv_v = 1.0f / (float)patch.tess_v; + for (int tile_v = 0; tile_v <= patch.tess_v; ++tile_v) { + for (int tile_u = 0; tile_u <= patch.tess_u; ++tile_u) { + SimpleVertex &vert = vertices[tile_v * (patch.tess_u + 1) + tile_u]; + vert.pos.x = (float)tile_u; + vert.pos.y = (float)tile_v; + // For texcoord generation + vert.nrm.x = (float)tile_u * inv_u; + vert.nrm.y = (float)tile_v * inv_v; + } + } + BuildIndex(indices, count, patch.tess_u, patch.tess_v, patch.primType); +} void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indices, int tess_u, int tess_v, int count_u, int count_v, int type_u, int type_v, GEPatchPrimType prim_type, bool computeNormals, bool patchFacing, u32 vertType, int *bytesRead) { PROFILE_THIS_SCOPE("spline"); @@ -536,14 +523,8 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi patch.patchFacing = patchFacing; if (CanUseHardwareTessellation(prim_type)) { - const u32 key_u = splineWeightsCache.ToKey(tess_u, count_u, type_u); - const u32 key_v = splineWeightsCache.ToKey(tess_v, count_v, type_v); - Weight2D weights(splineWeightsCache, key_u, key_v); - weights.size_u = (count_u - 3) * tess_u + 1; - weights.size_v = (count_v - 3) * tess_v + 1; - tessDataTransfer->SendDataToShader(points, count_u * count_v, origVertType, weights); - TessellateSplinePatchHardware(dest, quadIndices_, count, patch); - numPatches = (count_u - 3) * (count_v - 3); + HardwareTessellation((SimpleVertex *)splineBuffer, quadIndices_, count, patch, origVertType, points, splineWeightsCache, tessDataTransfer); + numPatches = patch.num_patches_u * patch.num_patches_v; } else { patch.Init(SPLINE_BUFFER_SIZE / vertexSize); SoftwareTessellation((SimpleVertex *)splineBuffer, quadIndices_, count, patch, origVertType, points, managedBuf, splineWeightsCache); @@ -621,27 +602,20 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi u8 *dest = splineBuffer; u16 *inds = quadIndices_; - // Bezier patches share less control points than spline patches. Otherwise they are pretty much the same (except bezier don't support the open/close thing) - int num_patches_u = (count_u - 1) / 3; - int num_patches_v = (count_v - 1) / 3; - if (CanUseHardwareTessellation(prim_type)) { - Weight2D weights(bezierWeightsCache, tess_u, tess_v); - weights.size_u = tess_u + 1; - weights.size_v = tess_v + 1; - tessDataTransfer->SendDataToShader(points, count_u * count_v, origVertType, weights); - TessellateBezierPatchHardware(dest, inds, count, tess_u, tess_v, prim_type); - numPatches = num_patches_u * num_patches_v; - } else { - BezierPatch patch; - patch.tess_u = tess_u; - patch.tess_v = tess_v; - patch.count_u = count_u; - patch.count_v = count_v; - patch.num_patches_u = (count_u - 1) / 3; - patch.num_patches_v = (count_v - 1) / 3; - patch.primType = prim_type; - patch.patchFacing = patchFacing; + BezierPatch patch; + patch.tess_u = tess_u; + patch.tess_v = tess_v; + patch.count_u = count_u; + patch.count_v = count_v; + patch.num_patches_u = (count_u - 1) / 3; + patch.num_patches_v = (count_v - 1) / 3; + patch.primType = prim_type; + patch.patchFacing = patchFacing; + if (CanUseHardwareTessellation(prim_type)) { + HardwareTessellation((SimpleVertex *)splineBuffer, quadIndices_, count, patch, origVertType, points, bezierWeightsCache, tessDataTransfer); + numPatches = patch.num_patches_u * patch.num_patches_v; + } else { patch.Init(SPLINE_BUFFER_SIZE / vertexSize); SoftwareTessellation((SimpleVertex *)splineBuffer, quadIndices_, count, patch, origVertType, points, managedBuf, bezierWeightsCache); } diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 1a77479851..537951fb49 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -111,7 +111,8 @@ void DrawEngineD3D11::InitDeviceObjects() { pushVerts_ = new PushBufferD3D11(device_, VERTEX_PUSH_SIZE, D3D11_BIND_VERTEX_BUFFER); pushInds_ = new PushBufferD3D11(device_, INDEX_PUSH_SIZE, D3D11_BIND_INDEX_BUFFER); - tessDataTransfer = new TessellationDataTransferD3D11(context_, device_); + tessDataTransferD3D11 = new TessellationDataTransferD3D11(context_, device_); + tessDataTransfer = tessDataTransferD3D11; } void DrawEngineD3D11::ClearTrackedVertexArrays() { @@ -137,7 +138,7 @@ void DrawEngineD3D11::Resized() { void DrawEngineD3D11::DestroyDeviceObjects() { ClearTrackedVertexArrays(); ClearInputLayoutMap(); - delete tessDataTransfer; + delete tessDataTransferD3D11; delete pushVerts_; delete pushInds_; depthStencilCache_.Iterate([&](const uint64_t &key, ID3D11DepthStencilState *ds) { @@ -692,7 +693,22 @@ rotateVBO: GPUDebug::NotifyDraw(); } -void DrawEngineD3D11::TessellationDataTransferD3D11::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) { +TessellationDataTransferD3D11::TessellationDataTransferD3D11(ID3D11DeviceContext *context, ID3D11Device *device) + : context_(context), device_(device) { + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; +} + +TessellationDataTransferD3D11::~TessellationDataTransferD3D11() { + for (int i = 0; i < 3; ++i) { + if (buf[i]) buf[i]->Release(); + if (view[i]) view[i]->Release(); + } +} + +void TessellationDataTransferD3D11::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) { struct TessData { float pos[3]; float pad1; float uv[2]; float pad2[2]; @@ -701,13 +717,11 @@ void DrawEngineD3D11::TessellationDataTransferD3D11::SendDataToShader(const Simp if (prevSize < size) { prevSize = size; - if (buf[0]) { - buf[0]->Release(); - view[0]->Release(); - } + if (buf[0]) buf[0]->Release(); + if (view[0]) view[0]->Release(); + desc.ByteWidth = size * sizeof(TessData); desc.StructureByteStride = sizeof(TessData); - device_->CreateBuffer(&desc, nullptr, &buf[0]); device_->CreateShaderResourceView(buf[0], nullptr, &view[0]); context_->VSSetShaderResources(0, 1, &view[0]); @@ -727,17 +741,14 @@ void DrawEngineD3D11::TessellationDataTransferD3D11::SendDataToShader(const Simp context_->Unmap(buf[0], 0); - // Weights U - if (prevSizeWeights[0] < weights.size_u) { - prevSizeWeights[0] = weights.size_u; - if (buf[1]) { - buf[1]->Release(); - view[1]->Release(); - } + if (prevSizeWU < weights.size_u) { + prevSizeWU = weights.size_u; + if (buf[1]) buf[1]->Release(); + if (view[1]) view[1]->Release(); + desc.ByteWidth = weights.size_u * sizeof(Weight); desc.StructureByteStride = sizeof(Weight); - device_->CreateBuffer(&desc, nullptr, &buf[1]); device_->CreateShaderResourceView(buf[1], nullptr, &view[1]); context_->VSSetShaderResources(1, 1, &view[1]); @@ -747,15 +758,13 @@ void DrawEngineD3D11::TessellationDataTransferD3D11::SendDataToShader(const Simp context_->Unmap(buf[1], 0); // Weights V - if (prevSizeWeights[1] < weights.size_v) { - prevSizeWeights[1] = weights.size_v; - if (buf[2]) { - buf[2]->Release(); - view[2]->Release(); - } + if (prevSizeWV < weights.size_v) { + prevSizeWV = weights.size_v; + if (buf[2]) buf[2]->Release(); + if (view[2]) view[2]->Release(); + desc.ByteWidth = weights.size_v * sizeof(Weight); desc.StructureByteStride = sizeof(Weight); - device_->CreateBuffer(&desc, nullptr, &buf[2]); device_->CreateShaderResourceView(buf[2], nullptr, &view[2]); context_->VSSetShaderResources(2, 1, &view[2]); diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h index c910e2d365..a74dd03458 100644 --- a/GPU/D3D11/DrawEngineD3D11.h +++ b/GPU/D3D11/DrawEngineD3D11.h @@ -99,6 +99,22 @@ public: u8 flags; }; +class TessellationDataTransferD3D11 : public TessellationDataTransfer { +private: + ID3D11DeviceContext *context_; + ID3D11Device *device_; + ID3D11Buffer *buf[3]{}; + ID3D11ShaderResourceView *view[3]{}; + D3D11_BUFFER_DESC desc{}; + int prevSize = 0; + int prevSizeWU = 0, prevSizeWV = 0; +public: + TessellationDataTransferD3D11(ID3D11DeviceContext *context, ID3D11Device *device); + ~TessellationDataTransferD3D11(); + // Send spline/bezier's control points and weights to vertex shader through structured shader buffer. + void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) override; +}; + // Handles transform, lighting and drawing. class DrawEngineD3D11 : public DrawEngineCommon { public: @@ -199,32 +215,5 @@ private: D3D11DynamicState dynState_{}; // Hardware tessellation - class TessellationDataTransferD3D11 : public TessellationDataTransfer { - private: - ID3D11DeviceContext *context_; - ID3D11Device *device_; - ID3D11Buffer *buf[3]; - ID3D11ShaderResourceView *view[3]; - D3D11_BUFFER_DESC desc; - int prevSize = 0; - int prevSizeWeights[2] = {}; - public: - TessellationDataTransferD3D11(ID3D11DeviceContext *context, ID3D11Device *device) - : TessellationDataTransfer(), context_(context), device_(device), buf(), view(), desc() { - desc.Usage = D3D11_USAGE_DYNAMIC; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; - } - ~TessellationDataTransferD3D11() { - for (int i = 0; i < 3; ++i) { - if (buf[i]) { - buf[i]->Release(); - view[i]->Release(); - } - } - } - - void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) override; - }; + TessellationDataTransferD3D11 *tessDataTransferD3D11; }; diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index b7ad1027a9..4300e18c86 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -101,7 +101,8 @@ DrawEngineDX9::DrawEngineDX9(Draw::DrawContext *draw) : vai_(256), vertexDeclMap InitDeviceObjects(); - tessDataTransfer = new TessellationDataTransferDX9(); + tessDataTransferDX9 = new TessellationDataTransferDX9(); + tessDataTransfer = tessDataTransferDX9; device_->CreateVertexDeclaration(TransformedVertexElements, &transformedVertexDecl_); } @@ -121,7 +122,7 @@ DrawEngineDX9::~DrawEngineDX9() { } }); vertexDeclMap_.Clear(); - delete tessDataTransfer; + delete tessDataTransferDX9; } void DrawEngineDX9::InitDeviceObjects() { @@ -624,7 +625,8 @@ rotateVBO: GPUDebug::NotifyDraw(); } -void DrawEngineDX9::TessellationDataTransferDX9::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) { +void TessellationDataTransferDX9::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) { + // TODO } } // namespace diff --git a/GPU/Directx9/DrawEngineDX9.h b/GPU/Directx9/DrawEngineDX9.h index be54128be2..32c0db6e0f 100644 --- a/GPU/Directx9/DrawEngineDX9.h +++ b/GPU/Directx9/DrawEngineDX9.h @@ -97,6 +97,13 @@ public: u8 flags; }; +class TessellationDataTransferDX9 : public TessellationDataTransfer { +public: + TessellationDataTransferDX9() {} + ~TessellationDataTransferDX9() {} + void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) override; +}; + // Handles transform, lighting and drawing. class DrawEngineDX9 : public DrawEngineCommon { public: @@ -158,16 +165,7 @@ private: FramebufferManagerDX9 *framebufferManager_ = nullptr; // Hardware tessellation - class TessellationDataTransferDX9 : public TessellationDataTransfer { - private: - int data_tex[3]; - public: - TessellationDataTransferDX9() : TessellationDataTransfer(), data_tex() { - } - ~TessellationDataTransferDX9() { - } - void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) override; - }; + TessellationDataTransferDX9 *tessDataTransferDX9; }; } // namespace diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 6fd3d68ced..957eda68bc 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -97,7 +97,7 @@ DrawEngineGLES::~DrawEngineGLES() { FreeMemoryPages(decIndex, DECODED_INDEX_BUFFER_SIZE); FreeMemoryPages(splineBuffer, SPLINE_BUFFER_SIZE); - delete tessDataTransfer; + delete tessDataTransferGLES; } void DrawEngineGLES::DeviceLost() { @@ -656,7 +656,7 @@ bool DrawEngineGLES::IsCodePtrVertexDecoder(const u8 *ptr) const { return decJitCache_->IsInSpace(ptr); } -void DrawEngineGLES::TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) { +void TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) { bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0; bool hasTexCoord = (vertType & GE_VTYPE_TC_MASK) != 0; int sizeColor = hasColor ? size : 1; @@ -703,7 +703,7 @@ void DrawEngineGLES::TessellationDataTransferGLES::SendDataToShader(const Simple } -void DrawEngineGLES::TessellationDataTransferGLES::EndFrame() { +void TessellationDataTransferGLES::EndFrame() { for (int i = 0; i < 3; i++) { if (data_tex[i]) { renderManager_->DeleteTexture(data_tex[i]); diff --git a/GPU/GLES/DrawEngineGLES.h b/GPU/GLES/DrawEngineGLES.h index 07707a435b..52605374d9 100644 --- a/GPU/GLES/DrawEngineGLES.h +++ b/GPU/GLES/DrawEngineGLES.h @@ -110,6 +110,21 @@ public: u8 flags; }; +class TessellationDataTransferGLES : public TessellationDataTransfer { +private: + GLRTexture *data_tex[3]{}; + GLRenderManager *renderManager_; +public: + TessellationDataTransferGLES(GLRenderManager *renderManager) + : renderManager_(renderManager) { } + ~TessellationDataTransferGLES() { + EndFrame(); + } + // Send spline/bezier's control points and weights to vertex shader through floating point texture. + void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) override; + void EndFrame(); // Queues textures for deletion. +}; + // Handles transform, lighting and drawing. class DrawEngineGLES : public DrawEngineCommon { public: @@ -208,18 +223,5 @@ private: int bufferDecimationCounter_ = 0; // Hardware tessellation - class TessellationDataTransferGLES : public TessellationDataTransfer { - private: - GLRTexture *data_tex[3]{}; - GLRenderManager *renderManager_; - public: - TessellationDataTransferGLES(GLRenderManager *renderManager) - : renderManager_(renderManager) { } - ~TessellationDataTransferGLES() { - EndFrame(); - } - void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) override; - void EndFrame(); // Queues textures for deletion. - }; TessellationDataTransferGLES *tessDataTransferGLES; }; diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index c8b2c43da1..bcd9648c76 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -212,7 +212,7 @@ void DrawEngineVulkan::FrameData::Destroy(VulkanContext *vulkan) { } void DrawEngineVulkan::DestroyDeviceObjects() { - delete tessDataTransfer; + delete tessDataTransferVulkan; tessDataTransfer = tessDataTransferVulkan = nullptr; for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) { @@ -1014,14 +1014,7 @@ void DrawEngineVulkan::UpdateUBOs(FrameData *frame) { } } -DrawEngineVulkan::TessellationDataTransferVulkan::TessellationDataTransferVulkan(VulkanContext *vulkan) - : TessellationDataTransfer(), vulkan_(vulkan) { -} - -DrawEngineVulkan::TessellationDataTransferVulkan::~TessellationDataTransferVulkan() { -} - -void DrawEngineVulkan::TessellationDataTransferVulkan::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) { +void TessellationDataTransferVulkan::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) { // SSBOs that are not simply float1 or float2 need to be padded up to a float4 size. vec3 members // also need to be 16-byte aligned, hence the padding. struct TessData { diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index 8cb4c82350..ad2cb30954 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -117,6 +117,20 @@ public: class VulkanRenderManager; +class TessellationDataTransferVulkan : public TessellationDataTransfer { +public: + TessellationDataTransferVulkan(VulkanContext *vulkan) : vulkan_(vulkan) {} + + void SetPushBuffer(VulkanPushBuffer *push) { push_ = push; } + // Send spline/bezier's control points and weights to vertex shader through structured shader buffer. + void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) override; + const VkDescriptorBufferInfo *GetBufferInfo() { return bufInfo_; } +private: + VulkanContext *vulkan_; + VulkanPushBuffer *push_; // Updated each frame. + VkDescriptorBufferInfo bufInfo_[3]{}; +}; + // Handles transform, lighting and drawing. class DrawEngineVulkan : public DrawEngineCommon { public: @@ -278,19 +292,5 @@ private: int tessOffset_ = 0; // Hardware tessellation - class TessellationDataTransferVulkan : public TessellationDataTransfer { - public: - TessellationDataTransferVulkan(VulkanContext *vulkan); - ~TessellationDataTransferVulkan(); - - void SetPushBuffer(VulkanPushBuffer *push) { push_ = push; } - void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) override; - const VkDescriptorBufferInfo *GetBufferInfo() { return bufInfo_; } - private: - VulkanContext *vulkan_; - VulkanPushBuffer *push_; // Updated each frame. - - VkDescriptorBufferInfo bufInfo_[3] = {}; - }; TessellationDataTransferVulkan *tessDataTransferVulkan; }; From 3d07bca010f03976139e2410661d27a2ba7ed20e Mon Sep 17 00:00:00 2001 From: xebra Date: Mon, 12 Feb 2018 00:50:21 +0900 Subject: [PATCH 044/347] [spline/bezier]Fix spline weights calculation and get rid of using next patch position in hwtess. # Conflicts: # GPU/Directx9/VertexShaderGeneratorDX9.cpp # GPU/GLES/VertexShaderGeneratorGLES.cpp # GPU/Vulkan/VertexShaderGeneratorVulkan.cpp --- GPU/Common/SplineCommon.cpp | 12 ++++++------ GPU/Common/SplineCommon.h | 6 ++---- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 18 ++++++++++++++---- GPU/GLES/VertexShaderGeneratorGLES.cpp | 18 ++++++++++++++---- GPU/Vulkan/VertexShaderGeneratorVulkan.cpp | 18 ++++++++++++++---- 5 files changed, 50 insertions(+), 22 deletions(-) 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"); From 41d6c3cf3ac73e065dfb0b3d51130f4181d6281e Mon Sep 17 00:00:00 2001 From: xebra Date: Fri, 13 Jul 2018 23:36:36 +0900 Subject: [PATCH 045/347] [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 ab771971ba..5ff0f6978f 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"); + // Hardware tessellation + WRITE(p, " Tess tess;\n"); + WRITE(p, " tessellate(In, tess);\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); - } - } - - // 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 895536fc04..84c782325d 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"); + // Hardware tessellation + WRITE(p, " Tess tess;\n"); + WRITE(p, " tessellate(tess);\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, " 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); - } + WRITE(p, " vec3 worldpos = (u_world * vec4(tess.pos.xyz, 1.0)).xyz;\n"); 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"); - 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 99b799cfcd..a45e10c70f 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"); + // Hardware tessellation + WRITE(p, " Tess tess;\n"); + WRITE(p, " tessellate(tess);\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, " 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"); - } + WRITE(p, " vec3 worldpos = vec4(tess.pos.xyz, 1.0) * base.world_mtx;\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"); - 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 { From 103d180ae7de18d1a8540451c29878aa4df0f39e Mon Sep 17 00:00:00 2001 From: xebra Date: Sat, 14 Jul 2018 00:14:19 +0900 Subject: [PATCH 046/347] [spline/bezier]Get rid of wasted if-checks at Graphics Processors. --- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 5 ++--- GPU/GLES/VertexShaderGeneratorGLES.cpp | 5 ++--- GPU/Vulkan/VertexShaderGeneratorVulkan.cpp | 5 ++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 5ff0f6978f..5f5a98f117 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -287,11 +287,10 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage // Define 3 types float2, float3, float4 WRITE(p, "float%d tess_sample(in float%d points[16], float4 weights_u, float4 weights_v) {\n", i, i); WRITE(p, " float%d pos = float%d(%s);\n", i, i, init[i - 2]); + WRITE(p, " int idx = 0;\n"); WRITE(p, " for (int v = 0; v < 4; ++v) {\n"); WRITE(p, " for (int u = 0; u < 4; ++u) {\n"); - WRITE(p, " float f = weights_u[u] * weights_v[v];\n"); - WRITE(p, " if (f != 0.0)\n"); - WRITE(p, " pos = pos + f * points[v * 4 + u];\n"); + WRITE(p, " pos += weights_u[u] * weights_v[v] * points[idx++];\n"); WRITE(p, " }\n"); WRITE(p, " }\n"); WRITE(p, " return pos;\n"); diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index 84c782325d..714c8f322b 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -390,11 +390,10 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, // Define 3 types vec2, vec3, vec4 WRITE(p, "vec%d tess_sample(in vec%d points[16], vec4 weights_u, vec4 weights_v) {\n", i, i); WRITE(p, " vec%d pos = vec%d(0.0);\n", i, i); + WRITE(p, " int idx = 0;\n"); WRITE(p, " for (int v = 0; v < 4; ++v) {\n"); WRITE(p, " for (int u = 0; u < 4; ++u) {\n"); - WRITE(p, " float f = weights_u[u] * weights_v[v];\n"); - WRITE(p, " if (f != 0.0)\n"); - WRITE(p, " pos += f * points[v * 4 + u];\n"); + WRITE(p, " pos += weights_u[u] * weights_v[v] * points[idx++];\n"); WRITE(p, " }\n"); WRITE(p, " }\n"); WRITE(p, " return pos;\n"); diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index a45e10c70f..f1230f2829 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -239,11 +239,10 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { // Define 3 types vec2, vec3, vec4 WRITE(p, "vec%d tess_sample(in vec%d points[16], vec4 weights_u, vec4 weights_v) {\n", i, i); WRITE(p, " vec%d pos = vec%d(0.0);\n", i, i); + WRITE(p, " int idx = 0;\n"); WRITE(p, " for (int v = 0; v < 4; ++v) {\n"); WRITE(p, " for (int u = 0; u < 4; ++u) {\n"); - WRITE(p, " float f = weights_u[u] * weights_v[v];\n"); - WRITE(p, " if (f != 0.0)\n"); - WRITE(p, " pos += f * points[v * 4 + u];\n"); + WRITE(p, " pos += weights_u[u] * weights_v[v] * points[idx++];\n"); WRITE(p, " }\n"); WRITE(p, " }\n"); WRITE(p, " return pos;\n"); From de5975f13eb02a0be3adcd447fc973c312ec7ccc Mon Sep 17 00:00:00 2001 From: xebra Date: Sat, 14 Jul 2018 06:40:50 +0900 Subject: [PATCH 047/347] [spline/bezier]Reduce multiplications in the shaders from 16 to 4. --- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 3 ++- GPU/GLES/VertexShaderGeneratorGLES.cpp | 3 ++- GPU/Vulkan/VertexShaderGeneratorVulkan.cpp | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 5f5a98f117..c43516e556 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -289,8 +289,9 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage WRITE(p, " float%d pos = float%d(%s);\n", i, i, init[i - 2]); WRITE(p, " int idx = 0;\n"); WRITE(p, " for (int v = 0; v < 4; ++v) {\n"); + WRITE(p, " float4 w = weights_u * weights_v[v];\n"); WRITE(p, " for (int u = 0; u < 4; ++u) {\n"); - WRITE(p, " pos += weights_u[u] * weights_v[v] * points[idx++];\n"); + WRITE(p, " pos += w[u] * points[idx++];\n"); WRITE(p, " }\n"); WRITE(p, " }\n"); WRITE(p, " return pos;\n"); diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index 714c8f322b..63e83b2465 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -392,8 +392,9 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, WRITE(p, " vec%d pos = vec%d(0.0);\n", i, i); WRITE(p, " int idx = 0;\n"); WRITE(p, " for (int v = 0; v < 4; ++v) {\n"); + WRITE(p, " vec4 w = weights_u * weights_v[v];\n"); WRITE(p, " for (int u = 0; u < 4; ++u) {\n"); - WRITE(p, " pos += weights_u[u] * weights_v[v] * points[idx++];\n"); + WRITE(p, " pos += w[u] * points[idx++];\n"); WRITE(p, " }\n"); WRITE(p, " }\n"); WRITE(p, " return pos;\n"); diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index f1230f2829..6aa72b31b3 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -241,8 +241,9 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { WRITE(p, " vec%d pos = vec%d(0.0);\n", i, i); WRITE(p, " int idx = 0;\n"); WRITE(p, " for (int v = 0; v < 4; ++v) {\n"); + WRITE(p, " vec4 w = weights_u * weights_v[v];\n"); WRITE(p, " for (int u = 0; u < 4; ++u) {\n"); - WRITE(p, " pos += weights_u[u] * weights_v[v] * points[idx++];\n"); + WRITE(p, " pos += w[u] * points[idx++];\n"); WRITE(p, " }\n"); WRITE(p, " }\n"); WRITE(p, " return pos;\n"); From d4a667397c9950d8112b70e9c55c04dd69ea9b9e Mon Sep 17 00:00:00 2001 From: xebra Date: Sat, 14 Jul 2018 09:40:13 +0900 Subject: [PATCH 048/347] [spline/bezier]Improve shader uniforms a bit. --- GPU/Common/ShaderUniforms.cpp | 2 +- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 10 +++++----- GPU/GLES/ShaderManagerGLES.cpp | 8 ++++---- GPU/GLES/ShaderManagerGLES.h | 2 +- GPU/GLES/VertexShaderGeneratorGLES.cpp | 11 ++++++----- GPU/GPUCommon.cpp | 13 ++++++++----- GPU/GPUState.h | 2 +- GPU/Vulkan/VertexShaderGeneratorVulkan.cpp | 13 ++++++------- 8 files changed, 32 insertions(+), 29 deletions(-) diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index 6fcdfa311e..ea152d260d 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -240,7 +240,7 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView } if (dirtyUniforms & DIRTY_BEZIERSPLINE) { - ub->spline_counts = BytesToUint32(gstate_c.spline_num_patches_u, gstate_c.spline_num_patches_v, gstate_c.spline_tess_u, gstate_c.spline_tess_v); + ub->spline_counts = BytesToUint32(gstate_c.spline_num_patches_u, gstate_c.spline_num_points_u, gstate_c.spline_tess_u, gstate_c.spline_tess_v); } if (dirtyUniforms & DIRTY_DEPAL) { diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index c43516e556..13d57125a9 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -309,12 +309,12 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage 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, " int spline_num_patches_u = int(u_spline_counts & 0xff);\n"); + WRITE(p, " int spline_num_points_u = int((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, " int u = In.instanceId %% spline_num_patches_u;\n"); + WRITE(p, " int v = In.instanceId / spline_num_patches_u;\n"); WRITE(p, " int2 patch_pos = int2(u, v);\n"); WRITE(p, " int2 vertex_pos = int2(In.position.xy);\n"); if (doSpline) { @@ -329,7 +329,7 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage 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, " index = (%i + v%s) * spline_num_points_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); diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 1df6f865cf..200642f104 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -163,7 +163,7 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs, queries.push_back({ &u_tess_weights_u, "u_tess_weights_u" }); queries.push_back({ &u_tess_weights_v, "u_tess_weights_v" }); queries.push_back({ &u_spline_tess, "u_spline_tess" }); - queries.push_back({ &u_spline_num_patches, "u_spline_num_patches" }); + queries.push_back({ &u_spline_counts, "u_spline_counts" }); queries.push_back({ &u_depal, "u_depal" }); attrMask = vs->GetAttrMask(); @@ -569,9 +569,9 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid) { int tess[] = { gstate_c.spline_tess_u, gstate_c.spline_tess_v }; render_->SetUniformI(&u_spline_tess, 2, tess); } - if (u_spline_num_patches != -1) { - int num_patches[] = { gstate_c.spline_num_patches_u, gstate_c.spline_num_patches_v }; - render_->SetUniformI(&u_spline_num_patches, 2, num_patches); + if (u_spline_counts != -1) { + int counts[] = { gstate_c.spline_num_patches_u, gstate_c.spline_num_points_u }; + render_->SetUniformI(&u_spline_counts, 2, counts); } } } diff --git a/GPU/GLES/ShaderManagerGLES.h b/GPU/GLES/ShaderManagerGLES.h index b335099f74..f77c60a4a0 100644 --- a/GPU/GLES/ShaderManagerGLES.h +++ b/GPU/GLES/ShaderManagerGLES.h @@ -122,7 +122,7 @@ public: int u_tess_weights_u; int u_tess_weights_v; int u_spline_tess; - int u_spline_num_patches; + int u_spline_counts; }; // Real public interface diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index 63e83b2465..41a1071f9b 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -383,7 +383,7 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, WRITE(p, "uniform sampler2D u_tess_weights_u;\n"); WRITE(p, "uniform sampler2D u_tess_weights_v;\n"); - WRITE(p, "uniform ivec2 u_spline_num_patches;\n"); + WRITE(p, "uniform ivec2 u_spline_counts;\n"); WRITE(p, "uniform ivec2 u_spline_tess;\n"); for (int i = 2; i <= 4; i++) { @@ -412,10 +412,11 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, WRITE(p, "};\n"); WRITE(p, "void tessellate(out Tess tess) {\n"); + WRITE(p, " int spline_num_patches_u = u_spline_counts[0];\n"); + WRITE(p, " int spline_num_points_u = u_spline_counts[1];\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, " int u = gl_InstanceID %% spline_num_patches_u;\n"); + WRITE(p, " int v = gl_InstanceID / spline_num_patches_u;\n"); WRITE(p, " ivec2 patch_pos = ivec2(u, v);\n"); WRITE(p, " ivec2 vertex_pos = ivec2(position.xy);\n"); if (doSpline) { @@ -429,7 +430,7 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, 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, " int index = (i + v%s) * spline_num_points_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); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 2bdd7d4d7d..d3b24ba58e 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1761,9 +1761,12 @@ void GPUCommon::Execute_Bezier(u32 op, u32 diff) { gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); gstate_c.bezier = true; int num_patches_u = (bz_ucount - 1) / 3; - if (gstate_c.spline_num_patches_u != num_patches_u) { + bool patchesChanged = gstate_c.spline_num_patches_u != num_patches_u; + bool countsChanged = gstate_c.spline_num_points_u != bz_ucount; + if (patchesChanged || countsChanged) { gstate_c.Dirty(DIRTY_BEZIERSPLINE); gstate_c.spline_num_patches_u = num_patches_u; + gstate_c.spline_num_points_u = bz_ucount; } } @@ -1828,15 +1831,15 @@ void GPUCommon::Execute_Spline(u32 op, u32 diff) { int tess_u = gstate.getPatchDivisionU(); int tess_v = gstate.getPatchDivisionV(); int num_patches_u = sp_ucount - 3; - int num_patches_v = sp_vcount - 3; bool divsChanged = gstate_c.spline_tess_u != tess_u || gstate_c.spline_tess_v != tess_v; - bool patchesChanged = gstate_c.spline_num_patches_u != num_patches_u || gstate_c.spline_num_patches_v != num_patches_v; - if (divsChanged || patchesChanged) { + bool patchesChanged = gstate_c.spline_num_patches_u != num_patches_u; + bool countsChanged = gstate_c.spline_num_points_u != sp_ucount; + if (divsChanged || patchesChanged || countsChanged) { gstate_c.Dirty(DIRTY_BEZIERSPLINE); gstate_c.spline_tess_u = tess_u; gstate_c.spline_tess_v = tess_v; gstate_c.spline_num_patches_u = num_patches_u; - gstate_c.spline_num_patches_v = num_patches_v; + gstate_c.spline_num_points_u = sp_ucount; } } diff --git a/GPU/GPUState.h b/GPU/GPUState.h index ce5d7116d3..d0287c3bcb 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -605,7 +605,7 @@ struct GPUStateCache { int spline_tess_u; int spline_tess_v; int spline_num_patches_u; - int spline_num_patches_v; + int spline_num_points_u; bool useShaderDepal; GEBufferFormat depalFramebufferFormat; diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index 6aa72b31b3..8f3ca2baa4 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -261,13 +261,12 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { 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, " int spline_num_patches_u = int(base.spline_counts & 0xff);\n"); + WRITE(p, " int spline_num_points_u = int((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"); + // Calculate current patch position and vertex position(index for the weights) + WRITE(p, " int u = gl_InstanceIndex %% spline_num_patches_u;\n"); + WRITE(p, " int v = gl_InstanceIndex / spline_num_patches_u;\n"); WRITE(p, " ivec2 patch_pos = ivec2(u, v);\n"); WRITE(p, " ivec2 vertex_pos = ivec2(position.xy);\n"); if (doSpline) { @@ -281,7 +280,7 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { 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, " int idx = (i + v%s) * spline_num_points_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"); From 453e274fbea19f94ea0821eb546c273ea829f659 Mon Sep 17 00:00:00 2001 From: xebra Date: Wed, 18 Jul 2018 00:52:20 +0900 Subject: [PATCH 049/347] [spline/bezier]Fix around vertex type flags. --- GPU/Common/DrawEngineCommon.cpp | 2 -- GPU/Common/ShaderId.cpp | 3 ++ GPU/Common/ShaderId.h | 2 +- GPU/D3D11/DrawEngineD3D11.cpp | 2 -- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 34 +++++++++----------- GPU/GLES/DrawEngineGLES.cpp | 7 ++--- GPU/GLES/VertexShaderGeneratorGLES.cpp | 36 +++++++++------------- GPU/Vulkan/VertexShaderGeneratorVulkan.cpp | 34 +++++++++----------- 8 files changed, 52 insertions(+), 68 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 0d2a8de032..abe7e7cf2d 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -760,7 +760,5 @@ void TessellationDataTransfer::CopyControlPoints(float *pos, float *tex, float * memcpy(col, Vec4f::FromRGBA(points[i]->color_32).AsArray(), 4 * sizeof(float)); col += colStride; } - } else { - memcpy(col, Vec4f::FromRGBA(points[0]->color_32).AsArray(), 4 * sizeof(float)); } } diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index 83bbd08e3e..e7ed0b4e87 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -53,6 +53,7 @@ std::string VertexShaderDesc(const ShaderID &id) { if (id.Bit(VS_BIT_SPLINE)) desc << "Spline "; if (id.Bit(VS_BIT_HAS_COLOR_TESS)) desc << "TessC "; if (id.Bit(VS_BIT_HAS_TEXCOORD_TESS)) desc << "TessT "; + if (id.Bit(VS_BIT_HAS_NORMAL_TESS)) desc << "TessN "; if (id.Bit(VS_BIT_NORM_REVERSE_TESS)) desc << "TessRevN "; return desc.str(); @@ -73,6 +74,7 @@ void ComputeVertexShaderID(ShaderID *id_out, u32 vertType, bool useHWTransform) bool doSpline = gstate_c.spline; bool hasColorTess = (gstate.vertType & GE_VTYPE_COL_MASK) != 0 && (doBezier || doSpline); bool hasTexcoordTess = (gstate.vertType & GE_VTYPE_TC_MASK) != 0 && (doBezier || doSpline); + bool hasNormalTess = (gstate.vertType & GE_VTYPE_NRM_MASK) != 0 && (doBezier || doSpline); bool enableFog = gstate.isFogEnabled() && !isModeThrough && !gstate.isModeClear(); bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !isModeThrough; @@ -139,6 +141,7 @@ void ComputeVertexShaderID(ShaderID *id_out, u32 vertType, bool useHWTransform) id.SetBit(VS_BIT_SPLINE, doSpline); id.SetBit(VS_BIT_HAS_COLOR_TESS, hasColorTess); id.SetBit(VS_BIT_HAS_TEXCOORD_TESS, hasTexcoordTess); + id.SetBit(VS_BIT_HAS_NORMAL_TESS, hasNormalTess); id.SetBit(VS_BIT_NORM_REVERSE_TESS, gstate.isPatchNormalsReversed()); } } diff --git a/GPU/Common/ShaderId.h b/GPU/Common/ShaderId.h index 740e321fe8..573da9c3f3 100644 --- a/GPU/Common/ShaderId.h +++ b/GPU/Common/ShaderId.h @@ -24,7 +24,7 @@ enum { VS_BIT_HAS_COLOR_TESS = 12, // 1 bit VS_BIT_HAS_TEXCOORD_TESS = 13, // 1 bit VS_BIT_NORM_REVERSE_TESS = 14, // 1 bit - // 15 is free. + VS_BIT_HAS_NORMAL_TESS = 15, // 1 bit VS_BIT_UVGEN_MODE = 16, VS_BIT_UVPROJ_MODE = 18, // 2, can overlap with LS0 VS_BIT_LS0 = 18, // 2 diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 537951fb49..91d31ff40c 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -734,8 +734,6 @@ void TessellationDataTransferD3D11::SendDataToShader(const SimpleVertex *const * float *tex = (float *)(data + offsetof(TessData, uv)); float *col = (float *)(data + offsetof(TessData, color)); int stride = sizeof(TessData) / sizeof(float); - bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0; - bool hasTexCoord = (vertType & GE_VTYPE_TC_MASK) != 0; CopyControlPoints(pos, tex, col, stride, stride, stride, points, size, vertType); diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 13d57125a9..790c33e85f 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -86,6 +86,7 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage bool doSpline = id.Bit(VS_BIT_SPLINE); bool hasColorTess = id.Bit(VS_BIT_HAS_COLOR_TESS); bool hasTexcoordTess = id.Bit(VS_BIT_HAS_TEXCOORD_TESS); + bool hasNormalTess = id.Bit(VS_BIT_HAS_NORMAL_TESS); bool flipNormalTess = id.Bit(VS_BIT_NORM_REVERSE_TESS); DoLightComputation doLight[4] = { LIGHT_OFF, LIGHT_OFF, LIGHT_OFF, LIGHT_OFF }; @@ -300,11 +301,10 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage WRITE(p, "struct Tess {\n"); WRITE(p, " float3 pos;\n"); - if (doTexture && hasTexcoord) + if (doTexture) WRITE(p, " float2 tex;\n"); - if (hasColor) - WRITE(p, " float4 col;\n"); - if (hasNormal) + WRITE(p, " float4 col;\n"); + if (hasNormalTess) WRITE(p, " float3 nrm;\n"); WRITE(p, "};\n"); @@ -331,9 +331,9 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage for (int j = 0; j < 4; j++) { WRITE(p, " index = (%i + v%s) * spline_num_points_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) + if (doTexture && hasTexcoordTess) WRITE(p, " _tex[%i] = tess_data[index].tex;\n", i * 4 + j); - if (hasColor && hasColorTess) + if (hasColorTess) WRITE(p, " _col[%i] = tess_data[index].col;\n", i * 4 + j); } } @@ -350,19 +350,17 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage // Tessellate WRITE(p, " tess.pos = tess_sample(_pos, basis_u, basis_v);\n"); - if (doTexture && hasTexcoord) { + if (doTexture) { 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) { + if (hasColorTess) + WRITE(p, " tess.col = tess_sample(_col, basis_u, basis_v);\n"); + else + WRITE(p, " tess.col = u_matambientalpha;\n"); + if (hasNormalTess) { // 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"); @@ -433,7 +431,7 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage WRITE(p, " tessellate(In, tess);\n"); WRITE(p, " float3 worldpos = mul(float4(tess.pos.xyz, 1.0), u_world);\n"); - if (hasNormal) + if (hasNormalTess) 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"); @@ -539,6 +537,7 @@ 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) { + // TODO: Probably, should use hasColorTess but FF4 has a problem with drawing the background. 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"; @@ -694,10 +693,7 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage } } else { if (hasTexcoord) { - if (doBezier || doSpline) - 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"); + WRITE(p, " Out.v_texcoord = float3(In.texcoord.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n"); } else { WRITE(p, " Out.v_texcoord = float3(u_uvscaleoffset.zw, 0.0);\n"); } diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 957eda68bc..5dde8b1eb9 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -659,11 +659,10 @@ bool DrawEngineGLES::IsCodePtrVertexDecoder(const u8 *ptr) const { void TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) { bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0; bool hasTexCoord = (vertType & GE_VTYPE_TC_MASK) != 0; - int sizeColor = hasColor ? size : 1; float *pos = new float[size * 4]; float *tex = hasTexCoord ? new float[size * 4] : nullptr; - float *col = new float[sizeColor * 4]; + float *col = hasColor ? new float[size * 4] : nullptr; int stride = 4; CopyControlPoints(pos, tex, col, stride, stride, stride, points, size, vertType); @@ -683,7 +682,8 @@ void TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *p if (hasTexCoord) renderManager_->TextureSubImage(data_tex[0], 0, 0, 1, size, 1, GL_RGBA, GL_FLOAT, (u8 *)tex, GLRAllocType::NEW); // Color - renderManager_->TextureSubImage(data_tex[0], 0, 0, 2, sizeColor, 1, GL_RGBA, GL_FLOAT, (u8 *)col, GLRAllocType::NEW); + if (hasColor) + renderManager_->TextureSubImage(data_tex[0], 0, 0, 2, size, 1, GL_RGBA, GL_FLOAT, (u8 *)col, GLRAllocType::NEW); // Weight U if (data_tex[1]) @@ -700,7 +700,6 @@ void TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *p renderManager_->TextureImage(data_tex[2], 0, weights.size_v * 2, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT, (uint8_t *)weights.v, GLRAllocType::NONE, false); renderManager_->FinalizeTexture(data_tex[2], 0, false); renderManager_->BindTexture(TEX_SLOT_SPLINE_WEIGHTS_V, data_tex[2]); - } void TessellationDataTransferGLES::EndFrame() { diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index 41a1071f9b..6ac31d2be0 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -193,6 +193,7 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, bool doSpline = id.Bit(VS_BIT_SPLINE); bool hasColorTess = id.Bit(VS_BIT_HAS_COLOR_TESS); bool hasTexcoordTess = id.Bit(VS_BIT_HAS_TEXCOORD_TESS); + bool hasNormalTess = id.Bit(VS_BIT_HAS_NORMAL_TESS); bool flipNormalTess = id.Bit(VS_BIT_NORM_REVERSE_TESS); const char *shading = ""; @@ -403,11 +404,10 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, WRITE(p, "struct Tess {\n"); WRITE(p, " vec3 pos;\n"); - if (doTexture && hasTexcoord) + if (doTexture) WRITE(p, " vec2 tex;\n"); - if (hasColor) - WRITE(p, " vec4 col;\n"); - if (hasNormal) + WRITE(p, " vec4 col;\n"); + if (hasNormalTess) WRITE(p, " vec3 nrm;\n"); WRITE(p, "};\n"); @@ -432,9 +432,9 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, WRITE(p, " for (int j = 0; j < 4; j++) {\n"); WRITE(p, " int index = (i + v%s) * spline_num_points_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) + if (doTexture && hasTexcoordTess) WRITE(p, " _tex[i * 4 + j] = %s(u_tess_points, ivec2(index, 1), 0).xy;\n", texelFetch); - if (hasColor && hasColorTess) + if (hasColorTess) WRITE(p, " _col[i * 4 + j] = %s(u_tess_points, ivec2(index, 2), 0).rgba;\n", texelFetch); WRITE(p, " }\n"); WRITE(p, " }\n"); @@ -451,19 +451,17 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, // Tessellate WRITE(p, " tess.pos = tess_sample(_pos, basis_u, basis_v);\n"); - if (doTexture && hasTexcoord) { + if (doTexture) { 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) { + if (hasColorTess) + WRITE(p, " tess.col = tess_sample(_col, basis_u, basis_v);\n"); + else + WRITE(p, " tess.col = u_matambientalpha;\n"); + if (hasNormalTess) { // 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)"); @@ -523,7 +521,7 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, WRITE(p, " tessellate(tess);\n"); WRITE(p, " vec3 worldpos = (u_world * vec4(tess.pos.xyz, 1.0)).xyz;\n"); - if (hasNormal) { + if (hasNormalTess) { 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"); @@ -628,6 +626,7 @@ 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) { + // TODO: Probably, should use hasColorTess but FF4 has a problem with drawing the background. 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"; @@ -775,8 +774,6 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, if (scaleUV) { if (hasTexcoord) { if (doBezier || doSpline) - // TODO: Need fix? - // Fix to avoid temporarily texture animation bug with hardware tessellation. 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"); @@ -785,10 +782,7 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, } } else { if (hasTexcoord) { - if (doBezier || doSpline) - 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"); + WRITE(p, " v_texcoord = vec3(texcoord.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n"); } else { WRITE(p, " v_texcoord = vec3(u_uvscaleoffset.zw, 0.0);\n"); } diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index 8f3ca2baa4..9f91889c52 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -133,6 +133,7 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { bool doSpline = id.Bit(VS_BIT_SPLINE); bool hasColorTess = id.Bit(VS_BIT_HAS_COLOR_TESS); bool hasTexcoordTess = id.Bit(VS_BIT_HAS_TEXCOORD_TESS); + bool hasNormalTess = id.Bit(VS_BIT_HAS_NORMAL_TESS); bool flipNormalTess = id.Bit(VS_BIT_NORM_REVERSE_TESS); WRITE(p, "\n"); @@ -252,11 +253,10 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { WRITE(p, "struct Tess {\n"); WRITE(p, " vec3 pos;\n"); - if (doTexture && hasTexcoord) + if (doTexture) WRITE(p, " vec2 tex;\n"); - if (hasColor) - WRITE(p, " vec4 col;\n"); - if (hasNormal) + WRITE(p, " vec4 col;\n"); + if (hasNormalTess) WRITE(p, " vec3 nrm;\n"); WRITE(p, "};\n"); @@ -282,9 +282,9 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { WRITE(p, " for (int j = 0; j < 4; j++) {\n"); WRITE(p, " int idx = (i + v%s) * spline_num_points_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) + if (doTexture && hasTexcoordTess) WRITE(p, " _tex[i * 4 + j] = tess_data.data[idx].uv.xy;\n"); - if (hasColor && hasColorTess) + if (hasColorTess) WRITE(p, " _col[i * 4 + j] = tess_data.data[idx].color;\n"); WRITE(p, " }\n"); WRITE(p, " }\n"); @@ -301,19 +301,17 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { // Tessellate WRITE(p, " tess.pos = tess_sample(_pos, basis_u, basis_v);\n"); - if (doTexture && hasTexcoord) { + if (doTexture) { 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) { + if (hasColorTess) + WRITE(p, " tess.col = tess_sample(_col, basis_u, basis_v);\n"); + else + WRITE(p, " tess.col = base.matambientalpha;\n"); + if (hasNormalTess) { // 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"); @@ -373,7 +371,7 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { WRITE(p, " tessellate(tess);\n"); WRITE(p, " vec3 worldpos = vec4(tess.pos.xyz, 1.0) * base.world_mtx;\n"); - if (hasNormal) { + if (hasNormalTess) { 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"); @@ -431,6 +429,7 @@ 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) { + // TODO: Probably, should use hasColorTess but FF4 has a problem with drawing the background. 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"; @@ -583,10 +582,7 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { } } else { if (hasTexcoord) { - if (doBezier || doSpline) - 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"); + WRITE(p, " v_texcoord = vec3(texcoord.xy * base.uvscaleoffset.xy + base.uvscaleoffset.zw, 0.0);\n"); } else { WRITE(p, " v_texcoord = vec3(base.uvscaleoffset.zw, 0.0);\n"); } From 03b9492f086e63bd96af8219fc4ab0d9d8d94f9e Mon Sep 17 00:00:00 2001 From: xebra Date: Sat, 21 Jul 2018 00:18:34 +0900 Subject: [PATCH 050/347] [spline/bezier]Sharing textures to avoid heavily textures creation/deletion in one frame. At least, it occurs about 1000 and very slow down in Pursuit Force. --- GPU/GLES/DrawEngineGLES.cpp | 40 +++++++++++++++++------------ GPU/GLES/DrawEngineGLES.h | 1 + ext/native/thin3d/GLQueueRunner.cpp | 36 ++++++++++++-------------- ext/native/thin3d/GLQueueRunner.h | 26 +++++++++---------- ext/native/thin3d/GLRenderManager.h | 25 +++++++++--------- 5 files changed, 67 insertions(+), 61 deletions(-) diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 5dde8b1eb9..749dae8780 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -669,13 +669,14 @@ void TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *p // Removed the 1D texture support, it's unlikely to be relevant for performance. // Control Points - if (data_tex[0]) - renderManager_->DeleteTexture(data_tex[0]); - data_tex[0] = renderManager_->CreateTexture(GL_TEXTURE_2D); - renderManager_->TextureImage(data_tex[0], 0, size, 3, GL_RGBA32F, GL_RGBA, GL_FLOAT, (u8 *)nullptr, GLRAllocType::NONE, false); - renderManager_->FinalizeTexture(data_tex[0], 0, false); + if (prevSize < size) { + prevSize = size; + if (!data_tex[0]) + data_tex[0] = renderManager_->CreateTexture(GL_TEXTURE_2D); + renderManager_->TextureImage(data_tex[0], 0, size, 3, GL_RGBA32F, GL_RGBA, GL_FLOAT, nullptr, GLRAllocType::NONE, false); + renderManager_->FinalizeTexture(data_tex[0], 0, false); + } renderManager_->BindTexture(TEX_SLOT_SPLINE_POINTS, data_tex[0]); - // Position renderManager_->TextureSubImage(data_tex[0], 0, 0, 0, size, 1, GL_RGBA, GL_FLOAT, (u8 *)pos, GLRAllocType::NEW); // Texcoord @@ -686,20 +687,26 @@ void TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *p renderManager_->TextureSubImage(data_tex[0], 0, 0, 2, size, 1, GL_RGBA, GL_FLOAT, (u8 *)col, GLRAllocType::NEW); // Weight U - if (data_tex[1]) - renderManager_->DeleteTexture(data_tex[1]); - data_tex[1] = renderManager_->CreateTexture(GL_TEXTURE_2D); - renderManager_->TextureImage(data_tex[1], 0, weights.size_u * 2, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT, (uint8_t *)weights.u, GLRAllocType::NONE, false); - renderManager_->FinalizeTexture(data_tex[1], 0, false); + if (prevSizeWU < weights.size_u) { + prevSizeWU = weights.size_u; + if (!data_tex[1]) + data_tex[1] = renderManager_->CreateTexture(GL_TEXTURE_2D); + renderManager_->TextureImage(data_tex[1], 0, weights.size_u * 2, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT, nullptr, GLRAllocType::NONE, false); + renderManager_->FinalizeTexture(data_tex[1], 0, false); + } renderManager_->BindTexture(TEX_SLOT_SPLINE_WEIGHTS_U, data_tex[1]); + renderManager_->TextureSubImage(data_tex[1], 0, 0, 0, weights.size_u * 2, 1, GL_RGBA, GL_FLOAT, (u8 *)weights.u, GLRAllocType::NONE); // Weight V - if (data_tex[2]) - renderManager_->DeleteTexture(data_tex[2]); - data_tex[2] = renderManager_->CreateTexture(GL_TEXTURE_2D); - renderManager_->TextureImage(data_tex[2], 0, weights.size_v * 2, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT, (uint8_t *)weights.v, GLRAllocType::NONE, false); - renderManager_->FinalizeTexture(data_tex[2], 0, false); + if (prevSizeWV < weights.size_v) { + prevSizeWV = weights.size_v; + if (!data_tex[2]) + data_tex[2] = renderManager_->CreateTexture(GL_TEXTURE_2D); + renderManager_->TextureImage(data_tex[2], 0, weights.size_v * 2, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT, nullptr, GLRAllocType::NONE, false); + renderManager_->FinalizeTexture(data_tex[2], 0, false); + } renderManager_->BindTexture(TEX_SLOT_SPLINE_WEIGHTS_V, data_tex[2]); + renderManager_->TextureSubImage(data_tex[2], 0, 0, 0, weights.size_v * 2, 1, GL_RGBA, GL_FLOAT, (u8 *)weights.v, GLRAllocType::NONE); } void TessellationDataTransferGLES::EndFrame() { @@ -709,4 +716,5 @@ void TessellationDataTransferGLES::EndFrame() { data_tex[i] = nullptr; } } + prevSize = prevSizeWU = prevSizeWV = 0; } diff --git a/GPU/GLES/DrawEngineGLES.h b/GPU/GLES/DrawEngineGLES.h index 52605374d9..9870adacd2 100644 --- a/GPU/GLES/DrawEngineGLES.h +++ b/GPU/GLES/DrawEngineGLES.h @@ -113,6 +113,7 @@ public: class TessellationDataTransferGLES : public TessellationDataTransfer { private: GLRTexture *data_tex[3]{}; + int prevSize = 0, prevSizeWU = 0, prevSizeWV = 0; GLRenderManager *renderManager_; public: TessellationDataTransferGLES(GLRenderManager *renderManager) diff --git a/ext/native/thin3d/GLQueueRunner.cpp b/ext/native/thin3d/GLQueueRunner.cpp index d12ba97d49..5db058262a 100644 --- a/ext/native/thin3d/GLQueueRunner.cpp +++ b/ext/native/thin3d/GLQueueRunner.cpp @@ -328,26 +328,6 @@ void GLQueueRunner::RunInitSteps(const std::vector &steps, bool ski CHECK_GL_ERROR_IF_DEBUG(); break; } - case GLRInitStepType::TEXTURE_SUBIMAGE: - { - GLRTexture *tex = step.texture_subimage.texture; - CHECK_GL_ERROR_IF_DEBUG(); - if (boundTexture != tex->texture) { - glBindTexture(tex->target, tex->texture); - boundTexture = tex->texture; - } - if (!step.texture_subimage.data) - Crash(); - // For things to show in RenderDoc, need to split into glTexImage2D(..., nullptr) and glTexSubImage. - glTexSubImage2D(tex->target, step.texture_subimage.level, step.texture_subimage.x, step.texture_subimage.y, step.texture_subimage.width, step.texture_subimage.height, step.texture_subimage.format, step.texture_subimage.type, step.texture_subimage.data); - if (step.texture_subimage.allocType == GLRAllocType::ALIGNED) { - FreeAlignedMemory(step.texture_subimage.data); - } else if (step.texture_subimage.allocType == GLRAllocType::NEW) { - delete[] step.texture_subimage.data; - } - CHECK_GL_ERROR_IF_DEBUG(); - break; - } case GLRInitStepType::TEXTURE_FINALIZE: { CHECK_GL_ERROR_IF_DEBUG(); @@ -1033,6 +1013,22 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) { } break; } + case GLRRenderCommand::TEXTURE_SUBIMAGE: + { + GLRTexture *tex = c.texture_subimage.texture; + // TODO: Need bind? + if (!c.texture_subimage.data) + Crash(); + // For things to show in RenderDoc, need to split into glTexImage2D(..., nullptr) and glTexSubImage. + glTexSubImage2D(tex->target, c.texture_subimage.level, c.texture_subimage.x, c.texture_subimage.y, c.texture_subimage.width, c.texture_subimage.height, c.texture_subimage.format, c.texture_subimage.type, c.texture_subimage.data); + if (c.texture_subimage.allocType == GLRAllocType::ALIGNED) { + FreeAlignedMemory(c.texture_subimage.data); + } else if (c.texture_subimage.allocType == GLRAllocType::NEW) { + delete[] c.texture_subimage.data; + } + CHECK_GL_ERROR_IF_DEBUG(); + break; + } case GLRRenderCommand::RASTER: if (c.raster.cullEnable) { if (!cullEnabled) { diff --git a/ext/native/thin3d/GLQueueRunner.h b/ext/native/thin3d/GLQueueRunner.h index 03420f6689..b7a1586d59 100644 --- a/ext/native/thin3d/GLQueueRunner.h +++ b/ext/native/thin3d/GLQueueRunner.h @@ -58,6 +58,7 @@ enum class GLRRenderCommand : uint8_t { DRAW, DRAW_INDEXED, PUSH_CONSTANTS, + TEXTURE_SUBIMAGE, }; // TODO: Bloated since the biggest struct decides the size. Will need something more efficient (separate structs with shared @@ -139,6 +140,18 @@ struct GLRRenderData { int slot; GLRTexture *texture; } texture; + struct { + GLRTexture *texture; + GLenum format; + GLenum type; + int level; + int x; + int y; + int width; + int height; + GLRAllocType allocType; + uint8_t *data; // owned, delete[]-d + } texture_subimage; struct { int slot; GLRFramebuffer *framebuffer; @@ -197,7 +210,6 @@ enum class GLRInitStepType : uint8_t { CREATE_FRAMEBUFFER, TEXTURE_IMAGE, - TEXTURE_SUBIMAGE, TEXTURE_FINALIZE, BUFFER_SUBDATA, }; @@ -252,18 +264,6 @@ struct GLRInitStep { bool linearFilter; uint8_t *data; // owned, delete[]-d } texture_image; - struct { - GLRTexture *texture; - GLenum format; - GLenum type; - int level; - int x; - int y; - int width; - int height; - GLRAllocType allocType; - uint8_t *data; // owned, delete[]-d - } texture_subimage; struct { GLRTexture *texture; int maxLevel; diff --git a/ext/native/thin3d/GLRenderManager.h b/ext/native/thin3d/GLRenderManager.h index 12bfea9dd7..9cc4ca4f7d 100644 --- a/ext/native/thin3d/GLRenderManager.h +++ b/ext/native/thin3d/GLRenderManager.h @@ -531,18 +531,19 @@ public: } void TextureSubImage(GLRTexture *texture, int level, int x, int y, int width, int height, GLenum format, GLenum type, uint8_t *data, GLRAllocType allocType = GLRAllocType::NEW) { - GLRInitStep step{ GLRInitStepType::TEXTURE_SUBIMAGE }; - step.texture_subimage.texture = texture; - step.texture_subimage.data = data; - step.texture_subimage.format = format; - step.texture_subimage.type = type; - step.texture_subimage.level = level; - step.texture_subimage.x = x; - step.texture_subimage.y = y; - step.texture_subimage.width = width; - step.texture_subimage.height = height; - step.texture_subimage.allocType = allocType; - initSteps_.push_back(step); + _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + GLRRenderData _data{ GLRRenderCommand::TEXTURE_SUBIMAGE }; + _data.texture_subimage.texture = texture; + _data.texture_subimage.data = data; + _data.texture_subimage.format = format; + _data.texture_subimage.type = type; + _data.texture_subimage.level = level; + _data.texture_subimage.x = x; + _data.texture_subimage.y = y; + _data.texture_subimage.width = width; + _data.texture_subimage.height = height; + _data.texture_subimage.allocType = allocType; + curRenderStep_->commands.push_back(_data); } void FinalizeTexture(GLRTexture *texture, int maxLevels, bool genMips) { From 8c279c0e25320839f941f40eff6ffe7d4786c28b Mon Sep 17 00:00:00 2001 From: xebra Date: Sat, 21 Jul 2018 17:01:03 +0900 Subject: [PATCH 051/347] [spline/bezier]Precalculate weights in the shaders using the outer product. --- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 20 ++++++++++------- GPU/GLES/VertexShaderGeneratorGLES.cpp | 25 +++++++++++++++------- GPU/Vulkan/VertexShaderGeneratorVulkan.cpp | 16 +++++++------- 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 790c33e85f..685a71e0b5 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -286,19 +286,22 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage const char *init[3] = { "0.0, 0.0", "0.0, 0.0, 0.0", "0.0, 0.0, 0.0, 0.0" }; for (int i = 2; i <= 4; i++) { // Define 3 types float2, float3, float4 - WRITE(p, "float%d tess_sample(in float%d points[16], float4 weights_u, float4 weights_v) {\n", i, i); + WRITE(p, "float%d tess_sample(in float%d points[16], float4x4 weights) {\n", i, i); WRITE(p, " float%d pos = float%d(%s);\n", i, i, init[i - 2]); WRITE(p, " int idx = 0;\n"); WRITE(p, " for (int v = 0; v < 4; ++v) {\n"); - WRITE(p, " float4 w = weights_u * weights_v[v];\n"); WRITE(p, " for (int u = 0; u < 4; ++u) {\n"); - WRITE(p, " pos += w[u] * points[idx++];\n"); + WRITE(p, " pos += weights[v][u] * points[idx++];\n"); WRITE(p, " }\n"); WRITE(p, " }\n"); WRITE(p, " return pos;\n"); WRITE(p, "}\n"); } + WRITE(p, "float4x4 outerProduct(float4 u, float4 v) {\n"); + WRITE(p, " return mul((float4x1)v, (float1x4)u);\n"); + WRITE(p, "}\n"); + WRITE(p, "struct Tess {\n"); WRITE(p, " float3 pos;\n"); if (doTexture) @@ -347,17 +350,18 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n"); WRITE(p, " basis_v = float4(basis_v.yzw, 0);\n"); } + WRITE(p, " float4x4 basis = outerProduct(basis_u, basis_v);\n"); // Tessellate - WRITE(p, " tess.pos = tess_sample(_pos, basis_u, basis_v);\n"); + WRITE(p, " tess.pos = tess_sample(_pos, basis);\n"); if (doTexture) { if (hasTexcoordTess) - WRITE(p, " tess.tex = tess_sample(_tex, basis_u, basis_v);\n"); + WRITE(p, " tess.tex = tess_sample(_tex, basis);\n"); else WRITE(p, " tess.tex = In.normal.xy + float2(patch_pos);\n"); } if (hasColorTess) - WRITE(p, " tess.col = tess_sample(_col, basis_u, basis_v);\n"); + WRITE(p, " tess.col = tess_sample(_col, basis);\n"); else WRITE(p, " tess.col = u_matambientalpha;\n"); if (hasNormalTess) { @@ -371,8 +375,8 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage 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 du = tess_sample(_pos, outerProduct(deriv_u, basis_v));\n"); + WRITE(p, " float3 dv = tess_sample(_pos, outerProduct(basis_u, deriv_v));\n"); WRITE(p, " tess.nrm = normalize(cross(du, dv));\n"); } WRITE(p, "}\n"); diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index 6ac31d2be0..6705f44b44 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -389,19 +389,27 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, for (int i = 2; i <= 4; i++) { // Define 3 types vec2, vec3, vec4 - WRITE(p, "vec%d tess_sample(in vec%d points[16], vec4 weights_u, vec4 weights_v) {\n", i, i); + WRITE(p, "vec%d tess_sample(in vec%d points[16], mat4 weights) {\n", i, i); WRITE(p, " vec%d pos = vec%d(0.0);\n", i, i); WRITE(p, " int idx = 0;\n"); WRITE(p, " for (int v = 0; v < 4; ++v) {\n"); - WRITE(p, " vec4 w = weights_u * weights_v[v];\n"); WRITE(p, " for (int u = 0; u < 4; ++u) {\n"); - WRITE(p, " pos += w[u] * points[idx++];\n"); + WRITE(p, " pos += weights[v][u] * points[idx++];\n"); WRITE(p, " }\n"); WRITE(p, " }\n"); WRITE(p, " return pos;\n"); WRITE(p, "}\n"); } + if (!gl_extensions.VersionGEThan(3, 0, 0)) { // For glsl version 1.10 + WRITE(p, "mat4 outerProduct(vec4 u, vec4 v) {\n"); + WRITE(p, " mat4 mat;\n"); + for (int v = 0; v < 4; ++v) + WRITE(p, " mat[%d] = u * v[%d];\n", v, v); + WRITE(p, " return mat;\n"); + WRITE(p, "}\n"); + } + WRITE(p, "struct Tess {\n"); WRITE(p, " vec3 pos;\n"); if (doTexture) @@ -448,17 +456,18 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n"); WRITE(p, " basis_v = vec4(basis_v.yzw, 0);\n"); } + WRITE(p, " mat4 basis = outerProduct(basis_u, basis_v);\n"); // Tessellate - WRITE(p, " tess.pos = tess_sample(_pos, basis_u, basis_v);\n"); + WRITE(p, " tess.pos = tess_sample(_pos, basis);\n"); if (doTexture) { if (hasTexcoordTess) - WRITE(p, " tess.tex = tess_sample(_tex, basis_u, basis_v);\n"); + WRITE(p, " tess.tex = tess_sample(_tex, basis);\n"); else WRITE(p, " tess.tex = normal.xy + vec2(patch_pos);\n"); } if (hasColorTess) - WRITE(p, " tess.col = tess_sample(_col, basis_u, basis_v);\n"); + WRITE(p, " tess.col = tess_sample(_col, basis);\n"); else WRITE(p, " tess.col = u_matambientalpha;\n"); if (hasNormalTess) { @@ -472,8 +481,8 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, 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 du = tess_sample(_pos, outerProduct(deriv_u, basis_v));\n"); + WRITE(p, " vec3 dv = tess_sample(_pos, outerProduct(basis_u, deriv_v));\n"); WRITE(p, " tess.nrm = normalize(cross(du, dv));\n"); } WRITE(p, "}\n"); diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index 9f91889c52..9bcf335a03 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -238,13 +238,12 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { for (int i = 2; i <= 4; i++) { // Define 3 types vec2, vec3, vec4 - WRITE(p, "vec%d tess_sample(in vec%d points[16], vec4 weights_u, vec4 weights_v) {\n", i, i); + WRITE(p, "vec%d tess_sample(in vec%d points[16], mat4 weights) {\n", i, i); WRITE(p, " vec%d pos = vec%d(0.0);\n", i, i); WRITE(p, " int idx = 0;\n"); WRITE(p, " for (int v = 0; v < 4; ++v) {\n"); - WRITE(p, " vec4 w = weights_u * weights_v[v];\n"); WRITE(p, " for (int u = 0; u < 4; ++u) {\n"); - WRITE(p, " pos += w[u] * points[idx++];\n"); + WRITE(p, " pos += weights[v][u] * points[idx++];\n"); WRITE(p, " }\n"); WRITE(p, " }\n"); WRITE(p, " return pos;\n"); @@ -298,17 +297,18 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n"); WRITE(p, " basis_v = vec4(basis_v.yzw, 0);\n"); } + WRITE(p, " mat4 basis = outerProduct(basis_u, basis_v);\n"); // Tessellate - WRITE(p, " tess.pos = tess_sample(_pos, basis_u, basis_v);\n"); + WRITE(p, " tess.pos = tess_sample(_pos, basis);\n"); if (doTexture) { if (hasTexcoordTess) - WRITE(p, " tess.tex = tess_sample(_tex, basis_u, basis_v);\n"); + WRITE(p, " tess.tex = tess_sample(_tex, basis);\n"); else WRITE(p, " tess.tex = normal.xy + vec2(patch_pos);\n"); } if (hasColorTess) - WRITE(p, " tess.col = tess_sample(_col, basis_u, basis_v);\n"); + WRITE(p, " tess.col = tess_sample(_col, basis);\n"); else WRITE(p, " tess.col = base.matambientalpha;\n"); if (hasNormalTess) { @@ -322,8 +322,8 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { 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 du = tess_sample(_pos, outerProduct(deriv_u, basis_v));\n"); + WRITE(p, " vec3 dv = tess_sample(_pos, outerProduct(basis_u, deriv_v));\n"); WRITE(p, " tess.nrm = normalize(cross(du, dv));\n"); } WRITE(p, "}\n"); From 3216a83a92a6f74cffbcdc8568e8f36b557d4637 Mon Sep 17 00:00:00 2001 From: xebra Date: Sat, 21 Jul 2018 19:46:14 +0900 Subject: [PATCH 052/347] [spline/bezier]Expand loops in the shaders. --- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 11 +++---- GPU/GLES/VertexShaderGeneratorGLES.cpp | 37 ++++++++++------------ GPU/Vulkan/VertexShaderGeneratorVulkan.cpp | 32 +++++++++---------- 3 files changed, 38 insertions(+), 42 deletions(-) diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 685a71e0b5..885d59e76d 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -288,12 +288,11 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage // Define 3 types float2, float3, float4 WRITE(p, "float%d tess_sample(in float%d points[16], float4x4 weights) {\n", i, i); WRITE(p, " float%d pos = float%d(%s);\n", i, i, init[i - 2]); - WRITE(p, " int idx = 0;\n"); - WRITE(p, " for (int v = 0; v < 4; ++v) {\n"); - WRITE(p, " for (int u = 0; u < 4; ++u) {\n"); - WRITE(p, " pos += weights[v][u] * points[idx++];\n"); - WRITE(p, " }\n"); - WRITE(p, " }\n"); + for (int v = 0; v < 4; ++v) { + for (int u = 0; u < 4; ++u) { + WRITE(p, " pos += weights[%i][%i] * points[%i];\n", v, u, v * 4 + u); + } + } WRITE(p, " return pos;\n"); WRITE(p, "}\n"); } diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index 6705f44b44..c9468bfccc 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -391,22 +391,18 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, // Define 3 types vec2, vec3, vec4 WRITE(p, "vec%d tess_sample(in vec%d points[16], mat4 weights) {\n", i, i); WRITE(p, " vec%d pos = vec%d(0.0);\n", i, i); - WRITE(p, " int idx = 0;\n"); - WRITE(p, " for (int v = 0; v < 4; ++v) {\n"); - WRITE(p, " for (int u = 0; u < 4; ++u) {\n"); - WRITE(p, " pos += weights[v][u] * points[idx++];\n"); - WRITE(p, " }\n"); - WRITE(p, " }\n"); + for (int v = 0; v < 4; ++v) { + for (int u = 0; u < 4; ++u) { + WRITE(p, " pos += weights[%i][%i] * points[%i];\n", v, u, v * 4 + u); + } + } WRITE(p, " return pos;\n"); WRITE(p, "}\n"); } if (!gl_extensions.VersionGEThan(3, 0, 0)) { // For glsl version 1.10 WRITE(p, "mat4 outerProduct(vec4 u, vec4 v) {\n"); - WRITE(p, " mat4 mat;\n"); - for (int v = 0; v < 4; ++v) - WRITE(p, " mat[%d] = u * v[%d];\n", v, v); - WRITE(p, " return mat;\n"); + WRITE(p, " return mat4(u * v[0], u * v[1], u * v[2], u * v[3]);\n"); WRITE(p, "}\n"); } @@ -436,16 +432,17 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, 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_num_points_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 && hasTexcoordTess) - WRITE(p, " _tex[i * 4 + j] = %s(u_tess_points, ivec2(index, 1), 0).xy;\n", texelFetch); - if (hasColorTess) - WRITE(p, " _col[i * 4 + j] = %s(u_tess_points, ivec2(index, 2), 0).rgba;\n", texelFetch); - WRITE(p, " }\n"); - WRITE(p, " }\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_num_points_u + (%i + u%s);\n", i, doBezier ? " * 3" : "", j, doBezier ? " * 3" : ""); + WRITE(p, " _pos[%i] = %s(u_tess_points, ivec2(index, 0), 0).xyz;\n", i * 4 + j, texelFetch); + if (doTexture && hasTexcoordTess) + WRITE(p, " _tex[%i] = %s(u_tess_points, ivec2(index, 1), 0).xy;\n", i * 4 + j, texelFetch); + if (hasColorTess) + WRITE(p, " _col[%i] = %s(u_tess_points, ivec2(index, 2), 0).rgba;\n", i * 4 + j, texelFetch); + } + } // 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)"); diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index 9bcf335a03..708e277021 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -240,12 +240,11 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { // Define 3 types vec2, vec3, vec4 WRITE(p, "vec%d tess_sample(in vec%d points[16], mat4 weights) {\n", i, i); WRITE(p, " vec%d pos = vec%d(0.0);\n", i, i); - WRITE(p, " int idx = 0;\n"); - WRITE(p, " for (int v = 0; v < 4; ++v) {\n"); - WRITE(p, " for (int u = 0; u < 4; ++u) {\n"); - WRITE(p, " pos += weights[v][u] * points[idx++];\n"); - WRITE(p, " }\n"); - WRITE(p, " }\n"); + for (int v = 0; v < 4; ++v) { + for (int u = 0; u < 4; ++u) { + WRITE(p, " pos += weights[%i][%i] * points[%i];\n", v, u, v * 4 + u); + } + } WRITE(p, " return pos;\n"); WRITE(p, "}\n"); } @@ -277,16 +276,17 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { 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_num_points_u + (j + u%s);\n", doBezier ? " * 3" : "", doBezier ? " * 3" : ""); - WRITE(p, " _pos[i * 4 + j] = tess_data.data[idx].pos.xyz;\n"); - if (doTexture && hasTexcoordTess) - WRITE(p, " _tex[i * 4 + j] = tess_data.data[idx].uv.xy;\n"); - if (hasColorTess) - WRITE(p, " _col[i * 4 + j] = tess_data.data[idx].color;\n"); - WRITE(p, " }\n"); - WRITE(p, " }\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_num_points_u + (%i + u%s);\n", i, doBezier ? " * 3" : "", j, doBezier ? " * 3" : ""); + WRITE(p, " _pos[%i] = tess_data.data[index].pos.xyz;\n", i * 4 + j); + if (doTexture && hasTexcoordTess) + WRITE(p, " _tex[%i] = tess_data.data[index].uv.xy;\n", i * 4 + j); + if (hasColorTess) + WRITE(p, " _col[%i] = tess_data.data[index].color;\n", i * 4 + j); + } + } // Basis polynomials as weight coefficients WRITE(p, " vec4 basis_u = tess_weights_u.data[vertex_pos.x].basis;\n"); From 98ddefbd5a8f52f56041266313eff1cf51c82653 Mon Sep 17 00:00:00 2001 From: xebra Date: Sat, 21 Jul 2018 23:00:28 +0900 Subject: [PATCH 053/347] [spline/bezier]Extract an if-check in the hot loops to the template parameter. --- GPU/Common/SplineCommon.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 6fb31015bb..e3718dad38 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -340,7 +340,7 @@ public: defcolor = points[0]->color_32; } - template + template void Tessellate(SimpleVertex *vertices, u16 *indices, int &count) { const float inv_u = 1.0f / (float)patch.tess_u; const float inv_v = 1.0f / (float)patch.tess_v; @@ -396,7 +396,7 @@ public: const Vec3f derivV = tess_pos.SampleV(wv.deriv); vert.nrm = Cross(derivU, derivV).Normalized(useSSE4); - if (patch.patchFacing) + if (patchFacing) vert.nrm *= -1.0f; } else { vert.nrm.SetZero(); @@ -414,7 +414,7 @@ public: void Tessellate(SimpleVertex *vertices, u16 *indices, int &count, u32 origVertType) { using TessFunc = void(SubdivisionSurface::*)(SimpleVertex *, u16 *, int &); - constexpr int NumParams = 4; + constexpr int NumParams = 5; static TemplateParameterDispatcherTess dispatcher; // Initialize only once const bool params[NumParams] = { @@ -422,6 +422,7 @@ public: (origVertType & GE_VTYPE_COL_MASK) != 0, (origVertType & GE_VTYPE_TC_MASK) != 0, cpu_info.bSSE4_1, + patch.patchFacing, }; TessFunc func = dispatcher.GetFunc(params); (this->*func)(vertices, indices, count); From a241058d7b809b34e5f1a4d52fafa6e2903d2182 Mon Sep 17 00:00:00 2001 From: xebra Date: Sun, 22 Jul 2018 01:11:23 +0900 Subject: [PATCH 054/347] [spline/bezier]Improve TemplateParameterDispatcher class macro to a real class. --- GPU/Common/SplineCommon.cpp | 5 +-- GPU/Common/SplineCommon.h | 75 +++++++++++++++++++++---------------- 2 files changed, 44 insertions(+), 36 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index e3718dad38..3495635417 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -409,13 +409,12 @@ public: patch.BuildIndex(indices, count); } - // Define class TemplateParameterDispatcherTess - TEMPLATE_PARAMETER_DISPATCHER(Tess, SubdivisionSurface::Tessellate); + TEMPLATE_PARAMETER_DISPATCHER_FUNCTION(Tess, SubdivisionSurface::Tessellate); void Tessellate(SimpleVertex *vertices, u16 *indices, int &count, u32 origVertType) { using TessFunc = void(SubdivisionSurface::*)(SimpleVertex *, u16 *, int &); constexpr int NumParams = 5; - static TemplateParameterDispatcherTess dispatcher; // Initialize only once + static TemplateParameterDispatcher dispatcher; // Initialize only once const bool params[NumParams] = { (origVertType & GE_VTYPE_NRM_MASK) != 0, diff --git a/GPU/Common/SplineCommon.h b/GPU/Common/SplineCommon.h index 7fa9585a9a..ebc82fa7dd 100644 --- a/GPU/Common/SplineCommon.h +++ b/GPU/Common/SplineCommon.h @@ -195,38 +195,47 @@ bool CanUseHardwareTessellation(GEPatchPrimType prim); void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, SplinePatchLocal &spatch, u32 origVertType, int maxVertices); void TessellateBezierPatch(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType, int maxVertices); -#define TEMPLATE_PARAMETER_DISPATCHER(NAME, FUNCNAME) \ -template \ -class TemplateParameterDispatcher##NAME { \ - /* Store all combinations of template functions into an array */ \ - template \ - struct Initializer { \ - Initializer(Func funcs[]) { \ - Initializer _true(funcs); \ - Initializer _false(funcs); \ - } \ - }; \ - /* Specialized for terminates the recursive loop */ \ - template \ - struct Initializer<0, Index, Params...> { \ - Initializer(Func funcs[]) { \ - funcs[Index] = &FUNCNAME; \ - } \ - }; \ - \ -private: \ - Func funcs[1 << NumParams]; /* Function pointers array */ \ -public: \ - TemplateParameterDispatcher##NAME() { \ - Initializer::Initializer(funcs); \ - } \ - \ - Func GetFunc(const bool params[]) const { \ - /* Convert bool parameters to index of the array */ \ - int param = 0; \ - for (int i = 0; i < NumParams; ++i) \ - param |= params[i] << i; \ - \ - return funcs[param]; \ +// Define function object for TemplateParameterDispatcher +#define TEMPLATE_PARAMETER_DISPATCHER_FUNCTION(NAME, FUNCNAME) \ +struct NAME { \ + template \ + static auto GetFunc() { \ + return &FUNCNAME; \ } \ }; + +template +class TemplateParameterDispatcher { + + /* Store all combinations of template functions into an array */ + template + struct Initializer { + static void Init(Func funcs[]) { + Initializer::Init(funcs); // true + Initializer::Init(funcs); // false + } + }; + /* Specialized for terminates the recursive loop */ + template + struct Initializer<0, Index, Params...> { + static void Init(Func funcs[]) { + funcs[Index] = Dispatcher::GetFunc(); + } + }; + +private: + Func funcs[1 << NumParams]; /* Function pointers array */ +public: + TemplateParameterDispatcher() { + Initializer::Init(funcs); + } + + Func GetFunc(const bool params[]) const { + /* Convert bool parameters to index of the array */ + int index = 0; + for (int i = 0; i < NumParams; ++i) + index |= params[i] << i; + + return funcs[index]; + } +}; From c4a8d80b61e360c99b7ba08a31d9d6b6cb64c99a Mon Sep 17 00:00:00 2001 From: xebra Date: Sun, 22 Jul 2018 11:22:17 +0900 Subject: [PATCH 055/347] [spline/bezier]Put the output buffers all in one structure. --- GPU/Common/SplineCommon.cpp | 47 ++++++++++++++++++++----------------- GPU/Common/SplineCommon.h | 6 +++++ 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 3495635417..06b896be8a 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -341,7 +341,7 @@ public: } template - void Tessellate(SimpleVertex *vertices, u16 *indices, int &count) { + void Tessellate(OutputBuffers &output) { const float inv_u = 1.0f / (float)patch.tess_u; const float inv_v = 1.0f / (float)patch.tess_v; @@ -375,7 +375,7 @@ public: const int index_v = patch.GetIndexV(patch_v, tile_v); const Weight &wv = weights.v[index_v]; - SimpleVertex &vert = vertices[patch.GetIndex(index_u, index_v, patch_u, patch_v)]; + SimpleVertex &vert = output.vertices[patch.GetIndex(index_u, index_v, patch_u, patch_v)]; // Tessellate vert.pos = tess_pos.SampleV(wv.basis); @@ -406,13 +406,13 @@ public: } } - patch.BuildIndex(indices, count); + patch.BuildIndex(output.indices, output.count); } TEMPLATE_PARAMETER_DISPATCHER_FUNCTION(Tess, SubdivisionSurface::Tessellate); - void Tessellate(SimpleVertex *vertices, u16 *indices, int &count, u32 origVertType) { - using TessFunc = void(SubdivisionSurface::*)(SimpleVertex *, u16 *, int &); + void Tessellate(OutputBuffers &output, u32 origVertType) { + using TessFunc = void(SubdivisionSurface::*)(OutputBuffers &); constexpr int NumParams = 5; static TemplateParameterDispatcher dispatcher; // Initialize only once @@ -424,23 +424,23 @@ public: patch.patchFacing, }; TessFunc func = dispatcher.GetFunc(params); - (this->*func)(vertices, indices, count); + (this->*func)(output); } }; template -static void SoftwareTessellation(SimpleVertex *vertices, u16 *indices, int &count, const Patch &patch, u32 origVertType, +static void SoftwareTessellation(OutputBuffers &output, const Patch &patch, u32 origVertType, const SimpleVertex *const *points, SimpleBufferManager &managedBuf, Cache &weightsCache) { u32 key_u = weightsCache.ToKey(patch.tess_u, patch.count_u, patch.type_u); u32 key_v = weightsCache.ToKey(patch.tess_v, patch.count_v, patch.type_v); Weight2D weights(weightsCache, key_u, key_v); SubdivisionSurface surface(managedBuf, points, patch, weights); - surface.Tessellate(vertices, indices, count, origVertType); + surface.Tessellate(output, origVertType); } template -static void HardwareTessellation(SimpleVertex *vertices, u16 *indices, int &count, const Patch &patch, u32 origVertType, +static void HardwareTessellation(OutputBuffers &output, const Patch &patch, u32 origVertType, const SimpleVertex *const *points, Cache &weightsCache, TessellationDataTransfer *tessDataTransfer) { u32 key_u = weightsCache.ToKey(patch.tess_u, patch.count_u, patch.type_u); u32 key_v = weightsCache.ToKey(patch.tess_v, patch.count_v, patch.type_v); @@ -454,7 +454,7 @@ static void HardwareTessellation(SimpleVertex *vertices, u16 *indices, int &coun float inv_v = 1.0f / (float)patch.tess_v; for (int tile_v = 0; tile_v <= patch.tess_v; ++tile_v) { for (int tile_u = 0; tile_u <= patch.tess_u; ++tile_u) { - SimpleVertex &vert = vertices[tile_v * (patch.tess_u + 1) + tile_u]; + SimpleVertex &vert = output.vertices[tile_v * (patch.tess_u + 1) + tile_u]; vert.pos.x = (float)tile_u; vert.pos.y = (float)tile_v; // For texcoord generation @@ -462,7 +462,7 @@ static void HardwareTessellation(SimpleVertex *vertices, u16 *indices, int &coun vert.nrm.y = (float)tile_v * inv_v; } } - BuildIndex(indices, count, patch.tess_u, patch.tess_v, patch.primType); + BuildIndex(output.indices, output.count, patch.tess_u, patch.tess_v, patch.primType); } void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indices, int tess_u, int tess_v, int count_u, int count_v, int type_u, int type_v, GEPatchPrimType prim_type, bool computeNormals, bool patchFacing, u32 vertType, int *bytesRead) { @@ -507,8 +507,10 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi for (int idx = 0; idx < count_u * count_v; idx++) points[idx] = simplified_control_points + (indices ? ConvertIndex(idx) : idx); - int count = 0; - u8 *dest = splineBuffer; + OutputBuffers output; + output.vertices = (SimpleVertex *)splineBuffer; + output.indices = quadIndices_; + output.count = 0; SplinePatchLocal patch; patch.tess_u = tess_u; @@ -523,11 +525,11 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi patch.patchFacing = patchFacing; if (CanUseHardwareTessellation(prim_type)) { - HardwareTessellation((SimpleVertex *)splineBuffer, quadIndices_, count, patch, origVertType, points, splineWeightsCache, tessDataTransfer); + HardwareTessellation(output, patch, origVertType, points, splineWeightsCache, tessDataTransfer); numPatches = patch.num_patches_u * patch.num_patches_v; } else { patch.Init(SPLINE_BUFFER_SIZE / vertexSize); - SoftwareTessellation((SimpleVertex *)splineBuffer, quadIndices_, count, patch, origVertType, points, managedBuf, splineWeightsCache); + SoftwareTessellation(output, patch, origVertType, points, managedBuf, splineWeightsCache); } u32 vertTypeWithIndex16 = (vertType & ~GE_VTYPE_IDX_MASK) | GE_VTYPE_IDX_16BIT; @@ -545,7 +547,7 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi uint32_t vertTypeID = GetVertTypeID(vertTypeWithIndex16, gstate.getUVGenMode()); int generatedBytesRead; - DispatchSubmitPrim(splineBuffer, quadIndices_, PatchPrimToPrim(prim_type), count, vertTypeID, &generatedBytesRead); + DispatchSubmitPrim(output.vertices, output.indices, PatchPrimToPrim(prim_type), output.count, vertTypeID, &generatedBytesRead); DispatchFlush(); @@ -598,9 +600,10 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi for (int idx = 0; idx < count_u * count_v; idx++) points[idx] = simplified_control_points + (indices ? ConvertIndex(idx) : idx); - int count = 0; - u8 *dest = splineBuffer; - u16 *inds = quadIndices_; + OutputBuffers output; + output.vertices = (SimpleVertex *)splineBuffer; + output.indices = quadIndices_; + output.count = 0; BezierPatch patch; patch.tess_u = tess_u; @@ -613,11 +616,11 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi patch.patchFacing = patchFacing; if (CanUseHardwareTessellation(prim_type)) { - HardwareTessellation((SimpleVertex *)splineBuffer, quadIndices_, count, patch, origVertType, points, bezierWeightsCache, tessDataTransfer); + HardwareTessellation(output, patch, origVertType, points, bezierWeightsCache, tessDataTransfer); numPatches = patch.num_patches_u * patch.num_patches_v; } else { patch.Init(SPLINE_BUFFER_SIZE / vertexSize); - SoftwareTessellation((SimpleVertex *)splineBuffer, quadIndices_, count, patch, origVertType, points, managedBuf, bezierWeightsCache); + SoftwareTessellation(output, patch, origVertType, points, managedBuf, bezierWeightsCache); } u32 vertTypeWithIndex16 = (vertType & ~GE_VTYPE_IDX_MASK) | GE_VTYPE_IDX_16BIT; @@ -634,7 +637,7 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi uint32_t vertTypeID = GetVertTypeID(vertTypeWithIndex16, gstate.getUVGenMode()); int generatedBytesRead; - DispatchSubmitPrim(splineBuffer, quadIndices_, PatchPrimToPrim(prim_type), count, vertTypeID, &generatedBytesRead); + DispatchSubmitPrim(output.vertices, output.indices, PatchPrimToPrim(prim_type), output.count, vertTypeID, &generatedBytesRead); DispatchFlush(); diff --git a/GPU/Common/SplineCommon.h b/GPU/Common/SplineCommon.h index ebc82fa7dd..bcb23e76b2 100644 --- a/GPU/Common/SplineCommon.h +++ b/GPU/Common/SplineCommon.h @@ -191,6 +191,12 @@ struct Weight2D { } }; +struct OutputBuffers { + SimpleVertex *vertices; + u16 *indices; + int count; +}; + bool CanUseHardwareTessellation(GEPatchPrimType prim); void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, SplinePatchLocal &spatch, u32 origVertType, int maxVertices); void TessellateBezierPatch(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType, int maxVertices); From 62aaf6336a928dddb932c231abc4f7d645a8918f Mon Sep 17 00:00:00 2001 From: xebra Date: Mon, 23 Jul 2018 23:11:58 +0900 Subject: [PATCH 056/347] Math3D: Something wrong with hand simd optimization in vec2, so it causes very slow down. However, compiler optimization is faster enough, so removed it. --- GPU/Math3D.h | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/GPU/Math3D.h b/GPU/Math3D.h index 04743436ea..292c63be05 100644 --- a/GPU/Math3D.h +++ b/GPU/Math3D.h @@ -1087,31 +1087,6 @@ __forceinline void Vec4::ToRGBA(u8 *rgba) const #if defined(_M_SSE) // Specialized for SIMD optimization -// Vec2 operation -template<> -inline void Vec2::operator += (const Vec2 &other) -{ - vec = _mm_add_ps(vec, other.vec); -} - -template<> -inline Vec2 Vec2::operator + (const Vec2 &other) const -{ - return Vec2(_mm_add_ps(vec, other.vec)); -} - -template<> -inline Vec2 Vec2::operator * (const Vec2 &other) const -{ - return Vec2(_mm_mul_ps(vec, other.vec)); -} - -template<> template<> -inline Vec2 Vec2::operator * (const float &other) const -{ - return Vec2(_mm_mul_ps(vec, _mm_set_ps1(other))); -} - // Vec3 operation template<> inline void Vec3::operator += (const Vec3 &other) From 66833513c02ebe14120c77d5b7833e229aa1ff23 Mon Sep 17 00:00:00 2001 From: xebra Date: Mon, 30 Jul 2018 19:36:41 +0900 Subject: [PATCH 057/347] [spline/bezier]Modify the weights cache variables to a template variable. --- GPU/Common/SplineCommon.cpp | 52 +++++++++++++++++++------------------ GPU/Common/SplineCommon.h | 7 +++++ 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 06b896be8a..8905653757 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -86,11 +86,11 @@ public: return weights; } - u32 ToKey(int tess, int count, int type) { + static u32 ToKey(int tess, int count, int type) { return tess; } - int CalcSize(int tess, int count) { + static int CalcSize(int tess, int count) { return tess + 1; } }; @@ -228,25 +228,25 @@ public: return weights; } - u32 ToKey(int tess, int count, int type) { + static u32 ToKey(int tess, int count, int type) { return tess | (count << 8) | (type << 16); } - void FromKey(u32 key, int &tess, int &count, int &type) { + static void FromKey(u32 key, int &tess, int &count, int &type) { tess = key & 0xFF; count = (key >> 8) & 0xFF; type = (key >> 16) & 0xFF; } - int CalcSize(int tess, int count) { + static int CalcSize(int tess, int count) { return (count - 3) * tess + 1; } }; -static WeightCache bezierWeightsCache; -static WeightCache splineWeightsCache; +template +static WeightCache weightsCache; void DrawEngineCommon::ClearSplineBezierWeights() { - bezierWeightsCache.Clear(); - splineWeightsCache.Clear(); + weightsCache.Clear(); + weightsCache.Clear(); } bool CanUseHardwareTessellation(GEPatchPrimType prim) { @@ -428,25 +428,27 @@ public: } }; -template +template static void SoftwareTessellation(OutputBuffers &output, const Patch &patch, u32 origVertType, - const SimpleVertex *const *points, SimpleBufferManager &managedBuf, Cache &weightsCache) { - u32 key_u = weightsCache.ToKey(patch.tess_u, patch.count_u, patch.type_u); - u32 key_v = weightsCache.ToKey(patch.tess_v, patch.count_v, patch.type_v); - Weight2D weights(weightsCache, key_u, key_v); + const SimpleVertex *const *points, SimpleBufferManager &managedBuf) { + using WeightType = Patch::WeightType; + u32 key_u = WeightType::ToKey(patch.tess_u, patch.count_u, patch.type_u); + u32 key_v = WeightType::ToKey(patch.tess_v, patch.count_v, patch.type_v); + Weight2D weights(weightsCache, key_u, key_v); SubdivisionSurface surface(managedBuf, points, patch, weights); surface.Tessellate(output, origVertType); } -template +template static void HardwareTessellation(OutputBuffers &output, const Patch &patch, u32 origVertType, - const SimpleVertex *const *points, Cache &weightsCache, TessellationDataTransfer *tessDataTransfer) { - u32 key_u = weightsCache.ToKey(patch.tess_u, patch.count_u, patch.type_u); - u32 key_v = weightsCache.ToKey(patch.tess_v, patch.count_v, patch.type_v); - Weight2D weights(weightsCache, key_u, key_v); - weights.size_u = weightsCache.CalcSize(patch.tess_u, patch.count_u); - weights.size_v = weightsCache.CalcSize(patch.tess_v, patch.count_v); + const SimpleVertex *const *points, TessellationDataTransfer *tessDataTransfer) { + using WeightType = Patch::WeightType; + u32 key_u = WeightType::ToKey(patch.tess_u, patch.count_u, patch.type_u); + u32 key_v = WeightType::ToKey(patch.tess_v, patch.count_v, patch.type_v); + Weight2D weights(weightsCache, key_u, key_v); + weights.size_u = WeightType::CalcSize(patch.tess_u, patch.count_u); + weights.size_v = WeightType::CalcSize(patch.tess_v, patch.count_v); tessDataTransfer->SendDataToShader(points, patch.count_u * patch.count_v, origVertType, weights); // Generating simple input vertices for the spline-computing vertex shader. @@ -525,11 +527,11 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi patch.patchFacing = patchFacing; if (CanUseHardwareTessellation(prim_type)) { - HardwareTessellation(output, patch, origVertType, points, splineWeightsCache, tessDataTransfer); + HardwareTessellation(output, patch, origVertType, points, tessDataTransfer); numPatches = patch.num_patches_u * patch.num_patches_v; } else { patch.Init(SPLINE_BUFFER_SIZE / vertexSize); - SoftwareTessellation(output, patch, origVertType, points, managedBuf, splineWeightsCache); + SoftwareTessellation(output, patch, origVertType, points, managedBuf); } u32 vertTypeWithIndex16 = (vertType & ~GE_VTYPE_IDX_MASK) | GE_VTYPE_IDX_16BIT; @@ -616,11 +618,11 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi patch.patchFacing = patchFacing; if (CanUseHardwareTessellation(prim_type)) { - HardwareTessellation(output, patch, origVertType, points, bezierWeightsCache, tessDataTransfer); + HardwareTessellation(output, patch, origVertType, points, tessDataTransfer); numPatches = patch.num_patches_u * patch.num_patches_v; } else { patch.Init(SPLINE_BUFFER_SIZE / vertexSize); - SoftwareTessellation(output, patch, origVertType, points, managedBuf, bezierWeightsCache); + SoftwareTessellation(output, patch, origVertType, points, managedBuf); } u32 vertTypeWithIndex16 = (vertType & ~GE_VTYPE_IDX_MASK) | GE_VTYPE_IDX_16BIT; diff --git a/GPU/Common/SplineCommon.h b/GPU/Common/SplineCommon.h index bcb23e76b2..0b44413cfe 100644 --- a/GPU/Common/SplineCommon.h +++ b/GPU/Common/SplineCommon.h @@ -45,9 +45,14 @@ enum SplineQuality { HIGH_QUALITY = 2, }; +class Bezier3DWeight; +class Spline3DWeight; + // We decode all vertices into a common format for easy interpolation and stuff. // Not fast but can be optimized later. struct BezierPatch { + using WeightType = Bezier3DWeight; + int tess_u; int tess_v; int count_u; @@ -104,6 +109,8 @@ struct BezierPatch { }; struct SplinePatchLocal { + using WeightType = Spline3DWeight; + int tess_u; int tess_v; int count_u; From 1c604d5b60bedaf6c13e1797a96b83dfc3a61999 Mon Sep 17 00:00:00 2001 From: xebra Date: Tue, 31 Jul 2018 04:12:12 +0900 Subject: [PATCH 058/347] [spline/bezier]Put the control points stuffs all in one structure. --- GPU/Common/SplineCommon.cpp | 39 +++++++++++++++---------------------- GPU/Common/SplineCommon.h | 16 +++++++++++++++ 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 8905653757..7d6d92ca26 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -318,26 +318,12 @@ public: template class SubdivisionSurface { private: - Vec3f *pos; - Vec4f *col; - Vec2f *tex; - u32_le defcolor; + const ControlPoints &points; const Patch &patch; const Weight2D &weights; public: - SubdivisionSurface(SimpleBufferManager &managedBuf, const SimpleVertex *const *points, const Patch &patch, const Weight2D &weights) - : patch(patch), weights(weights) - { - int size = patch.count_u * patch.count_v; - pos = (Vec3f *)managedBuf.Allocate(sizeof(Vec3f) * size); - tex = (Vec2f *)managedBuf.Allocate(sizeof(Vec2f) * size); - col = (Vec4f *)managedBuf.Allocate(sizeof(Vec4f) * size); - for (int idx = 0; idx < size; ++idx) { - pos[idx] = Vec3f(points[idx]->pos); - tex[idx] = Vec2f(points[idx]->uv); - col[idx] = Vec4f::FromRGBA(points[idx]->color_32); - } - defcolor = points[0]->color_32; + SubdivisionSurface(const ControlPoints &points, const Patch &patch, const Weight2D &weights) + : points(points), patch(patch), weights(weights) { } template @@ -353,10 +339,10 @@ public: // Prepare 4x4 control points to tessellate const int idx = patch.GetPointIndex(patch_u, patch_v); const int idx_v[4] = { idx, idx + patch.count_u, idx + patch.count_u * 2, idx + patch.count_u * 3 }; - Tessellator tess_pos(pos, idx_v); - Tessellator tess_col(col, idx_v); - Tessellator tess_tex(tex, idx_v); - Tessellator tess_nrm(pos, idx_v); + Tessellator tess_pos(points.pos, idx_v); + Tessellator tess_col(points.col, idx_v); + Tessellator tess_tex(points.tex, idx_v); + Tessellator tess_nrm(points.pos, idx_v); for (int tile_u = start_u; tile_u <= patch.tess_u; ++tile_u) { const int index_u = patch.GetIndexU(patch_u, tile_u); @@ -382,7 +368,7 @@ public: if (sampleCol) { vert.color_32 = tess_col.SampleV(wv.basis).ToRGBA(); } else { - vert.color_32 = defcolor; + vert.color_32 = points.defcolor; } if (sampleTex) { tess_tex.SampleV(wv.basis).Write(vert.uv); @@ -436,7 +422,14 @@ static void SoftwareTessellation(OutputBuffers &output, const Patch &patch, u32 u32 key_v = WeightType::ToKey(patch.tess_v, patch.count_v, patch.type_v); Weight2D weights(weightsCache, key_u, key_v); - SubdivisionSurface surface(managedBuf, points, patch, weights); + int size = patch.count_u * patch.count_v; + ControlPoints cpoints; + cpoints.pos = (Vec3f *)managedBuf.Allocate(sizeof(Vec3f) * size); + cpoints.tex = (Vec2f *)managedBuf.Allocate(sizeof(Vec2f) * size); + cpoints.col = (Vec4f *)managedBuf.Allocate(sizeof(Vec4f) * size); + cpoints.Convert(points, size); + + SubdivisionSurface surface(cpoints, patch, weights); surface.Tessellate(output, origVertType); } diff --git a/GPU/Common/SplineCommon.h b/GPU/Common/SplineCommon.h index 0b44413cfe..2d7b6cd4ae 100644 --- a/GPU/Common/SplineCommon.h +++ b/GPU/Common/SplineCommon.h @@ -198,6 +198,22 @@ struct Weight2D { } }; +struct ControlPoints { + Vec3f *pos; + Vec2f *tex; + Vec4f *col; + u32_le defcolor; + + void Convert(const SimpleVertex *const *points, int size) { + for (int i = 0; i < size; ++i) { + pos[i] = Vec3f(points[i]->pos); + tex[i] = Vec2f(points[i]->uv); + col[i] = Vec4f::FromRGBA(points[i]->color_32); + } + defcolor = points[0]->color_32; + } +}; + struct OutputBuffers { SimpleVertex *vertices; u16 *indices; From 019e276798243d41003d22c7cc4e78b9328ca439 Mon Sep 17 00:00:00 2001 From: xebra Date: Thu, 9 Aug 2018 19:29:19 +0900 Subject: [PATCH 059/347] [spline/bezier]Modify ControlPoints and fix VertexPreview. --- GPU/Common/SplineCommon.cpp | 35 +++--- GPU/Common/SplineCommon.h | 18 ++-- Windows/GEDebugger/VertexPreview.cpp | 155 ++++++++++++++------------- 3 files changed, 111 insertions(+), 97 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 7d6d92ca26..76680aa314 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -21,7 +21,6 @@ #include "profiler/profiler.h" #include "Common/CPUDetect.h" -#include "Common/MemoryUtil.h" #include "GPU/Common/GPUStateUtils.h" #include "GPU/Common/SplineCommon.h" @@ -315,6 +314,22 @@ public: } }; +ControlPoints::ControlPoints(const SimpleVertex *const *points, int size, SimpleBufferManager &managedBuf) { + pos = (Vec3f *)managedBuf.Allocate(sizeof(Vec3f) * size); + tex = (Vec2f *)managedBuf.Allocate(sizeof(Vec2f) * size); + col = (Vec4f *)managedBuf.Allocate(sizeof(Vec4f) * size); + Convert(points, size); +} + +void ControlPoints::Convert(const SimpleVertex *const *points, int size) { + for (int i = 0; i < size; ++i) { + pos[i] = Vec3f(points[i]->pos); + tex[i] = Vec2f(points[i]->uv); + col[i] = Vec4f::FromRGBA(points[i]->color_32); + } + defcolor = points[0]->color_32; +} + template class SubdivisionSurface { private: @@ -415,21 +430,13 @@ public: }; template -static void SoftwareTessellation(OutputBuffers &output, const Patch &patch, u32 origVertType, - const SimpleVertex *const *points, SimpleBufferManager &managedBuf) { +void SoftwareTessellation(OutputBuffers &output, const Patch &patch, u32 origVertType, const ControlPoints &points) { using WeightType = Patch::WeightType; u32 key_u = WeightType::ToKey(patch.tess_u, patch.count_u, patch.type_u); u32 key_v = WeightType::ToKey(patch.tess_v, patch.count_v, patch.type_v); Weight2D weights(weightsCache, key_u, key_v); - int size = patch.count_u * patch.count_v; - ControlPoints cpoints; - cpoints.pos = (Vec3f *)managedBuf.Allocate(sizeof(Vec3f) * size); - cpoints.tex = (Vec2f *)managedBuf.Allocate(sizeof(Vec2f) * size); - cpoints.col = (Vec4f *)managedBuf.Allocate(sizeof(Vec4f) * size); - cpoints.Convert(points, size); - - SubdivisionSurface surface(cpoints, patch, weights); + SubdivisionSurface surface(points, patch, weights); surface.Tessellate(output, origVertType); } @@ -523,8 +530,9 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi HardwareTessellation(output, patch, origVertType, points, tessDataTransfer); numPatches = patch.num_patches_u * patch.num_patches_v; } else { + ControlPoints cpoints(points, count_u * count_v, managedBuf); patch.Init(SPLINE_BUFFER_SIZE / vertexSize); - SoftwareTessellation(output, patch, origVertType, points, managedBuf); + SoftwareTessellation(output, patch, origVertType, cpoints); } u32 vertTypeWithIndex16 = (vertType & ~GE_VTYPE_IDX_MASK) | GE_VTYPE_IDX_16BIT; @@ -614,8 +622,9 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi HardwareTessellation(output, patch, origVertType, points, tessDataTransfer); numPatches = patch.num_patches_u * patch.num_patches_v; } else { + ControlPoints cpoints(points, count_u * count_v, managedBuf); patch.Init(SPLINE_BUFFER_SIZE / vertexSize); - SoftwareTessellation(output, patch, origVertType, points, managedBuf); + SoftwareTessellation(output, patch, origVertType, cpoints); } u32 vertTypeWithIndex16 = (vertType & ~GE_VTYPE_IDX_MASK) | GE_VTYPE_IDX_16BIT; diff --git a/GPU/Common/SplineCommon.h b/GPU/Common/SplineCommon.h index 2d7b6cd4ae..ed4a526776 100644 --- a/GPU/Common/SplineCommon.h +++ b/GPU/Common/SplineCommon.h @@ -198,20 +198,17 @@ struct Weight2D { } }; +class SimpleBufferManager; + struct ControlPoints { Vec3f *pos; Vec2f *tex; Vec4f *col; u32_le defcolor; - void Convert(const SimpleVertex *const *points, int size) { - for (int i = 0; i < size; ++i) { - pos[i] = Vec3f(points[i]->pos); - tex[i] = Vec2f(points[i]->uv); - col[i] = Vec4f::FromRGBA(points[i]->color_32); - } - defcolor = points[0]->color_32; - } + ControlPoints() {} + ControlPoints(const SimpleVertex *const *points, int size, SimpleBufferManager &managedBuf); + void Convert(const SimpleVertex *const *points, int size); }; struct OutputBuffers { @@ -221,8 +218,9 @@ struct OutputBuffers { }; bool CanUseHardwareTessellation(GEPatchPrimType prim); -void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, SplinePatchLocal &spatch, u32 origVertType, int maxVertices); -void TessellateBezierPatch(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType, int maxVertices); + +template +void SoftwareTessellation(OutputBuffers &output, const Patch &patch, u32 origVertType, const ControlPoints &points); // Define function object for TemplateParameterDispatcher #define TEMPLATE_PARAMETER_DISPATCHER_FUNCTION(NAME, FUNCNAME) \ diff --git a/Windows/GEDebugger/VertexPreview.cpp b/Windows/GEDebugger/VertexPreview.cpp index d7ea8f1755..c4c42f81ad 100644 --- a/Windows/GEDebugger/VertexPreview.cpp +++ b/Windows/GEDebugger/VertexPreview.cpp @@ -26,6 +26,7 @@ #include "GPU/Common/GPUDebugInterface.h" #include "GPU/Common/SplineCommon.h" #include "GPU/GPUState.h" +#include "Common/MemoryUtil.h" static const char preview_fs[] = "#ifdef GL_ES\n" @@ -164,106 +165,112 @@ u32 CGEDebugger::PrimPreviewOp() { } static void ExpandBezier(int &count, int op, const std::vector &simpleVerts, const std::vector &indices, std::vector &generatedVerts, std::vector &generatedInds) { - int count_u = (op & 0x00FF) >> 0; - int count_v = (op & 0xFF00) >> 8; + int count_u = (op >> 0) & 0xFF; + int count_v = (op >> 8) & 0xFF; + // Real hardware seems to draw nothing when given < 4 either U or V. + if (count_u < 4 || count_v < 4) + return; int tess_u = gstate.getPatchDivisionU(); int tess_v = gstate.getPatchDivisionV(); - if (tess_u < 1) { - tess_u = 1; - } - if (tess_v < 1) { - tess_v = 1; - } - - // Bezier patches share less control points than spline patches. Otherwise they are pretty much the same (except bezier don't support the open/close thing) - int num_patches_u = (count_u - 1) / 3; - int num_patches_v = (count_v - 1) / 3; - int total_patches = num_patches_u * num_patches_v; - - std::vector points(count_u * count_v); - for (int idx = 0; idx < count_u * count_v; idx++) - points[idx] = &simpleVerts[0] + (!indices.empty() ? indices[idx] : idx); + // If specified as 0, uses 1. + if (tess_u < 1) tess_u = 1; + if (tess_v < 1) tess_v = 1; BezierPatch patch; patch.count_u = count_u; patch.count_v = count_v; + patch.tess_u = tess_u; + patch.tess_v = tess_v; + patch.num_patches_u = (count_u - 1) / 3; + patch.num_patches_v = (count_v - 1) / 3; patch.primType = gstate.getPatchPrimitiveType(); patch.patchFacing = false; - patch.defcolor = 0xFFFFFFFF; - std::vector pos(patch.count_u * patch.count_v); - std::vector tex(patch.count_u * patch.count_v); - std::vector col(patch.count_u * patch.count_v); - patch.pos = pos.data(); - patch.tex = tex.data(); - patch.col = col.data(); - for (int idx = 0; idx < count_u * count_v; idx++) { - patch.pos[idx] = Vec3f(points[idx]->pos); - patch.tex[idx] = Vec2f(points[idx]->uv); - patch.col[idx] = Vec4f::FromRGBA(points[idx]->color_32); - } + // Make an array of pointers to the control points, to get rid of indices. + std::vector points(count_u * count_v); + for (int idx = 0; idx < count_u * count_v; idx++) + points[idx] = simpleVerts.data() + (!indices.empty() ? indices[idx] : idx); + int total_patches = patch.num_patches_u * patch.num_patches_v; generatedVerts.resize((tess_u + 1) * (tess_v + 1) * total_patches); generatedInds.resize(tess_u * tess_v * 6 * total_patches); - count = 0; - u8 *dest = (u8 *)&generatedVerts[0]; - u16 *inds = &generatedInds[0]; - TessellateBezierPatch(dest, inds, count, tess_u, tess_v, patch, gstate.vertType, generatedVerts.size()); + OutputBuffers output; + output.vertices = generatedVerts.data(); + output.indices = generatedInds.data(); + output.count = 0; + + int size = count_u * count_v; + ControlPoints cpoints; + cpoints.pos = (Vec3f *)AllocateAlignedMemory(sizeof(Vec3f) * size, 16); + cpoints.tex = (Vec2f *)AllocateAlignedMemory(sizeof(Vec2f) * size, 16); + cpoints.col = (Vec4f *)AllocateAlignedMemory(sizeof(Vec4f) * size, 16); + cpoints.Convert(points.data(), size); + + patch.Init(generatedVerts.size()); + SoftwareTessellation(output, patch, gstate.vertType, cpoints); + count = output.count; + + FreeAlignedMemory(cpoints.pos); + FreeAlignedMemory(cpoints.tex); + FreeAlignedMemory(cpoints.col); } static void ExpandSpline(int &count, int op, const std::vector &simpleVerts, const std::vector &indices, std::vector &generatedVerts, std::vector &generatedInds) { + int count_u = (op >> 0) & 0xFF; + int count_v = (op >> 8) & 0xFF; + // Real hardware seems to draw nothing when given < 4 either U or V. + if (count_u < 4 || count_v < 4) + return; + + int tess_u = gstate.getPatchDivisionU(); + int tess_v = gstate.getPatchDivisionV(); + // If specified as 0, uses 1. + if (tess_u < 1) tess_u = 1; + if (tess_v < 1) tess_v = 1; + SplinePatchLocal patch; + patch.count_u = count_u; + patch.count_v = count_v; + patch.tess_u = tess_u; + patch.tess_v = tess_v; + patch.type_u = (op >> 16) & 0x3; + patch.type_v = (op >> 18) & 0x3; + patch.num_patches_u = count_u - 3; + patch.num_patches_v = count_v - 3; patch.primType = gstate.getPatchPrimitiveType(); patch.patchFacing = false; - patch.count_u = (op & 0x00FF) >> 0; - patch.count_v = (op & 0xFF00) >> 8; - patch.type_u = (op >> 16) & 0x3; - patch.type_v = (op >> 18) & 0x3; - - patch.tess_u = gstate.getPatchDivisionU(); - patch.tess_v = gstate.getPatchDivisionV(); - if (patch.tess_u < 1) { - patch.tess_u = 1; - } - if (patch.tess_v < 1) { - patch.tess_v = 1; - } - - // Real hardware seems to draw nothing when given < 4 either U or V. - if (patch.count_u < 4 || patch.count_v < 4) { - return; - } - - std::vector points(patch.count_u * patch.count_v); - // Make an array of pointers to the control points, to get rid of indices. - for (int idx = 0; idx < patch.count_u * patch.count_v; idx++) { - points[idx] = &simpleVerts[0] + (!indices.empty() ? indices[idx] : idx); - } - std::vector pos(patch.count_u * patch.count_v); - std::vector tex(patch.count_u * patch.count_v); - std::vector col(patch.count_u * patch.count_v); - patch.pos = pos.data(); - patch.tex = tex.data(); - patch.col = col.data(); - for (int idx = 0; idx < patch.count_u * patch.count_v; idx++) { - patch.pos[idx] = Vec3f(points[idx]->pos); - patch.tex[idx] = Vec2f(points[idx]->uv); - patch.col[idx] = Vec4f::FromRGBA(points[idx]->color_32); - } - - int patch_div_s = (patch.count_u - 3) * patch.tess_u; - int patch_div_t = (patch.count_v - 3) * patch.tess_v; + std::vector points(count_u * count_v); + for (int idx = 0; idx < count_u * count_v; idx++) + points[idx] = simpleVerts.data() + (!indices.empty() ? indices[idx] : idx); + int patch_div_s = patch.num_patches_u * patch.tess_u; + int patch_div_t = patch.num_patches_v * patch.tess_v; generatedVerts.resize((patch_div_s + 1) * (patch_div_t + 1)); generatedInds.resize(patch_div_s * patch_div_t * 6); - count = 0; - u8 *dest = (u8 *)&generatedVerts[0]; - TessellateSplinePatch(dest, &generatedInds[0], count, patch, gstate.vertType, generatedVerts.size()); + OutputBuffers output; + output.vertices = generatedVerts.data(); + output.indices = generatedInds.data(); + output.count = 0; + + int size = count_u * count_v; + ControlPoints cpoints; + cpoints.pos = (Vec3f *)AllocateAlignedMemory(sizeof(Vec3f) * size, 16); + cpoints.tex = (Vec2f *)AllocateAlignedMemory(sizeof(Vec2f) * size, 16); + cpoints.col = (Vec4f *)AllocateAlignedMemory(sizeof(Vec4f) * size, 16); + cpoints.Convert(points.data(), size); + + patch.Init(generatedVerts.size()); + SoftwareTessellation(output, patch, gstate.vertType, cpoints); + count = output.count; + + FreeAlignedMemory(cpoints.pos); + FreeAlignedMemory(cpoints.tex); + FreeAlignedMemory(cpoints.col); } void CGEDebugger::UpdatePrimPreview(u32 op, int which) { From d98fa06b5f3fb8d265f10b6219d669c5b69452bb Mon Sep 17 00:00:00 2001 From: xebra Date: Fri, 31 Aug 2018 20:10:02 +0900 Subject: [PATCH 060/347] [spline/bezier]Fix to build for Android(clang). --- GPU/Common/SplineCommon.cpp | 49 +++++++++++++++++++++++-------------- GPU/Common/SplineCommon.h | 8 +++--- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 76680aa314..747245de10 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -46,7 +46,7 @@ static void CopyQuadIndex(u16 *&indices, GEPatchPrimType type, const int idx0, c } } -static void BuildIndex(u16 *indices, int &count, int num_u, int num_v, GEPatchPrimType prim_type, int total) { +void BuildIndex(u16 *indices, int &count, int num_u, int num_v, GEPatchPrimType prim_type, int total) { for (int v = 0; v < num_v; ++v) { for (int u = 0; u < num_u; ++u) { int idx0 = v * (num_u + 1) + u + total; // Top left @@ -92,6 +92,8 @@ public: static int CalcSize(int tess, int count) { return tess + 1; } + + static WeightCache weightsCache; }; class Spline3DWeight { @@ -143,7 +145,6 @@ private: const __m128 t012 = _mm_sub_ps(_mm_set_ps1(t), knot012); const __m128 f30_41_52 = _mm_mul_ps(t012, _mm_loadu_ps(&div._3_0)); const __m128 f52_31_42 = _mm_mul_ps(t012, _mm_loadu_ps(&div._5_2)); - const float &f32 = t012.m128_f32[2]; // Following comments are for explains order of the multiply. // float a = (1-f30)*(1-f31); @@ -154,14 +155,24 @@ private: const __m128 f31_42_41_52 = _mm_shuffle_ps(f52_31_42, f30_41_52, _MM_SHUFFLE(2, 1, 2, 1)); const __m128 c1_1_0_0 = { 1, 1, 0, 0 }; const __m128 acbd = _mm_mul_ps(_mm_sub_ps(c1_1_0_0, f30_41_31_42), _mm_sub_ps(c1_1_0_0, f31_42_41_52)); - const float &a = acbd.m128_f32[0]; - const float &b = acbd.m128_f32[2]; - const float &c = acbd.m128_f32[1]; - const float &d = acbd.m128_f32[3]; + + alignas(16) float f_t012[4]; + alignas(16) float f_acbd[4]; + alignas(16) float f_f30_41_31_42[4]; + _mm_store_ps(f_t012, t012); + _mm_store_ps(f_acbd, acbd); + _mm_store_ps(f_f30_41_31_42, f30_41_31_42); + + const float &f32 = f_t012[2]; + + const float &a = f_acbd[0]; + const float &b = f_acbd[2]; + const float &c = f_acbd[1]; + const float &d = f_acbd[3]; // For derivative - const float &f31 = f30_41_31_42.m128_f32[2]; - const float &f42 = f30_41_31_42.m128_f32[3]; + const float &f31 = f_f30_41_31_42[2]; + const float &f42 = f_f30_41_31_42[3]; #else // TODO: Maybe compilers could be coaxed into vectorizing this code without the above explicitly... float t0 = (t - knots[0]); @@ -238,14 +249,16 @@ public: static int CalcSize(int tess, int count) { return (count - 3) * tess + 1; } + + static WeightCache weightsCache; }; -template -static WeightCache weightsCache; +WeightCache Bezier3DWeight::weightsCache; +WeightCache Spline3DWeight::weightsCache; void DrawEngineCommon::ClearSplineBezierWeights() { - weightsCache.Clear(); - weightsCache.Clear(); + Bezier3DWeight::weightsCache.Clear(); + Spline3DWeight::weightsCache.Clear(); } bool CanUseHardwareTessellation(GEPatchPrimType prim) { @@ -410,10 +423,10 @@ public: patch.BuildIndex(output.indices, output.count); } - TEMPLATE_PARAMETER_DISPATCHER_FUNCTION(Tess, SubdivisionSurface::Tessellate); + using TessFunc = void(SubdivisionSurface::*)(OutputBuffers &); + TEMPLATE_PARAMETER_DISPATCHER_FUNCTION(Tess, SubdivisionSurface::Tessellate, TessFunc); void Tessellate(OutputBuffers &output, u32 origVertType) { - using TessFunc = void(SubdivisionSurface::*)(OutputBuffers &); constexpr int NumParams = 5; static TemplateParameterDispatcher dispatcher; // Initialize only once @@ -431,10 +444,10 @@ public: template void SoftwareTessellation(OutputBuffers &output, const Patch &patch, u32 origVertType, const ControlPoints &points) { - using WeightType = Patch::WeightType; + using WeightType = typename Patch::WeightType; u32 key_u = WeightType::ToKey(patch.tess_u, patch.count_u, patch.type_u); u32 key_v = WeightType::ToKey(patch.tess_v, patch.count_v, patch.type_v); - Weight2D weights(weightsCache, key_u, key_v); + Weight2D weights(WeightType::weightsCache, key_u, key_v); SubdivisionSurface surface(points, patch, weights); surface.Tessellate(output, origVertType); @@ -443,10 +456,10 @@ void SoftwareTessellation(OutputBuffers &output, const Patch &patch, u32 origVer template static void HardwareTessellation(OutputBuffers &output, const Patch &patch, u32 origVertType, const SimpleVertex *const *points, TessellationDataTransfer *tessDataTransfer) { - using WeightType = Patch::WeightType; + using WeightType = typename Patch::WeightType; u32 key_u = WeightType::ToKey(patch.tess_u, patch.count_u, patch.type_u); u32 key_v = WeightType::ToKey(patch.tess_v, patch.count_v, patch.type_v); - Weight2D weights(weightsCache, key_u, key_v); + Weight2D weights(WeightType::weightsCache, key_u, key_v); weights.size_u = WeightType::CalcSize(patch.tess_u, patch.count_u); weights.size_v = WeightType::CalcSize(patch.tess_v, patch.count_v); tessDataTransfer->SendDataToShader(points, patch.count_u * patch.count_v, origVertType, weights); diff --git a/GPU/Common/SplineCommon.h b/GPU/Common/SplineCommon.h index ed4a526776..3918cf1845 100644 --- a/GPU/Common/SplineCommon.h +++ b/GPU/Common/SplineCommon.h @@ -176,7 +176,7 @@ public: Weight* operator [] (u32 key) { Weight *&weights = weightsCache[key]; if (!weights) - weights = CalcWeightsAll(key); + weights = T::CalcWeightsAll(key); return weights; } @@ -223,10 +223,10 @@ template void SoftwareTessellation(OutputBuffers &output, const Patch &patch, u32 origVertType, const ControlPoints &points); // Define function object for TemplateParameterDispatcher -#define TEMPLATE_PARAMETER_DISPATCHER_FUNCTION(NAME, FUNCNAME) \ +#define TEMPLATE_PARAMETER_DISPATCHER_FUNCTION(NAME, FUNCNAME, FUNCTYPE) \ struct NAME { \ template \ - static auto GetFunc() { \ + static FUNCTYPE GetFunc() { \ return &FUNCNAME; \ } \ }; @@ -246,7 +246,7 @@ class TemplateParameterDispatcher { template struct Initializer<0, Index, Params...> { static void Init(Func funcs[]) { - funcs[Index] = Dispatcher::GetFunc(); + funcs[Index] = Dispatcher::template GetFunc(); // Resolve the nested dependent name as template function. } }; From 89786b943df5bbceb513f78e67618dbee8781967 Mon Sep 17 00:00:00 2001 From: xebra Date: Sat, 22 Sep 2018 19:20:30 +0900 Subject: [PATCH 061/347] [spline/bezier]Instanced rendering for B-Spline is very slow when using weak GPU, so disabled it and simplify the shaders. Add changing the quality of HW tessellation. --- GPU/Common/DrawEngineCommon.h | 1 - GPU/Common/ShaderUniforms.cpp | 2 +- GPU/Common/SplineCommon.cpp | 36 ++++++++++++------- GPU/D3D11/DrawEngineD3D11.cpp | 10 ++---- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 39 +++++--------------- GPU/GLES/DrawEngineGLES.cpp | 5 +-- GPU/GLES/GPU_GLES.cpp | 2 +- GPU/GLES/ShaderManagerGLES.cpp | 8 +---- GPU/GLES/ShaderManagerGLES.h | 1 - GPU/GLES/VertexShaderGeneratorGLES.cpp | 42 ++++++---------------- GPU/Vulkan/DrawEngineVulkan.cpp | 3 +- GPU/Vulkan/VertexShaderGeneratorVulkan.cpp | 39 +++++--------------- UI/GameSettingsScreen.cpp | 13 +++---- 13 files changed, 60 insertions(+), 141 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 9211905606..37b9dd865d 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -178,6 +178,5 @@ protected: bool fboTexBound_ = false; // Hardware tessellation - int numPatches; TessellationDataTransfer *tessDataTransfer; }; diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index ea152d260d..26bdbd7c17 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -240,7 +240,7 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView } if (dirtyUniforms & DIRTY_BEZIERSPLINE) { - ub->spline_counts = BytesToUint32(gstate_c.spline_num_patches_u, gstate_c.spline_num_points_u, gstate_c.spline_tess_u, gstate_c.spline_tess_v); + ub->spline_counts = gstate_c.spline_num_points_u; } if (dirtyUniforms & DIRTY_DEPAL) { diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 747245de10..8f145824af 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -467,17 +467,29 @@ static void HardwareTessellation(OutputBuffers &output, const Patch &patch, u32 // Generating simple input vertices for the spline-computing vertex shader. float inv_u = 1.0f / (float)patch.tess_u; float inv_v = 1.0f / (float)patch.tess_v; - for (int tile_v = 0; tile_v <= patch.tess_v; ++tile_v) { - for (int tile_u = 0; tile_u <= patch.tess_u; ++tile_u) { - SimpleVertex &vert = output.vertices[tile_v * (patch.tess_u + 1) + tile_u]; - vert.pos.x = (float)tile_u; - vert.pos.y = (float)tile_v; - // For texcoord generation - vert.nrm.x = (float)tile_u * inv_u; - vert.nrm.y = (float)tile_v * inv_v; + for (int patch_u = 0; patch_u < patch.num_patches_u; ++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 start_v = patch.GetTessStart(patch_v); + for (int tile_u = start_u; tile_u <= patch.tess_u; ++tile_u) { + const int index_u = patch.GetIndexU(patch_u, tile_u); + for (int tile_v = start_v; tile_v <= patch.tess_v; ++tile_v) { + const int index_v = patch.GetIndexV(patch_v, tile_v); + SimpleVertex &vert = output.vertices[patch.GetIndex(index_u, index_v, patch_u, patch_v)]; + // Index for the weights + vert.pos.x = index_u; + vert.pos.y = index_v; + // For texcoord generation + vert.nrm.x = patch_u + (float)tile_u * inv_u; + vert.nrm.y = patch_v + (float)tile_v * inv_v; + // Patch position + vert.pos.z = patch_u; + vert.nrm.z = patch_v; + } + } } } - BuildIndex(output.indices, output.count, patch.tess_u, patch.tess_v, patch.primType); + patch.BuildIndex(output.indices, output.count); } void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indices, int tess_u, int tess_v, int count_u, int count_v, int type_u, int type_v, GEPatchPrimType prim_type, bool computeNormals, bool patchFacing, u32 vertType, int *bytesRead) { @@ -538,13 +550,12 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi patch.num_patches_v = count_v - 3; patch.primType = prim_type; patch.patchFacing = patchFacing; + patch.Init(SPLINE_BUFFER_SIZE / vertexSize); if (CanUseHardwareTessellation(prim_type)) { HardwareTessellation(output, patch, origVertType, points, tessDataTransfer); - numPatches = patch.num_patches_u * patch.num_patches_v; } else { ControlPoints cpoints(points, count_u * count_v, managedBuf); - patch.Init(SPLINE_BUFFER_SIZE / vertexSize); SoftwareTessellation(output, patch, origVertType, cpoints); } @@ -630,13 +641,12 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi patch.num_patches_v = (count_v - 1) / 3; patch.primType = prim_type; patch.patchFacing = patchFacing; + patch.Init(SPLINE_BUFFER_SIZE / vertexSize); if (CanUseHardwareTessellation(prim_type)) { HardwareTessellation(output, patch, origVertType, points, tessDataTransfer); - numPatches = patch.num_patches_u * patch.num_patches_v; } else { ControlPoints cpoints(points, count_u * count_v, managedBuf); - patch.Init(SPLINE_BUFFER_SIZE / vertexSize); SoftwareTessellation(output, patch, origVertType, cpoints); } diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 91d31ff40c..a5c70a34f2 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -540,10 +540,7 @@ rotateVBO: memcpy(iptr, decIndex, iSize); pushInds_->EndPush(context_); context_->IASetIndexBuffer(pushInds_->Buf(), DXGI_FORMAT_R16_UINT, iOffset); - if (tess) - context_->DrawIndexedInstanced(vertexCount, numPatches, 0, 0, 0); - else - context_->DrawIndexed(vertexCount, 0, 0); + context_->DrawIndexed(vertexCount, 0, 0); } else { context_->Draw(vertexCount, 0); } @@ -552,10 +549,7 @@ rotateVBO: context_->IASetVertexBuffers(0, 1, &vb_, &stride, &offset); if (useElements) { context_->IASetIndexBuffer(ib_, DXGI_FORMAT_R16_UINT, 0); - if (tess) - context_->DrawIndexedInstanced(vertexCount, numPatches, 0, 0, 0); - else - context_->DrawIndexed(vertexCount, 0, 0); + context_->DrawIndexed(vertexCount, 0, 0); } else { context_->Draw(vertexCount, 0); } diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 885d59e76d..3a595467b6 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -311,19 +311,8 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage WRITE(p, "};\n"); WRITE(p, "void tessellate(in VS_IN In, out Tess tess) {\n"); - WRITE(p, " int spline_num_patches_u = int(u_spline_counts & 0xff);\n"); - WRITE(p, " int spline_num_points_u = int((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 u = In.instanceId %% spline_num_patches_u;\n"); - WRITE(p, " int v = In.instanceId / spline_num_patches_u;\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"); - } + WRITE(p, " int2 point_pos = int2(In.position.z, In.normal.z)%s;\n", doBezier ? " * 3" : ""); + WRITE(p, " int2 weight_idx = int2(In.position.xy);\n"); // Load 4x4 control points WRITE(p, " float3 _pos[16];\n"); WRITE(p, " float2 _tex[16];\n"); @@ -331,7 +320,7 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage 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_num_points_u + (%i + u%s);\n", i, doBezier ? " * 3" : "", j, doBezier ? " * 3" : ""); + WRITE(p, " index = (%i + point_pos.y) * u_spline_counts + (%i + point_pos.x);\n", i, j); WRITE(p, " _pos[%i] = tess_data[index].pos;\n", i * 4 + j); if (doTexture && hasTexcoordTess) WRITE(p, " _tex[%i] = tess_data[index].tex;\n", i * 4 + j); @@ -341,14 +330,8 @@ 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"); - } + WRITE(p, " float4 basis_u = tess_weights_u[weight_idx.x].basis;\n"); + WRITE(p, " float4 basis_v = tess_weights_v[weight_idx.y].basis;\n"); WRITE(p, " float4x4 basis = outerProduct(basis_u, basis_v);\n"); // Tessellate @@ -357,7 +340,7 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage if (hasTexcoordTess) WRITE(p, " tess.tex = tess_sample(_tex, basis);\n"); else - WRITE(p, " tess.tex = In.normal.xy + float2(patch_pos);\n"); + WRITE(p, " tess.tex = In.normal.xy;\n"); } if (hasColorTess) WRITE(p, " tess.col = tess_sample(_col, basis);\n"); @@ -365,14 +348,8 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage WRITE(p, " tess.col = u_matambientalpha;\n"); if (hasNormalTess) { // 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, " float4 deriv_u = tess_weights_u[weight_idx.x].deriv;\n"); + WRITE(p, " float4 deriv_v = tess_weights_v[weight_idx.y].deriv;\n"); WRITE(p, " float3 du = tess_sample(_pos, outerProduct(deriv_u, basis_v));\n"); WRITE(p, " float3 dv = tess_sample(_pos, outerProduct(basis_u, deriv_v));\n"); diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 749dae8780..93ef574b61 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -521,10 +521,7 @@ rotateVBO: indexBufferOffset = (uint32_t)frameData.pushIndex->Push(decIndex, sizeof(uint16_t) * indexGen.VertexCount(), &indexBuffer); render_->BindIndexBuffer(indexBuffer); } - if (gstate_c.bezier || gstate_c.spline) - render_->DrawIndexed(glprim[prim], vertexCount, GL_UNSIGNED_SHORT, (GLvoid*)(intptr_t)indexBufferOffset, numPatches); - else - render_->DrawIndexed(glprim[prim], vertexCount, GL_UNSIGNED_SHORT, (GLvoid*)(intptr_t)indexBufferOffset); + render_->DrawIndexed(glprim[prim], vertexCount, GL_UNSIGNED_SHORT, (GLvoid*)(intptr_t)indexBufferOffset); } else { render_->Draw(glprim[prim], 0, vertexCount); } diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 2a75ead250..f527010a55 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -109,7 +109,7 @@ GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw) if (g_Config.bHardwareTessellation) { // Disable hardware tessellation if device is unsupported. bool hasTexelFetch = gl_extensions.GLES3 || (!gl_extensions.IsGLES && gl_extensions.VersionGEThan(3, 3, 0)) || gl_extensions.EXT_gpu_shader4; - if (!gstate_c.SupportsAll(GPU_SUPPORTS_INSTANCE_RENDERING | GPU_SUPPORTS_VERTEX_TEXTURE_FETCH | GPU_SUPPORTS_TEXTURE_FLOAT) || !hasTexelFetch) { + if (!gstate_c.SupportsAll(GPU_SUPPORTS_VERTEX_TEXTURE_FETCH | GPU_SUPPORTS_TEXTURE_FLOAT) || !hasTexelFetch) { // TODO: Check unsupported device name list.(Above gpu features are supported but it has issues with weak gpu, memory, shader compiler etc...) g_Config.bHardwareTessellation = false; ERROR_LOG(G3D, "Hardware Tessellation is unsupported, falling back to software tessellation"); diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 200642f104..c361538a9b 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -162,7 +162,6 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs, queries.push_back({ &u_tess_points, "u_tess_points" }); queries.push_back({ &u_tess_weights_u, "u_tess_weights_u" }); queries.push_back({ &u_tess_weights_v, "u_tess_weights_v" }); - queries.push_back({ &u_spline_tess, "u_spline_tess" }); queries.push_back({ &u_spline_counts, "u_spline_counts" }); queries.push_back({ &u_depal, "u_depal" }); @@ -565,13 +564,8 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid) { } if (dirty & DIRTY_BEZIERSPLINE) { - if (u_spline_tess != -1) { - int tess[] = { gstate_c.spline_tess_u, gstate_c.spline_tess_v }; - render_->SetUniformI(&u_spline_tess, 2, tess); - } if (u_spline_counts != -1) { - int counts[] = { gstate_c.spline_num_patches_u, gstate_c.spline_num_points_u }; - render_->SetUniformI(&u_spline_counts, 2, counts); + render_->SetUniformI1(&u_spline_counts, gstate_c.spline_num_points_u); } } } diff --git a/GPU/GLES/ShaderManagerGLES.h b/GPU/GLES/ShaderManagerGLES.h index f77c60a4a0..998e49704a 100644 --- a/GPU/GLES/ShaderManagerGLES.h +++ b/GPU/GLES/ShaderManagerGLES.h @@ -121,7 +121,6 @@ public: int u_tess_points; // Control Points int u_tess_weights_u; int u_tess_weights_v; - int u_spline_tess; int u_spline_counts; }; diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index c9468bfccc..72b47652f0 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -384,8 +384,7 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, WRITE(p, "uniform sampler2D u_tess_weights_u;\n"); WRITE(p, "uniform sampler2D u_tess_weights_v;\n"); - WRITE(p, "uniform ivec2 u_spline_counts;\n"); - WRITE(p, "uniform ivec2 u_spline_tess;\n"); + WRITE(p, "uniform int u_spline_counts;\n"); for (int i = 2; i <= 4; i++) { // Define 3 types vec2, vec3, vec4 @@ -416,18 +415,9 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, WRITE(p, "};\n"); WRITE(p, "void tessellate(out Tess tess) {\n"); - WRITE(p, " int spline_num_patches_u = u_spline_counts[0];\n"); - WRITE(p, " int spline_num_points_u = u_spline_counts[1];\n"); - // Calculate current patch position and vertex position(index for the weights) - WRITE(p, " int u = gl_InstanceID %% spline_num_patches_u;\n"); - WRITE(p, " int v = gl_InstanceID / spline_num_patches_u;\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"); - } + WRITE(p, " ivec2 point_pos = ivec2(position.z, normal.z)%s;\n", doBezier ? " * 3" : ""); + WRITE(p, " ivec2 weight_idx = ivec2(position.xy);\n"); + // Load 4x4 control points WRITE(p, " vec3 _pos[16];\n"); WRITE(p, " vec2 _tex[16];\n"); @@ -435,7 +425,7 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, 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_num_points_u + (%i + u%s);\n", i, doBezier ? " * 3" : "", j, doBezier ? " * 3" : ""); + WRITE(p, " index = (%i + point_pos.y) * u_spline_counts + (%i + point_pos.x);\n", i, j); WRITE(p, " _pos[%i] = %s(u_tess_points, ivec2(index, 0), 0).xyz;\n", i * 4 + j, texelFetch); if (doTexture && hasTexcoordTess) WRITE(p, " _tex[%i] = %s(u_tess_points, ivec2(index, 1), 0).xy;\n", i * 4 + j, texelFetch); @@ -445,14 +435,8 @@ 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"); - } + WRITE(p, " vec4 basis_u = %s(u_tess_weights_u, %s, 0);\n", texelFetch, "ivec2(weight_idx.x * 2, 0)"); + WRITE(p, " vec4 basis_v = %s(u_tess_weights_v, %s, 0);\n", texelFetch, "ivec2(weight_idx.y * 2, 0)"); WRITE(p, " mat4 basis = outerProduct(basis_u, basis_v);\n"); // Tessellate @@ -461,7 +445,7 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, if (hasTexcoordTess) WRITE(p, " tess.tex = tess_sample(_tex, basis);\n"); else - WRITE(p, " tess.tex = normal.xy + vec2(patch_pos);\n"); + WRITE(p, " tess.tex = normal.xy;\n"); } if (hasColorTess) WRITE(p, " tess.col = tess_sample(_col, basis);\n"); @@ -469,14 +453,8 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, WRITE(p, " tess.col = u_matambientalpha;\n"); if (hasNormalTess) { // 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, " vec4 deriv_u = %s(u_tess_weights_u, %s, 0);\n", texelFetch, "ivec2(weight_idx.x * 2 + 1, 0)"); + WRITE(p, " vec4 deriv_v = %s(u_tess_weights_v, %s, 0);\n", texelFetch, "ivec2(weight_idx.y * 2 + 1, 0)"); WRITE(p, " vec3 du = tess_sample(_pos, outerProduct(deriv_u, basis_v));\n"); WRITE(p, " vec3 dv = tess_sample(_pos, outerProduct(basis_u, deriv_v));\n"); diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index bcd9648c76..0132c57bea 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -845,8 +845,7 @@ void DrawEngineVulkan::DoFlush() { if (useElements) { if (!ibuf) ibOffset = (uint32_t)frame->pushIndex->Push(decIndex, sizeof(uint16_t) * indexGen.VertexCount(), &ibuf); - int numInstances = tess ? numPatches : 1; - renderManager->DrawIndexed(pipelineLayout_, ds, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, vertexCount, numInstances, VK_INDEX_TYPE_UINT16); + renderManager->DrawIndexed(pipelineLayout_, ds, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, vertexCount, 1, VK_INDEX_TYPE_UINT16); } else { renderManager->Draw(pipelineLayout_, ds, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, vertexCount); } diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index 708e277021..947a7d35b4 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -259,19 +259,8 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { WRITE(p, "};\n"); WRITE(p, "void tessellate(out Tess tess) {\n"); - WRITE(p, " int spline_num_patches_u = int(base.spline_counts & 0xff);\n"); - WRITE(p, " int spline_num_points_u = int((base.spline_counts >> 8) & 0xff);\n"); - WRITE(p, " ivec2 spline_tess = ivec2((base.spline_counts >> 16) & 0xff, (base.spline_counts >> 24) & 0xff);\n"); - // Calculate current patch position and vertex position(index for the weights) - WRITE(p, " int u = gl_InstanceIndex %% spline_num_patches_u;\n"); - WRITE(p, " int v = gl_InstanceIndex / spline_num_patches_u;\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"); - } + WRITE(p, " ivec2 point_pos = ivec2(position.z, normal.z)%s;\n", doBezier ? " * 3" : ""); + WRITE(p, " ivec2 weight_idx = ivec2(position.xy);\n"); // Load 4x4 control points WRITE(p, " vec3 _pos[16];\n"); WRITE(p, " vec2 _tex[16];\n"); @@ -279,7 +268,7 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { 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_num_points_u + (%i + u%s);\n", i, doBezier ? " * 3" : "", j, doBezier ? " * 3" : ""); + WRITE(p, " index = (%i + point_pos.y) * int(base.spline_counts) + (%i + point_pos.x);\n", i, j); WRITE(p, " _pos[%i] = tess_data.data[index].pos.xyz;\n", i * 4 + j); if (doTexture && hasTexcoordTess) WRITE(p, " _tex[%i] = tess_data.data[index].uv.xy;\n", i * 4 + j); @@ -289,14 +278,8 @@ 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"); - } + WRITE(p, " vec4 basis_u = tess_weights_u.data[weight_idx.x].basis;\n"); + WRITE(p, " vec4 basis_v = tess_weights_v.data[weight_idx.y].basis;\n"); WRITE(p, " mat4 basis = outerProduct(basis_u, basis_v);\n"); // Tessellate @@ -305,7 +288,7 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { if (hasTexcoordTess) WRITE(p, " tess.tex = tess_sample(_tex, basis);\n"); else - WRITE(p, " tess.tex = normal.xy + vec2(patch_pos);\n"); + WRITE(p, " tess.tex = normal.xy;\n"); } if (hasColorTess) WRITE(p, " tess.col = tess_sample(_col, basis);\n"); @@ -313,14 +296,8 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { WRITE(p, " tess.col = base.matambientalpha;\n"); if (hasNormalTess) { // 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, " vec4 deriv_u = tess_weights_u.data[weight_idx.x].deriv;\n"); + WRITE(p, " vec4 deriv_v = tess_weights_v.data[weight_idx.y].deriv;\n"); WRITE(p, " vec3 du = tess_sample(_pos, outerProduct(deriv_u, basis_v));\n"); WRITE(p, " vec3 dv = tess_sample(_pos, outerProduct(basis_u, deriv_v));\n"); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 43bb8dd58a..5dc93d0436 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -80,7 +80,7 @@ bool GameSettingsScreen::UseVerticalLayout() const { // This needs before run CheckGPUFeatures() // TODO: Remove this if fix the issue -bool CheckSupportInstancedTessellationGLES() { +bool CheckSupportShaderTessellationGLES() { #if PPSSPP_PLATFORM(UWP) return true; #else @@ -88,21 +88,17 @@ bool CheckSupportInstancedTessellationGLES() { int maxVertexTextureImageUnits = gl_extensions.maxVertexTextureUnits; bool vertexTexture = maxVertexTextureImageUnits >= 3; // At least 3 for hardware tessellation - bool canUseInstanceID = gl_extensions.EXT_draw_instanced || gl_extensions.ARB_draw_instanced; - bool canDefInstanceID = gl_extensions.IsGLES || gl_extensions.EXT_gpu_shader4 || gl_extensions.VersionGEThan(3, 1); - bool instanceRendering = gl_extensions.GLES3 || (canUseInstanceID && canDefInstanceID); - bool textureFloat = gl_extensions.ARB_texture_float || gl_extensions.OES_texture_float; bool hasTexelFetch = gl_extensions.GLES3 || (!gl_extensions.IsGLES && gl_extensions.VersionGEThan(3, 3, 0)) || gl_extensions.EXT_gpu_shader4; - return instanceRendering && vertexTexture && textureFloat && hasTexelFetch; + return vertexTexture && textureFloat && hasTexelFetch; #endif } bool DoesBackendSupportHWTess() { switch (GetGPUBackend()) { case GPUBackend::OPENGL: - return CheckSupportInstancedTessellationGLES(); + return CheckSupportShaderTessellationGLES(); case GPUBackend::VULKAN: case GPUBackend::DIRECT3D11: return true; @@ -392,11 +388,10 @@ void GameSettingsScreen::CreateViews() { } return UI::EVENT_CONTINUE; }); - beziersChoice->SetDisabledPtr(&g_Config.bHardwareTessellation); CheckBox *tessellationHW = graphicsSettings->Add(new CheckBox(&g_Config.bHardwareTessellation, gr->T("Hardware Tessellation"))); tessellationHW->OnClick.Add([=](EventParams &e) { - settingInfo_->Show(gr->T("HardwareTessellation Tip", "Uses hardware to make curves, always uses a fixed quality"), e.v); + settingInfo_->Show(gr->T("HardwareTessellation Tip", "Uses hardware to make curves"), e.v); return UI::EVENT_CONTINUE; }); tessHWEnable_ = DoesBackendSupportHWTess() && !g_Config.bSoftwareRendering && g_Config.bHardwareTransform; From 41823f8780ce77ffe9fcaf37bf55da2b59682c76 Mon Sep 17 00:00:00 2001 From: xebra Date: Sat, 22 Sep 2018 22:06:40 +0900 Subject: [PATCH 062/347] [spline/bezier]Fix GLES texture resolution of HW tess to real 2D to avoid huge width in FF4CC mist dragon morphing. --- GPU/Common/DrawEngineCommon.h | 2 +- GPU/Common/SplineCommon.cpp | 2 +- GPU/D3D11/DrawEngineD3D11.cpp | 4 +++- GPU/D3D11/DrawEngineD3D11.h | 2 +- GPU/Directx9/DrawEngineDX9.cpp | 2 +- GPU/Directx9/DrawEngineDX9.h | 2 +- GPU/GLES/DrawEngineGLES.cpp | 19 ++++++++++--------- GPU/GLES/DrawEngineGLES.h | 5 +++-- GPU/GLES/VertexShaderGeneratorGLES.cpp | 11 ++++++----- GPU/Vulkan/DrawEngineVulkan.cpp | 4 +++- GPU/Vulkan/DrawEngineVulkan.h | 2 +- 11 files changed, 31 insertions(+), 24 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 37b9dd865d..c2bc891845 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -56,7 +56,7 @@ struct SimpleVertex; class TessellationDataTransfer { public: void CopyControlPoints(float *pos, float *tex, float *col, int posStride, int texStride, int colStride, const SimpleVertex *const *points, int size, u32 vertType); - virtual void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) = 0; + virtual void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) = 0; }; class DrawEngineCommon { diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 8f145824af..75866aa11b 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -462,7 +462,7 @@ static void HardwareTessellation(OutputBuffers &output, const Patch &patch, u32 Weight2D weights(WeightType::weightsCache, key_u, key_v); weights.size_u = WeightType::CalcSize(patch.tess_u, patch.count_u); weights.size_v = WeightType::CalcSize(patch.tess_v, patch.count_v); - tessDataTransfer->SendDataToShader(points, patch.count_u * patch.count_v, origVertType, weights); + tessDataTransfer->SendDataToShader(points, patch.count_u, patch.count_v, origVertType, weights); // Generating simple input vertices for the spline-computing vertex shader. float inv_u = 1.0f / (float)patch.tess_u; diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index a5c70a34f2..9a90320407 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -702,13 +702,15 @@ TessellationDataTransferD3D11::~TessellationDataTransferD3D11() { } } -void TessellationDataTransferD3D11::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) { +void TessellationDataTransferD3D11::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) { struct TessData { float pos[3]; float pad1; float uv[2]; float pad2[2]; float color[4]; }; + int size = size_u * size_v; + if (prevSize < size) { prevSize = size; if (buf[0]) buf[0]->Release(); diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h index a74dd03458..a29b43553a 100644 --- a/GPU/D3D11/DrawEngineD3D11.h +++ b/GPU/D3D11/DrawEngineD3D11.h @@ -112,7 +112,7 @@ public: TessellationDataTransferD3D11(ID3D11DeviceContext *context, ID3D11Device *device); ~TessellationDataTransferD3D11(); // Send spline/bezier's control points and weights to vertex shader through structured shader buffer. - void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) override; + void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) override; }; // Handles transform, lighting and drawing. diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index 4300e18c86..0669412d0a 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -625,7 +625,7 @@ rotateVBO: GPUDebug::NotifyDraw(); } -void TessellationDataTransferDX9::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) { +void TessellationDataTransferDX9::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) { // TODO } diff --git a/GPU/Directx9/DrawEngineDX9.h b/GPU/Directx9/DrawEngineDX9.h index 32c0db6e0f..7ec653ddef 100644 --- a/GPU/Directx9/DrawEngineDX9.h +++ b/GPU/Directx9/DrawEngineDX9.h @@ -101,7 +101,7 @@ class TessellationDataTransferDX9 : public TessellationDataTransfer { public: TessellationDataTransferDX9() {} ~TessellationDataTransferDX9() {} - void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) override; + void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) override; }; // Handles transform, lighting and drawing. diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 93ef574b61..79051abb07 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -653,35 +653,36 @@ bool DrawEngineGLES::IsCodePtrVertexDecoder(const u8 *ptr) const { return decJitCache_->IsInSpace(ptr); } -void TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) { +void TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) { bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0; bool hasTexCoord = (vertType & GE_VTYPE_TC_MASK) != 0; + int size = size_u * size_v; float *pos = new float[size * 4]; float *tex = hasTexCoord ? new float[size * 4] : nullptr; float *col = hasColor ? new float[size * 4] : nullptr; int stride = 4; CopyControlPoints(pos, tex, col, stride, stride, stride, points, size, vertType); - // Removed the 1D texture support, it's unlikely to be relevant for performance. // Control Points - if (prevSize < size) { - prevSize = size; + if (prevSizeU < size_u || prevSizeV < size_v) { + prevSizeU = size_u; + prevSizeV = size_v; if (!data_tex[0]) data_tex[0] = renderManager_->CreateTexture(GL_TEXTURE_2D); - renderManager_->TextureImage(data_tex[0], 0, size, 3, GL_RGBA32F, GL_RGBA, GL_FLOAT, nullptr, GLRAllocType::NONE, false); + renderManager_->TextureImage(data_tex[0], 0, size_u * 3, size_v, GL_RGBA32F, GL_RGBA, GL_FLOAT, nullptr, GLRAllocType::NONE, false); renderManager_->FinalizeTexture(data_tex[0], 0, false); } renderManager_->BindTexture(TEX_SLOT_SPLINE_POINTS, data_tex[0]); // Position - renderManager_->TextureSubImage(data_tex[0], 0, 0, 0, size, 1, GL_RGBA, GL_FLOAT, (u8 *)pos, GLRAllocType::NEW); + renderManager_->TextureSubImage(data_tex[0], 0, 0, 0, size_u, size_v, GL_RGBA, GL_FLOAT, (u8 *)pos, GLRAllocType::NEW); // Texcoord if (hasTexCoord) - renderManager_->TextureSubImage(data_tex[0], 0, 0, 1, size, 1, GL_RGBA, GL_FLOAT, (u8 *)tex, GLRAllocType::NEW); + renderManager_->TextureSubImage(data_tex[0], 0, size_u, 0, size_u, size_v, GL_RGBA, GL_FLOAT, (u8 *)tex, GLRAllocType::NEW); // Color if (hasColor) - renderManager_->TextureSubImage(data_tex[0], 0, 0, 2, size, 1, GL_RGBA, GL_FLOAT, (u8 *)col, GLRAllocType::NEW); + renderManager_->TextureSubImage(data_tex[0], 0, size_u * 2, 0, size_u, size_v, GL_RGBA, GL_FLOAT, (u8 *)col, GLRAllocType::NEW); // Weight U if (prevSizeWU < weights.size_u) { @@ -713,5 +714,5 @@ void TessellationDataTransferGLES::EndFrame() { data_tex[i] = nullptr; } } - prevSize = prevSizeWU = prevSizeWV = 0; + prevSizeU = prevSizeV = prevSizeWU = prevSizeWV = 0; } diff --git a/GPU/GLES/DrawEngineGLES.h b/GPU/GLES/DrawEngineGLES.h index 9870adacd2..858f927485 100644 --- a/GPU/GLES/DrawEngineGLES.h +++ b/GPU/GLES/DrawEngineGLES.h @@ -113,7 +113,8 @@ public: class TessellationDataTransferGLES : public TessellationDataTransfer { private: GLRTexture *data_tex[3]{}; - int prevSize = 0, prevSizeWU = 0, prevSizeWV = 0; + int prevSizeU = 0, prevSizeV = 0; + int prevSizeWU = 0, prevSizeWV = 0; GLRenderManager *renderManager_; public: TessellationDataTransferGLES(GLRenderManager *renderManager) @@ -122,7 +123,7 @@ public: EndFrame(); } // Send spline/bezier's control points and weights to vertex shader through floating point texture. - void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) override; + void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) override; void EndFrame(); // Queues textures for deletion. }; diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index 72b47652f0..926291dc84 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -422,15 +422,16 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, WRITE(p, " vec3 _pos[16];\n"); WRITE(p, " vec2 _tex[16];\n"); WRITE(p, " vec4 _col[16];\n"); - WRITE(p, " int index;\n"); + WRITE(p, " int index_u, index_v;\n"); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { - WRITE(p, " index = (%i + point_pos.y) * u_spline_counts + (%i + point_pos.x);\n", i, j); - WRITE(p, " _pos[%i] = %s(u_tess_points, ivec2(index, 0), 0).xyz;\n", i * 4 + j, texelFetch); + WRITE(p, " index_u = (%i + point_pos.x);\n", j); + WRITE(p, " index_v = (%i + point_pos.y);\n", i); + WRITE(p, " _pos[%i] = %s(u_tess_points, ivec2(index_u, index_v), 0).xyz;\n", i * 4 + j, texelFetch); if (doTexture && hasTexcoordTess) - WRITE(p, " _tex[%i] = %s(u_tess_points, ivec2(index, 1), 0).xy;\n", i * 4 + j, texelFetch); + WRITE(p, " _tex[%i] = %s(u_tess_points, ivec2(index_u + u_spline_counts, index_v), 0).xy;\n", i * 4 + j, texelFetch); if (hasColorTess) - WRITE(p, " _col[%i] = %s(u_tess_points, ivec2(index, 2), 0).rgba;\n", i * 4 + j, texelFetch); + WRITE(p, " _col[%i] = %s(u_tess_points, ivec2(index_u + u_spline_counts * 2, index_v), 0).rgba;\n", i * 4 + j, texelFetch); } } diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 0132c57bea..a3bba5d3b7 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -1013,7 +1013,7 @@ void DrawEngineVulkan::UpdateUBOs(FrameData *frame) { } } -void TessellationDataTransferVulkan::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) { +void TessellationDataTransferVulkan::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) { // SSBOs that are not simply float1 or float2 need to be padded up to a float4 size. vec3 members // also need to be 16-byte aligned, hence the padding. struct TessData { @@ -1022,6 +1022,8 @@ void TessellationDataTransferVulkan::SendDataToShader(const SimpleVertex *const float color[4]; }; + int size = size_u * size_v; + int ssboAlignment = vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).limits.minStorageBufferOffsetAlignment; uint8_t *data = (uint8_t *)push_->PushAligned(size * sizeof(TessData), (uint32_t *)&bufInfo_[0].offset, &bufInfo_[0].buffer, ssboAlignment); bufInfo_[0].range = size * sizeof(TessData); diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index ad2cb30954..c27e9be04b 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -123,7 +123,7 @@ public: void SetPushBuffer(VulkanPushBuffer *push) { push_ = push; } // Send spline/bezier's control points and weights to vertex shader through structured shader buffer. - void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) override; + void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) override; const VkDescriptorBufferInfo *GetBufferInfo() { return bufInfo_; } private: VulkanContext *vulkan_; From c49d9e2f720841dafb402072b4e88a806ac3e4d0 Mon Sep 17 00:00:00 2001 From: xebra Date: Sun, 23 Sep 2018 14:24:23 +0900 Subject: [PATCH 063/347] [spline/bezier]minor fix(referenced to c1f0e981). --- GPU/Vulkan/VertexShaderGeneratorVulkan.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index 947a7d35b4..c5d1110b39 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -229,10 +229,10 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { WRITE(p, " vec4 basis;\n"); WRITE(p, " vec4 deriv;\n"); WRITE(p, "};\n"); - WRITE(p, "layout (std430, set = 0, binding = 7) buffer s_tess_weights_u {\n"); + WRITE(p, "layout (std430, set = 0, binding = 7) readonly buffer s_tess_weights_u {\n"); WRITE(p, " TessWeight data[];\n"); WRITE(p, "} tess_weights_u;\n"); - WRITE(p, "layout (std430, set = 0, binding = 8) buffer s_tess_weights_v {\n"); + WRITE(p, "layout (std430, set = 0, binding = 8) readonly buffer s_tess_weights_v {\n"); WRITE(p, " TessWeight data[];\n"); WRITE(p, "} tess_weights_v;\n"); From 8ad38dfaae30ed460edb6bbfd3c3172ff2d71a3a Mon Sep 17 00:00:00 2001 From: xebra Date: Mon, 24 Sep 2018 20:12:28 +0900 Subject: [PATCH 064/347] [spline/bezier]oops --- GPU/GPUCommon.cpp | 17 ++--------------- GPU/GPUState.h | 3 --- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index d3b24ba58e..ff6b91d039 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1760,12 +1760,8 @@ void GPUCommon::Execute_Bezier(u32 op, u32 diff) { if (CanUseHardwareTessellation(patchPrim)) { gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); gstate_c.bezier = true; - int num_patches_u = (bz_ucount - 1) / 3; - bool patchesChanged = gstate_c.spline_num_patches_u != num_patches_u; - bool countsChanged = gstate_c.spline_num_points_u != bz_ucount; - if (patchesChanged || countsChanged) { + if (gstate_c.spline_num_points_u != bz_ucount) { gstate_c.Dirty(DIRTY_BEZIERSPLINE); - gstate_c.spline_num_patches_u = num_patches_u; gstate_c.spline_num_points_u = bz_ucount; } } @@ -1828,17 +1824,8 @@ void GPUCommon::Execute_Spline(u32 op, u32 diff) { if (CanUseHardwareTessellation(patchPrim)) { gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); gstate_c.spline = true; - int tess_u = gstate.getPatchDivisionU(); - int tess_v = gstate.getPatchDivisionV(); - int num_patches_u = sp_ucount - 3; - bool divsChanged = gstate_c.spline_tess_u != tess_u || gstate_c.spline_tess_v != tess_v; - bool patchesChanged = gstate_c.spline_num_patches_u != num_patches_u; - bool countsChanged = gstate_c.spline_num_points_u != sp_ucount; - if (divsChanged || patchesChanged || countsChanged) { + if (gstate_c.spline_num_points_u != sp_ucount) { gstate_c.Dirty(DIRTY_BEZIERSPLINE); - gstate_c.spline_tess_u = tess_u; - gstate_c.spline_tess_v = tess_v; - gstate_c.spline_num_patches_u = num_patches_u; gstate_c.spline_num_points_u = sp_ucount; } } diff --git a/GPU/GPUState.h b/GPU/GPUState.h index d0287c3bcb..cb6aad524a 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -602,9 +602,6 @@ struct GPUStateCache { bool bezier; bool spline; - int spline_tess_u; - int spline_tess_v; - int spline_num_patches_u; int spline_num_points_u; bool useShaderDepal; From 10afcf2dbbbd38baa486d0dd94beda3aec843f61 Mon Sep 17 00:00:00 2001 From: xebra Date: Thu, 27 Sep 2018 20:57:30 +0900 Subject: [PATCH 065/347] [spline/bezier]Improve basic spline/bezier structures. --- GPU/Common/SplineCommon.cpp | 168 ++++++++++++--------------- GPU/Common/SplineCommon.h | 99 +++++++--------- Windows/GEDebugger/VertexPreview.cpp | 82 ++++++------- 3 files changed, 151 insertions(+), 198 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 75866aa11b..80d9bad20c 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -343,37 +343,29 @@ void ControlPoints::Convert(const SimpleVertex *const *points, int size) { defcolor = points[0]->color_32; } -template +template class SubdivisionSurface { -private: - const ControlPoints &points; - const Patch &patch; - const Weight2D &weights; public: - SubdivisionSurface(const ControlPoints &points, const Patch &patch, const Weight2D &weights) - : points(points), patch(patch), weights(weights) { - } - template - void Tessellate(OutputBuffers &output) { - const float inv_u = 1.0f / (float)patch.tess_u; - const float inv_v = 1.0f / (float)patch.tess_v; + static void Tessellate(OutputBuffers &output, const Surface &surface, const ControlPoints &points, const Weight2D &weights) { + const float inv_u = 1.0f / (float)surface.tess_u; + const float inv_v = 1.0f / (float)surface.tess_v; - for (int patch_u = 0; patch_u < patch.num_patches_u; ++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 start_v = patch.GetTessStart(patch_v); + for (int patch_u = 0; patch_u < surface.num_patches_u; ++patch_u) { + const int start_u = surface.GetTessStart(patch_u); + for (int patch_v = 0; patch_v < surface.num_patches_v; ++patch_v) { + const int start_v = surface.GetTessStart(patch_v); // Prepare 4x4 control points to tessellate - const int idx = patch.GetPointIndex(patch_u, patch_v); - const int idx_v[4] = { idx, idx + patch.count_u, idx + patch.count_u * 2, idx + patch.count_u * 3 }; + const int idx = surface.GetPointIndex(patch_u, patch_v); + const int idx_v[4] = { idx, idx + surface.num_points_u, idx + surface.num_points_u * 2, idx + surface.num_points_u * 3 }; Tessellator tess_pos(points.pos, idx_v); Tessellator tess_col(points.col, idx_v); Tessellator tess_tex(points.tex, idx_v); Tessellator tess_nrm(points.pos, idx_v); - for (int tile_u = start_u; tile_u <= patch.tess_u; ++tile_u) { - const int index_u = patch.GetIndexU(patch_u, tile_u); + for (int tile_u = start_u; tile_u <= surface.tess_u; ++tile_u) { + const int index_u = surface.GetIndexU(patch_u, tile_u); const Weight &wu = weights.u[index_u]; // Pre-tessellate U lines @@ -385,11 +377,11 @@ public: if (sampleNrm) tess_nrm.SampleU(wu.deriv); - for (int tile_v = start_v; tile_v <= patch.tess_v; ++tile_v) { - const int index_v = patch.GetIndexV(patch_v, tile_v); + for (int tile_v = start_v; tile_v <= surface.tess_v; ++tile_v) { + const int index_v = surface.GetIndexV(patch_v, tile_v); const Weight &wv = weights.v[index_v]; - SimpleVertex &vert = output.vertices[patch.GetIndex(index_u, index_v, patch_u, patch_v)]; + SimpleVertex &vert = output.vertices[surface.GetIndex(index_u, index_v, patch_u, patch_v)]; // Tessellate vert.pos = tess_pos.SampleV(wv.basis); @@ -420,62 +412,60 @@ public: } } - patch.BuildIndex(output.indices, output.count); + surface.BuildIndex(output.indices, output.count); } - using TessFunc = void(SubdivisionSurface::*)(OutputBuffers &); + using TessFunc = void(*)(OutputBuffers &, const Surface &, const ControlPoints &, const Weight2D &); TEMPLATE_PARAMETER_DISPATCHER_FUNCTION(Tess, SubdivisionSurface::Tessellate, TessFunc); - void Tessellate(OutputBuffers &output, u32 origVertType) { - constexpr int NumParams = 5; - static TemplateParameterDispatcher dispatcher; // Initialize only once - - const bool params[NumParams] = { + static void Tessellate(OutputBuffers &output, const Surface &surface, const ControlPoints &points, const Weight2D &weights, u32 origVertType) { + const bool params[] = { (origVertType & GE_VTYPE_NRM_MASK) != 0, (origVertType & GE_VTYPE_COL_MASK) != 0, (origVertType & GE_VTYPE_TC_MASK) != 0, cpu_info.bSSE4_1, - patch.patchFacing, + surface.patchFacing, }; + static TemplateParameterDispatcher dispatcher; // Initialize only once + TessFunc func = dispatcher.GetFunc(params); - (this->*func)(output); + func(output, surface, points, weights); } }; -template -void SoftwareTessellation(OutputBuffers &output, const Patch &patch, u32 origVertType, const ControlPoints &points) { - using WeightType = typename Patch::WeightType; - u32 key_u = WeightType::ToKey(patch.tess_u, patch.count_u, patch.type_u); - u32 key_v = WeightType::ToKey(patch.tess_v, patch.count_v, patch.type_v); +template +void SoftwareTessellation(OutputBuffers &output, const Surface &surface, u32 origVertType, const ControlPoints &points) { + using WeightType = typename Surface::WeightType; + u32 key_u = WeightType::ToKey(surface.tess_u, surface.num_points_u, surface.type_u); + u32 key_v = WeightType::ToKey(surface.tess_v, surface.num_points_v, surface.type_v); Weight2D weights(WeightType::weightsCache, key_u, key_v); - SubdivisionSurface surface(points, patch, weights); - surface.Tessellate(output, origVertType); + SubdivisionSurface::Tessellate(output, surface, points, weights, origVertType); } -template -static void HardwareTessellation(OutputBuffers &output, const Patch &patch, u32 origVertType, +template +static void HardwareTessellation(OutputBuffers &output, const Surface &surface, u32 origVertType, const SimpleVertex *const *points, TessellationDataTransfer *tessDataTransfer) { - using WeightType = typename Patch::WeightType; - u32 key_u = WeightType::ToKey(patch.tess_u, patch.count_u, patch.type_u); - u32 key_v = WeightType::ToKey(patch.tess_v, patch.count_v, patch.type_v); + using WeightType = typename Surface::WeightType; + u32 key_u = WeightType::ToKey(surface.tess_u, surface.num_points_u, surface.type_u); + u32 key_v = WeightType::ToKey(surface.tess_v, surface.num_points_v, surface.type_v); Weight2D weights(WeightType::weightsCache, key_u, key_v); - weights.size_u = WeightType::CalcSize(patch.tess_u, patch.count_u); - weights.size_v = WeightType::CalcSize(patch.tess_v, patch.count_v); - tessDataTransfer->SendDataToShader(points, patch.count_u, patch.count_v, origVertType, weights); + weights.size_u = WeightType::CalcSize(surface.tess_u, surface.num_points_u); + weights.size_v = WeightType::CalcSize(surface.tess_v, surface.num_points_v); + tessDataTransfer->SendDataToShader(points, surface.num_points_u, surface.num_points_v, origVertType, weights); // Generating simple input vertices for the spline-computing vertex shader. - float inv_u = 1.0f / (float)patch.tess_u; - float inv_v = 1.0f / (float)patch.tess_v; - for (int patch_u = 0; patch_u < patch.num_patches_u; ++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 start_v = patch.GetTessStart(patch_v); - for (int tile_u = start_u; tile_u <= patch.tess_u; ++tile_u) { - const int index_u = patch.GetIndexU(patch_u, tile_u); - for (int tile_v = start_v; tile_v <= patch.tess_v; ++tile_v) { - const int index_v = patch.GetIndexV(patch_v, tile_v); - SimpleVertex &vert = output.vertices[patch.GetIndex(index_u, index_v, patch_u, patch_v)]; + float inv_u = 1.0f / (float)surface.tess_u; + float inv_v = 1.0f / (float)surface.tess_v; + for (int patch_u = 0; patch_u < surface.num_patches_u; ++patch_u) { + const int start_u = surface.GetTessStart(patch_u); + for (int patch_v = 0; patch_v < surface.num_patches_v; ++patch_v) { + const int start_v = surface.GetTessStart(patch_v); + for (int tile_u = start_u; tile_u <= surface.tess_u; ++tile_u) { + const int index_u = surface.GetIndexU(patch_u, tile_u); + for (int tile_v = start_v; tile_v <= surface.tess_v; ++tile_v) { + const int index_v = surface.GetIndexV(patch_v, tile_v); + SimpleVertex &vert = output.vertices[surface.GetIndex(index_u, index_v, patch_u, patch_v)]; // Index for the weights vert.pos.x = index_u; vert.pos.y = index_v; @@ -489,7 +479,7 @@ static void HardwareTessellation(OutputBuffers &output, const Patch &patch, u32 } } } - patch.BuildIndex(output.indices, output.count); + surface.BuildIndex(output.indices, output.count); } void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indices, int tess_u, int tess_v, int count_u, int count_v, int type_u, int type_v, GEPatchPrimType prim_type, bool computeNormals, bool patchFacing, u32 vertType, int *bytesRead) { @@ -525,10 +515,6 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi ERROR_LOG(G3D, "Something went really wrong, vertex size: %i vs %i", vertexSize, (int)sizeof(SimpleVertex)); } - // If specified as 0, uses 1. - if (tess_u < 1) tess_u = 1; - if (tess_v < 1) tess_v = 1; - // Make an array of pointers to the control points, to get rid of indices. const SimpleVertex **points = (const SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * count_u * count_v); for (int idx = 0; idx < count_u * count_v; idx++) @@ -539,24 +525,24 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi output.indices = quadIndices_; output.count = 0; - SplinePatchLocal patch; - patch.tess_u = tess_u; - patch.tess_v = tess_v; - patch.type_u = type_u; - patch.type_v = type_v; - patch.count_u = count_u; - patch.count_v = count_v; - patch.num_patches_u = count_u - 3; - patch.num_patches_v = count_v - 3; - patch.primType = prim_type; - patch.patchFacing = patchFacing; - patch.Init(SPLINE_BUFFER_SIZE / vertexSize); + SplineSurface surface; + surface.tess_u = tess_u; + surface.tess_v = tess_v; + surface.type_u = type_u; + surface.type_v = type_v; + surface.num_points_u = count_u; + surface.num_points_v = count_v; + surface.num_patches_u = count_u - 3; + surface.num_patches_v = count_v - 3; + surface.primType = prim_type; + surface.patchFacing = patchFacing; + surface.Init(SPLINE_BUFFER_SIZE / vertexSize); if (CanUseHardwareTessellation(prim_type)) { - HardwareTessellation(output, patch, origVertType, points, tessDataTransfer); + HardwareTessellation(output, surface, origVertType, points, tessDataTransfer); } else { ControlPoints cpoints(points, count_u * count_v, managedBuf); - SoftwareTessellation(output, patch, origVertType, cpoints); + SoftwareTessellation(output, surface, origVertType, cpoints); } u32 vertTypeWithIndex16 = (vertType & ~GE_VTYPE_IDX_MASK) | GE_VTYPE_IDX_16BIT; @@ -618,10 +604,6 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi ERROR_LOG(G3D, "Something went really wrong, vertex size: %i vs %i", vertexSize, (int)sizeof(SimpleVertex)); } - // If specified as 0, uses 1. - if (tess_u < 1) tess_u = 1; - if (tess_v < 1) tess_v = 1; - // Make an array of pointers to the control points, to get rid of indices. const SimpleVertex **points = (const SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * count_u * count_v); for (int idx = 0; idx < count_u * count_v; idx++) @@ -632,22 +614,22 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi output.indices = quadIndices_; output.count = 0; - BezierPatch patch; - patch.tess_u = tess_u; - patch.tess_v = tess_v; - patch.count_u = count_u; - patch.count_v = count_v; - patch.num_patches_u = (count_u - 1) / 3; - patch.num_patches_v = (count_v - 1) / 3; - patch.primType = prim_type; - patch.patchFacing = patchFacing; - patch.Init(SPLINE_BUFFER_SIZE / vertexSize); + BezierSurface surface; + surface.tess_u = tess_u; + surface.tess_v = tess_v; + surface.num_points_u = count_u; + surface.num_points_v = count_v; + surface.num_patches_u = (count_u - 1) / 3; + surface.num_patches_v = (count_v - 1) / 3; + surface.primType = prim_type; + surface.patchFacing = patchFacing; + surface.Init(SPLINE_BUFFER_SIZE / vertexSize); if (CanUseHardwareTessellation(prim_type)) { - HardwareTessellation(output, patch, origVertType, points, tessDataTransfer); + HardwareTessellation(output, surface, origVertType, points, tessDataTransfer); } else { ControlPoints cpoints(points, count_u * count_v, managedBuf); - SoftwareTessellation(output, patch, origVertType, cpoints); + SoftwareTessellation(output, surface, origVertType, cpoints); } u32 vertTypeWithIndex16 = (vertType & ~GE_VTYPE_IDX_MASK) | GE_VTYPE_IDX_16BIT; diff --git a/GPU/Common/SplineCommon.h b/GPU/Common/SplineCommon.h index 3918cf1845..fdac8b7831 100644 --- a/GPU/Common/SplineCommon.h +++ b/GPU/Common/SplineCommon.h @@ -50,21 +50,20 @@ class Spline3DWeight; // We decode all vertices into a common format for easy interpolation and stuff. // Not fast but can be optimized later. -struct BezierPatch { - using WeightType = Bezier3DWeight; - int tess_u; - int tess_v; - int count_u; - int count_v; - int type_u; - int type_v; - int num_patches_u; - int num_patches_v; +struct SurfaceInfo { + int tess_u, tess_v; + int num_points_u, num_points_v; + int num_patches_u, num_patches_v; + int type_u, type_v; GEPatchPrimType primType; bool patchFacing; - void Init(int maxVertices) { + void Init() { + // If specified as 0, uses 1. + if (tess_u < 1) tess_u = 1; + if (tess_v < 1) tess_v = 1; + switch (g_Config.iSplineBezierQuality) { case LOW_QUALITY: tess_u = 2; @@ -74,93 +73,77 @@ struct BezierPatch { // Don't cut below 2, though. if (tess_u > 2) tess_u = HALF_CEIL(tess_u); if (tess_v > 2) tess_v = HALF_CEIL(tess_v); - // Pass through - case HIGH_QUALITY: - // Downsample until it fits, in case crazy tessellation factors are sent. - while ((tess_u + 1) * (tess_v + 1) * num_patches_u * num_patches_v > maxVertices) { - tess_u--; - tess_v--; - } break; } } +}; + +struct BezierSurface : public SurfaceInfo { + using WeightType = Bezier3DWeight; + + int num_verts_per_patch; + + void Init(int maxVertices) { + SurfaceInfo::Init(); + // Downsample until it fits, in case crazy tessellation factors are sent. + while ((tess_u + 1) * (tess_v + 1) * num_patches_u * num_patches_v > maxVertices) { + tess_u--; + tess_v--; + } + num_verts_per_patch = (tess_u + 1) * (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;} + int GetPointIndex(int patch_u, int patch_v) const { return patch_v * 3 * num_points_u + patch_u * 3; } int GetIndexU(int patch_u, int tile_u) const { return tile_u; } int GetIndexV(int patch_v, int tile_v) const { return tile_v; } - int GetPatchIndex(int patch_u, int patch_v) const { return patch_v * num_patches_u + patch_u;} int GetIndex(int index_u, int index_v, int patch_u, int patch_v) const { - return index_v * (tess_u + 1) + index_u + (tess_u + 1) * (tess_v + 1) * GetPatchIndex(patch_u, patch_v); + int patch_index = patch_v * num_patches_u + patch_u; + return index_v * (tess_u + 1) + index_u + num_verts_per_patch * patch_index; } void BuildIndex(u16 *indices, int &count) const { for (int patch_u = 0; patch_u < num_patches_u; ++patch_u) { for (int patch_v = 0; patch_v < num_patches_v; ++patch_v) { int patch_index = patch_v * num_patches_u + patch_u; - int total = patch_index * (tess_u + 1) * (tess_v + 1); + int total = patch_index * num_verts_per_patch; ::BuildIndex(indices + count, count, tess_u, tess_v, primType, total); } } } }; -struct SplinePatchLocal { +struct SplineSurface : public SurfaceInfo { using WeightType = Spline3DWeight; - int tess_u; - int tess_v; - int count_u; - int count_v; - int type_u; - int type_v; - int num_patches_u; - int num_patches_v; - int num_divisions_u; - int num_divisions_v; - bool patchFacing; - GEPatchPrimType primType; + int num_vertices_u; void Init(int maxVertices) { - switch (g_Config.iSplineBezierQuality) { - case LOW_QUALITY: - tess_u = 2; - tess_v = 2; - break; - case MEDIUM_QUALITY: - // Don't cut below 2, though. - if (tess_u > 2) tess_u = HALF_CEIL(tess_u); - if (tess_v > 2) tess_v = HALF_CEIL(tess_v); - // Pass through - case HIGH_QUALITY: - // Downsample until it fits, in case crazy tessellation factors are sent. - while ((num_patches_u * tess_u + 1) * (num_patches_v * tess_v + 1) > maxVertices) { - tess_u--; - tess_v--; - } - break; + SurfaceInfo::Init(); + // Downsample until it fits, in case crazy tessellation factors are sent. + while ((num_patches_u * tess_u + 1) * (num_patches_v * tess_v + 1) > maxVertices) { + tess_u--; + tess_v--; } - - num_divisions_u = num_patches_u * tess_u; - num_divisions_v = num_patches_v * tess_v; + num_vertices_u = num_patches_u * tess_u + 1; } 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;} + int GetPointIndex(int patch_u, int patch_v) const { return patch_v * num_points_u + patch_u; } int GetIndexU(int patch_u, int tile_u) const { return patch_u * tess_u + tile_u; } int GetIndexV(int patch_v, int tile_v) const { return patch_v * tess_v + tile_v; } int GetIndex(int index_u, int index_v, int patch_u, int patch_v) const { - return index_v * (num_divisions_u + 1) + index_u; + return index_v * num_vertices_u + index_u; } void BuildIndex(u16 *indices, int &count) const { - ::BuildIndex(indices, count, num_divisions_u, num_divisions_v, primType); + ::BuildIndex(indices, count, num_patches_u * tess_u, num_patches_v * tess_v, primType); } }; diff --git a/Windows/GEDebugger/VertexPreview.cpp b/Windows/GEDebugger/VertexPreview.cpp index c4c42f81ad..f4e54e76b8 100644 --- a/Windows/GEDebugger/VertexPreview.cpp +++ b/Windows/GEDebugger/VertexPreview.cpp @@ -171,45 +171,39 @@ static void ExpandBezier(int &count, int op, const std::vector &si if (count_u < 4 || count_v < 4) return; - int tess_u = gstate.getPatchDivisionU(); - int tess_v = gstate.getPatchDivisionV(); - // If specified as 0, uses 1. - if (tess_u < 1) tess_u = 1; - if (tess_v < 1) tess_v = 1; - - BezierPatch patch; - patch.count_u = count_u; - patch.count_v = count_v; - patch.tess_u = tess_u; - patch.tess_v = tess_v; - patch.num_patches_u = (count_u - 1) / 3; - patch.num_patches_v = (count_v - 1) / 3; - patch.primType = gstate.getPatchPrimitiveType(); - patch.patchFacing = false; + BezierSurface surface; + surface.num_points_u = count_u; + surface.num_points_v = count_v; + surface.tess_u = gstate.getPatchDivisionU(); + surface.tess_v = gstate.getPatchDivisionV(); + surface.num_patches_u = (count_u - 1) / 3; + surface.num_patches_v = (count_v - 1) / 3; + surface.primType = gstate.getPatchPrimitiveType(); + surface.patchFacing = false; + int size = count_u * count_v; // Make an array of pointers to the control points, to get rid of indices. - std::vector points(count_u * count_v); - for (int idx = 0; idx < count_u * count_v; idx++) + std::vector points(size); + for (int idx = 0; idx < size; idx++) points[idx] = simpleVerts.data() + (!indices.empty() ? indices[idx] : idx); - int total_patches = patch.num_patches_u * patch.num_patches_v; - generatedVerts.resize((tess_u + 1) * (tess_v + 1) * total_patches); - generatedInds.resize(tess_u * tess_v * 6 * total_patches); + int total_patches = surface.num_patches_u * surface.num_patches_v; + generatedVerts.resize((surface.tess_u + 1) * (surface.tess_v + 1) * total_patches); + generatedInds.resize(surface.tess_u * surface.tess_v * 6 * total_patches); OutputBuffers output; output.vertices = generatedVerts.data(); output.indices = generatedInds.data(); output.count = 0; - int size = count_u * count_v; ControlPoints cpoints; cpoints.pos = (Vec3f *)AllocateAlignedMemory(sizeof(Vec3f) * size, 16); cpoints.tex = (Vec2f *)AllocateAlignedMemory(sizeof(Vec2f) * size, 16); cpoints.col = (Vec4f *)AllocateAlignedMemory(sizeof(Vec4f) * size, 16); cpoints.Convert(points.data(), size); - patch.Init(generatedVerts.size()); - SoftwareTessellation(output, patch, gstate.vertType, cpoints); + surface.Init(generatedVerts.size()); + SoftwareTessellation(output, surface, gstate.vertType, cpoints); count = output.count; FreeAlignedMemory(cpoints.pos); @@ -224,31 +218,26 @@ static void ExpandSpline(int &count, int op, const std::vector &si if (count_u < 4 || count_v < 4) return; - int tess_u = gstate.getPatchDivisionU(); - int tess_v = gstate.getPatchDivisionV(); - // If specified as 0, uses 1. - if (tess_u < 1) tess_u = 1; - if (tess_v < 1) tess_v = 1; - - SplinePatchLocal patch; - patch.count_u = count_u; - patch.count_v = count_v; - patch.tess_u = tess_u; - patch.tess_v = tess_v; - patch.type_u = (op >> 16) & 0x3; - patch.type_v = (op >> 18) & 0x3; - patch.num_patches_u = count_u - 3; - patch.num_patches_v = count_v - 3; - patch.primType = gstate.getPatchPrimitiveType(); - patch.patchFacing = false; + SplineSurface surface; + surface.num_points_u = count_u; + surface.num_points_v = count_v; + surface.tess_u = gstate.getPatchDivisionU(); + surface.tess_v = gstate.getPatchDivisionV(); + surface.type_u = (op >> 16) & 0x3; + surface.type_v = (op >> 18) & 0x3; + surface.num_patches_u = count_u - 3; + surface.num_patches_v = count_v - 3; + surface.primType = gstate.getPatchPrimitiveType(); + surface.patchFacing = false; + int size = count_u * count_v; // Make an array of pointers to the control points, to get rid of indices. - std::vector points(count_u * count_v); - for (int idx = 0; idx < count_u * count_v; idx++) + std::vector points(size); + for (int idx = 0; idx < size; idx++) points[idx] = simpleVerts.data() + (!indices.empty() ? indices[idx] : idx); - int patch_div_s = patch.num_patches_u * patch.tess_u; - int patch_div_t = patch.num_patches_v * patch.tess_v; + int patch_div_s = surface.num_patches_u * surface.tess_u; + int patch_div_t = surface.num_patches_v * surface.tess_v; generatedVerts.resize((patch_div_s + 1) * (patch_div_t + 1)); generatedInds.resize(patch_div_s * patch_div_t * 6); @@ -257,15 +246,14 @@ static void ExpandSpline(int &count, int op, const std::vector &si output.indices = generatedInds.data(); output.count = 0; - int size = count_u * count_v; ControlPoints cpoints; cpoints.pos = (Vec3f *)AllocateAlignedMemory(sizeof(Vec3f) * size, 16); cpoints.tex = (Vec2f *)AllocateAlignedMemory(sizeof(Vec2f) * size, 16); cpoints.col = (Vec4f *)AllocateAlignedMemory(sizeof(Vec4f) * size, 16); cpoints.Convert(points.data(), size); - patch.Init(generatedVerts.size()); - SoftwareTessellation(output, patch, gstate.vertType, cpoints); + surface.Init(generatedVerts.size()); + SoftwareTessellation(output, surface, gstate.vertType, cpoints); count = output.count; FreeAlignedMemory(cpoints.pos); From 1dfb4028710a4de95da9a8f8bd182c72eef4a640 Mon Sep 17 00:00:00 2001 From: xebra Date: Sat, 29 Sep 2018 01:15:38 +0900 Subject: [PATCH 066/347] [spline/bezier]Remove comment. --- GPU/GLES/GPU_GLES.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index f527010a55..fe934d7124 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -110,7 +110,6 @@ GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw) // Disable hardware tessellation if device is unsupported. bool hasTexelFetch = gl_extensions.GLES3 || (!gl_extensions.IsGLES && gl_extensions.VersionGEThan(3, 3, 0)) || gl_extensions.EXT_gpu_shader4; if (!gstate_c.SupportsAll(GPU_SUPPORTS_VERTEX_TEXTURE_FETCH | GPU_SUPPORTS_TEXTURE_FLOAT) || !hasTexelFetch) { - // TODO: Check unsupported device name list.(Above gpu features are supported but it has issues with weak gpu, memory, shader compiler etc...) g_Config.bHardwareTessellation = false; ERROR_LOG(G3D, "Hardware Tessellation is unsupported, falling back to software tessellation"); I18NCategory *gr = GetI18NCategory("Graphics"); From ef53195ae83db5d5dc7a9a392c11ffdc11aa7b72 Mon Sep 17 00:00:00 2001 From: xebra Date: Sat, 29 Sep 2018 13:39:02 +0900 Subject: [PATCH 067/347] [spline/bezier]Surround with namespace Spline. --- GPU/Common/DrawEngineCommon.h | 4 +- GPU/Common/SplineCommon.cpp | 70 +++++++++++++++------------- GPU/Common/SplineCommon.h | 16 ++++--- GPU/D3D11/DrawEngineD3D11.cpp | 4 +- GPU/D3D11/DrawEngineD3D11.h | 2 +- GPU/Directx9/DrawEngineDX9.cpp | 2 +- GPU/Directx9/DrawEngineDX9.h | 2 +- GPU/GLES/DrawEngineGLES.cpp | 2 +- GPU/GLES/DrawEngineGLES.h | 2 +- GPU/Vulkan/DrawEngineVulkan.cpp | 4 +- GPU/Vulkan/DrawEngineVulkan.h | 2 +- Windows/GEDebugger/VertexPreview.cpp | 4 ++ 12 files changed, 66 insertions(+), 48 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index c2bc891845..349b9ff958 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -27,7 +27,6 @@ #include "GPU/Common/GPUDebugInterface.h" #include "GPU/Common/IndexGenerator.h" #include "GPU/Common/VertexDecoderCommon.h" -#include "GPU/Common/SplineCommon.h" class VertexDecoder; @@ -52,11 +51,12 @@ inline uint32_t GetVertTypeID(uint32_t vertType, int uvGenMode) { } struct SimpleVertex; +namespace Spline { struct Weight2D; } class TessellationDataTransfer { public: void CopyControlPoints(float *pos, float *tex, float *col, int posStride, int texStride, int colStride, const SimpleVertex *const *points, int size, u32 vertType); - virtual void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) = 0; + virtual void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) = 0; }; class DrawEngineCommon { diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 80d9bad20c..449d58f723 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -28,6 +28,35 @@ #include "GPU/ge_constants.h" #include "GPU/GPUState.h" // only needed for UVScale stuff +bool CanUseHardwareTessellation(GEPatchPrimType prim) { + if (g_Config.bHardwareTessellation && !g_Config.bSoftwareRendering) { + return CanUseHardwareTransform(PatchPrimToPrim(prim)); + } + return false; +} + +class SimpleBufferManager { +private: + u8 *buf_; + size_t totalSize, maxSize_; +public: + SimpleBufferManager(u8 *buf, size_t maxSize) + : buf_(buf), totalSize(0), maxSize_(maxSize) {} + + u8 *Allocate(size_t size) { + size = (size + 15) & ~15; // Align for 16 bytes + + if ((totalSize + size) > maxSize_) + return nullptr; // No more memory + + size_t tmp = totalSize; + totalSize += size; + return buf_ + tmp; + } +}; + +namespace Spline { + static void CopyQuadIndex(u16 *&indices, GEPatchPrimType type, const int idx0, const int idx1, const int idx2, const int idx3) { if (type == GE_PATCHPRIM_LINES) { *(indices++) = idx0; @@ -256,18 +285,6 @@ public: WeightCache Bezier3DWeight::weightsCache; WeightCache Spline3DWeight::weightsCache; -void DrawEngineCommon::ClearSplineBezierWeights() { - Bezier3DWeight::weightsCache.Clear(); - Spline3DWeight::weightsCache.Clear(); -} - -bool CanUseHardwareTessellation(GEPatchPrimType prim) { - if (g_Config.bHardwareTessellation && !g_Config.bSoftwareRendering) { - return CanUseHardwareTransform(PatchPrimToPrim(prim)); - } - return false; -} - // Tessellate single patch (4x4 control points) template class Tessellator { @@ -307,26 +324,6 @@ public: } }; -class SimpleBufferManager { -private: - u8 *buf_; - size_t totalSize, maxSize_; -public: - SimpleBufferManager(u8 *buf, size_t maxSize) - : buf_(buf), totalSize(0), maxSize_(maxSize) {} - - u8 *Allocate(size_t size) { - size = (size + 15) & ~15; // Align for 16 bytes - - if ((totalSize + size) > maxSize_) - return nullptr; // No more memory - - size_t tmp = totalSize; - totalSize += size; - return buf_ + tmp; - } -}; - ControlPoints::ControlPoints(const SimpleVertex *const *points, int size, SimpleBufferManager &managedBuf) { pos = (Vec3f *)managedBuf.Allocate(sizeof(Vec3f) * size); tex = (Vec2f *)managedBuf.Allocate(sizeof(Vec2f) * size); @@ -482,6 +479,15 @@ static void HardwareTessellation(OutputBuffers &output, const Surface &surface, surface.BuildIndex(output.indices, output.count); } +} + +using namespace Spline; + +void DrawEngineCommon::ClearSplineBezierWeights() { + Bezier3DWeight::weightsCache.Clear(); + Spline3DWeight::weightsCache.Clear(); +} + void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indices, int tess_u, int tess_v, int count_u, int count_v, int type_u, int type_v, GEPatchPrimType prim_type, bool computeNormals, bool patchFacing, u32 vertType, int *bytesRead) { PROFILE_THIS_SCOPE("spline"); DispatchFlush(); diff --git a/GPU/Common/SplineCommon.h b/GPU/Common/SplineCommon.h index fdac8b7831..1d534cf215 100644 --- a/GPU/Common/SplineCommon.h +++ b/GPU/Common/SplineCommon.h @@ -37,6 +37,10 @@ struct SimpleVertex { Vec3Packedf pos; }; +class SimpleBufferManager; + +namespace Spline { + void BuildIndex(u16 *indices, int &count, int num_u, int num_v, GEPatchPrimType prim_type, int total = 0); enum SplineQuality { @@ -110,7 +114,7 @@ struct BezierSurface : public SurfaceInfo { for (int patch_v = 0; patch_v < num_patches_v; ++patch_v) { int patch_index = patch_v * num_patches_u + patch_u; int total = patch_index * num_verts_per_patch; - ::BuildIndex(indices + count, count, tess_u, tess_v, primType, total); + Spline::BuildIndex(indices + count, count, tess_u, tess_v, primType, total); } } } @@ -143,7 +147,7 @@ struct SplineSurface : public SurfaceInfo { } void BuildIndex(u16 *indices, int &count) const { - ::BuildIndex(indices, count, num_patches_u * tess_u, num_patches_v * tess_v, primType); + Spline::BuildIndex(indices, count, num_patches_u * tess_u, num_patches_v * tess_v, primType); } }; @@ -181,8 +185,6 @@ struct Weight2D { } }; -class SimpleBufferManager; - struct ControlPoints { Vec3f *pos; Vec2f *tex; @@ -200,11 +202,13 @@ struct OutputBuffers { int count; }; -bool CanUseHardwareTessellation(GEPatchPrimType prim); - template void SoftwareTessellation(OutputBuffers &output, const Patch &patch, u32 origVertType, const ControlPoints &points); +} + +bool CanUseHardwareTessellation(GEPatchPrimType prim); + // Define function object for TemplateParameterDispatcher #define TEMPLATE_PARAMETER_DISPATCHER_FUNCTION(NAME, FUNCNAME, FUNCTYPE) \ struct NAME { \ diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 9a90320407..3a37cb63d1 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -702,7 +702,7 @@ TessellationDataTransferD3D11::~TessellationDataTransferD3D11() { } } -void TessellationDataTransferD3D11::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) { +void TessellationDataTransferD3D11::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) { struct TessData { float pos[3]; float pad1; float uv[2]; float pad2[2]; @@ -735,6 +735,8 @@ void TessellationDataTransferD3D11::SendDataToShader(const SimpleVertex *const * context_->Unmap(buf[0], 0); + using Spline::Weight; + // Weights U if (prevSizeWU < weights.size_u) { prevSizeWU = weights.size_u; diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h index a29b43553a..11ed3e41e9 100644 --- a/GPU/D3D11/DrawEngineD3D11.h +++ b/GPU/D3D11/DrawEngineD3D11.h @@ -112,7 +112,7 @@ public: TessellationDataTransferD3D11(ID3D11DeviceContext *context, ID3D11Device *device); ~TessellationDataTransferD3D11(); // Send spline/bezier's control points and weights to vertex shader through structured shader buffer. - void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) override; + void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) override; }; // Handles transform, lighting and drawing. diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index 0669412d0a..3dec358faa 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -625,7 +625,7 @@ rotateVBO: GPUDebug::NotifyDraw(); } -void TessellationDataTransferDX9::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) { +void TessellationDataTransferDX9::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) { // TODO } diff --git a/GPU/Directx9/DrawEngineDX9.h b/GPU/Directx9/DrawEngineDX9.h index 7ec653ddef..f1c80eea51 100644 --- a/GPU/Directx9/DrawEngineDX9.h +++ b/GPU/Directx9/DrawEngineDX9.h @@ -101,7 +101,7 @@ class TessellationDataTransferDX9 : public TessellationDataTransfer { public: TessellationDataTransferDX9() {} ~TessellationDataTransferDX9() {} - void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) override; + void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) override; }; // Handles transform, lighting and drawing. diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 79051abb07..937ab0bca8 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -653,7 +653,7 @@ bool DrawEngineGLES::IsCodePtrVertexDecoder(const u8 *ptr) const { return decJitCache_->IsInSpace(ptr); } -void TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) { +void TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) { bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0; bool hasTexCoord = (vertType & GE_VTYPE_TC_MASK) != 0; diff --git a/GPU/GLES/DrawEngineGLES.h b/GPU/GLES/DrawEngineGLES.h index 858f927485..8b29700f83 100644 --- a/GPU/GLES/DrawEngineGLES.h +++ b/GPU/GLES/DrawEngineGLES.h @@ -123,7 +123,7 @@ public: EndFrame(); } // Send spline/bezier's control points and weights to vertex shader through floating point texture. - void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) override; + void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) override; void EndFrame(); // Queues textures for deletion. }; diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index a3bba5d3b7..407580e16f 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -1013,7 +1013,7 @@ void DrawEngineVulkan::UpdateUBOs(FrameData *frame) { } } -void TessellationDataTransferVulkan::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) { +void TessellationDataTransferVulkan::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) { // SSBOs that are not simply float1 or float2 need to be padded up to a float4 size. vec3 members // also need to be 16-byte aligned, hence the padding. struct TessData { @@ -1035,6 +1035,8 @@ void TessellationDataTransferVulkan::SendDataToShader(const SimpleVertex *const CopyControlPoints(pos, tex, col, stride, stride, stride, points, size, vertType); + using Spline::Weight; + // Weights U data = (uint8_t *)push_->PushAligned(weights.size_u * sizeof(Weight), (uint32_t *)&bufInfo_[1].offset, &bufInfo_[1].buffer, ssboAlignment); memcpy(data, weights.u, weights.size_u * sizeof(Weight)); diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index c27e9be04b..cece2c08c6 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -123,7 +123,7 @@ public: void SetPushBuffer(VulkanPushBuffer *push) { push_ = push; } // Send spline/bezier's control points and weights to vertex shader through structured shader buffer. - void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) override; + void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) override; const VkDescriptorBufferInfo *GetBufferInfo() { return bufInfo_; } private: VulkanContext *vulkan_; diff --git a/Windows/GEDebugger/VertexPreview.cpp b/Windows/GEDebugger/VertexPreview.cpp index f4e54e76b8..31058e1f8e 100644 --- a/Windows/GEDebugger/VertexPreview.cpp +++ b/Windows/GEDebugger/VertexPreview.cpp @@ -165,6 +165,8 @@ u32 CGEDebugger::PrimPreviewOp() { } static void ExpandBezier(int &count, int op, const std::vector &simpleVerts, const std::vector &indices, std::vector &generatedVerts, std::vector &generatedInds) { + using namespace Spline; + int count_u = (op >> 0) & 0xFF; int count_v = (op >> 8) & 0xFF; // Real hardware seems to draw nothing when given < 4 either U or V. @@ -212,6 +214,8 @@ static void ExpandBezier(int &count, int op, const std::vector &si } static void ExpandSpline(int &count, int op, const std::vector &simpleVerts, const std::vector &indices, std::vector &generatedVerts, std::vector &generatedInds) { + using namespace Spline; + int count_u = (op >> 0) & 0xFF; int count_v = (op >> 8) & 0xFF; // Real hardware seems to draw nothing when given < 4 either U or V. From 405ead8d413f4c6145e72782c382c2a167539c94 Mon Sep 17 00:00:00 2001 From: xebra Date: Sat, 29 Sep 2018 18:04:32 +0900 Subject: [PATCH 068/347] [spline/bezier]Get rid of duplication call of Flush(). --- GPU/GPUCommon.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index ff6b91d039..1d8266d500 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1718,8 +1718,6 @@ bail: } void GPUCommon::Execute_Bezier(u32 op, u32 diff) { - drawEngineCommon_->DispatchFlush(); - // We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier. gstate_c.Dirty(DIRTY_UVSCALEOFFSET); @@ -1780,8 +1778,6 @@ void GPUCommon::Execute_Bezier(u32 op, u32 diff) { } void GPUCommon::Execute_Spline(u32 op, u32 diff) { - drawEngineCommon_->DispatchFlush(); - // We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier. gstate_c.Dirty(DIRTY_UVSCALEOFFSET); From 5f9022ae1451f341aa5e175c91b2eba03c609001 Mon Sep 17 00:00:00 2001 From: xebra Date: Sun, 30 Sep 2018 11:07:28 +0900 Subject: [PATCH 069/347] [spline/bezier]minor fix --- GPU/Common/SplineCommon.cpp | 30 +++++++++++++++------------- Windows/GEDebugger/VertexPreview.cpp | 28 +++++++++++++------------- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 449d58f723..c75c0c4ed6 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -498,18 +498,19 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi SimpleBufferManager managedBuf(decoded, DECODED_VERTEX_BUFFER_SIZE); + int num_points = count_u * count_v; u16 index_lower_bound = 0; - u16 index_upper_bound = count_u * count_v - 1; + u16 index_upper_bound = num_points - 1; IndexConverter ConvertIndex(vertType, indices); if (indices) - GetIndexBounds(indices, count_u * count_v, vertType, &index_lower_bound, &index_upper_bound); + GetIndexBounds(indices, num_points, vertType, &index_lower_bound, &index_upper_bound); VertexDecoder *origVDecoder = GetVertexDecoder((vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24)); - *bytesRead = count_u * count_v * origVDecoder->VertexSize(); + *bytesRead = num_points * origVDecoder->VertexSize(); // Simplify away bones and morph before proceeding SimpleVertex *simplified_control_points = (SimpleVertex *)managedBuf.Allocate(sizeof(SimpleVertex) * (index_upper_bound + 1)); - u8 *temp_buffer = managedBuf.Allocate(sizeof(SimpleVertex) * count_u * count_v); + u8 *temp_buffer = managedBuf.Allocate(sizeof(SimpleVertex) * num_points); u32 origVertType = vertType; vertType = NormalizeVertices((u8 *)simplified_control_points, temp_buffer, (u8 *)control_points, index_lower_bound, index_upper_bound, vertType); @@ -522,8 +523,8 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi } // Make an array of pointers to the control points, to get rid of indices. - const SimpleVertex **points = (const SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * count_u * count_v); - for (int idx = 0; idx < count_u * count_v; idx++) + const SimpleVertex **points = (const SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * num_points); + for (int idx = 0; idx < num_points; idx++) points[idx] = simplified_control_points + (indices ? ConvertIndex(idx) : idx); OutputBuffers output; @@ -547,7 +548,7 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi if (CanUseHardwareTessellation(prim_type)) { HardwareTessellation(output, surface, origVertType, points, tessDataTransfer); } else { - ControlPoints cpoints(points, count_u * count_v, managedBuf); + ControlPoints cpoints(points, num_points, managedBuf); SoftwareTessellation(output, surface, origVertType, cpoints); } @@ -586,19 +587,20 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi SimpleBufferManager managedBuf(decoded, DECODED_VERTEX_BUFFER_SIZE); + int num_points = count_u * count_v; u16 index_lower_bound = 0; - u16 index_upper_bound = count_u * count_v - 1; + u16 index_upper_bound = num_points - 1; IndexConverter ConvertIndex(vertType, indices); if (indices) - GetIndexBounds(indices, count_u*count_v, vertType, &index_lower_bound, &index_upper_bound); + GetIndexBounds(indices, num_points, vertType, &index_lower_bound, &index_upper_bound); VertexDecoder *origVDecoder = GetVertexDecoder((vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24)); - *bytesRead = count_u * count_v * origVDecoder->VertexSize(); + *bytesRead = num_points * origVDecoder->VertexSize(); // Simplify away bones and morph before proceeding // There are normally not a lot of control points so just splitting decoded should be reasonably safe, although not great. SimpleVertex *simplified_control_points = (SimpleVertex *)managedBuf.Allocate(sizeof(SimpleVertex) * (index_upper_bound + 1)); - u8 *temp_buffer = managedBuf.Allocate(sizeof(SimpleVertex) * count_u * count_v); + u8 *temp_buffer = managedBuf.Allocate(sizeof(SimpleVertex) * num_points); u32 origVertType = vertType; vertType = NormalizeVertices((u8 *)simplified_control_points, temp_buffer, (u8 *)control_points, index_lower_bound, index_upper_bound, vertType); @@ -611,8 +613,8 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi } // Make an array of pointers to the control points, to get rid of indices. - const SimpleVertex **points = (const SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * count_u * count_v); - for (int idx = 0; idx < count_u * count_v; idx++) + const SimpleVertex **points = (const SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * num_points); + for (int idx = 0; idx < num_points; idx++) points[idx] = simplified_control_points + (indices ? ConvertIndex(idx) : idx); OutputBuffers output; @@ -634,7 +636,7 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi if (CanUseHardwareTessellation(prim_type)) { HardwareTessellation(output, surface, origVertType, points, tessDataTransfer); } else { - ControlPoints cpoints(points, count_u * count_v, managedBuf); + ControlPoints cpoints(points, num_points, managedBuf); SoftwareTessellation(output, surface, origVertType, cpoints); } diff --git a/Windows/GEDebugger/VertexPreview.cpp b/Windows/GEDebugger/VertexPreview.cpp index 31058e1f8e..79183d236f 100644 --- a/Windows/GEDebugger/VertexPreview.cpp +++ b/Windows/GEDebugger/VertexPreview.cpp @@ -183,10 +183,10 @@ static void ExpandBezier(int &count, int op, const std::vector &si surface.primType = gstate.getPatchPrimitiveType(); surface.patchFacing = false; - int size = count_u * count_v; + int num_points = count_u * count_v; // Make an array of pointers to the control points, to get rid of indices. - std::vector points(size); - for (int idx = 0; idx < size; idx++) + std::vector points(num_points); + for (int idx = 0; idx < num_points; idx++) points[idx] = simpleVerts.data() + (!indices.empty() ? indices[idx] : idx); int total_patches = surface.num_patches_u * surface.num_patches_v; @@ -199,10 +199,10 @@ static void ExpandBezier(int &count, int op, const std::vector &si output.count = 0; ControlPoints cpoints; - cpoints.pos = (Vec3f *)AllocateAlignedMemory(sizeof(Vec3f) * size, 16); - cpoints.tex = (Vec2f *)AllocateAlignedMemory(sizeof(Vec2f) * size, 16); - cpoints.col = (Vec4f *)AllocateAlignedMemory(sizeof(Vec4f) * size, 16); - cpoints.Convert(points.data(), size); + cpoints.pos = (Vec3f *)AllocateAlignedMemory(sizeof(Vec3f) * num_points, 16); + cpoints.tex = (Vec2f *)AllocateAlignedMemory(sizeof(Vec2f) * num_points, 16); + cpoints.col = (Vec4f *)AllocateAlignedMemory(sizeof(Vec4f) * num_points, 16); + cpoints.Convert(points.data(), num_points); surface.Init(generatedVerts.size()); SoftwareTessellation(output, surface, gstate.vertType, cpoints); @@ -234,10 +234,10 @@ static void ExpandSpline(int &count, int op, const std::vector &si surface.primType = gstate.getPatchPrimitiveType(); surface.patchFacing = false; - int size = count_u * count_v; + int num_points = count_u * count_v; // Make an array of pointers to the control points, to get rid of indices. - std::vector points(size); - for (int idx = 0; idx < size; idx++) + std::vector points(num_points); + for (int idx = 0; idx < num_points; idx++) points[idx] = simpleVerts.data() + (!indices.empty() ? indices[idx] : idx); int patch_div_s = surface.num_patches_u * surface.tess_u; @@ -251,10 +251,10 @@ static void ExpandSpline(int &count, int op, const std::vector &si output.count = 0; ControlPoints cpoints; - cpoints.pos = (Vec3f *)AllocateAlignedMemory(sizeof(Vec3f) * size, 16); - cpoints.tex = (Vec2f *)AllocateAlignedMemory(sizeof(Vec2f) * size, 16); - cpoints.col = (Vec4f *)AllocateAlignedMemory(sizeof(Vec4f) * size, 16); - cpoints.Convert(points.data(), size); + cpoints.pos = (Vec3f *)AllocateAlignedMemory(sizeof(Vec3f) * num_points, 16); + cpoints.tex = (Vec2f *)AllocateAlignedMemory(sizeof(Vec2f) * num_points, 16); + cpoints.col = (Vec4f *)AllocateAlignedMemory(sizeof(Vec4f) * num_points, 16); + cpoints.Convert(points.data(), num_points); surface.Init(generatedVerts.size()); SoftwareTessellation(output, surface, gstate.vertType, cpoints); From 5f07213c25ef1d09f085dc324749135fbaa47a39 Mon Sep 17 00:00:00 2001 From: xebra Date: Sun, 30 Sep 2018 17:10:58 +0900 Subject: [PATCH 070/347] [spline/bezier]minor fix --- GPU/Common/SplineCommon.cpp | 2 +- GPU/Common/SplineCommon.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index c75c0c4ed6..ee4b26a6b9 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -479,7 +479,7 @@ static void HardwareTessellation(OutputBuffers &output, const Surface &surface, surface.BuildIndex(output.indices, output.count); } -} +} // namespace Spline using namespace Spline; diff --git a/GPU/Common/SplineCommon.h b/GPU/Common/SplineCommon.h index 1d534cf215..a6d82def4b 100644 --- a/GPU/Common/SplineCommon.h +++ b/GPU/Common/SplineCommon.h @@ -202,10 +202,10 @@ struct OutputBuffers { int count; }; -template -void SoftwareTessellation(OutputBuffers &output, const Patch &patch, u32 origVertType, const ControlPoints &points); +template +void SoftwareTessellation(OutputBuffers &output, const Surface &surface, u32 origVertType, const ControlPoints &points); -} +} // namespace Spline bool CanUseHardwareTessellation(GEPatchPrimType prim); From eca9386c0583d3fa1eccd37ce0e6014758ae1150 Mon Sep 17 00:00:00 2001 From: xebra Date: Mon, 1 Oct 2018 12:54:14 +0900 Subject: [PATCH 071/347] [spline/bezier]Reduce static buffers. Get rid of the spline buffer using half of the vertex buffer. --- GPU/Common/DrawEngineCommon.cpp | 2 -- GPU/Common/DrawEngineCommon.h | 4 ---- GPU/Common/SplineCommon.cpp | 12 ++++++------ GPU/D3D11/DrawEngineD3D11.cpp | 2 -- GPU/Directx9/DrawEngineDX9.cpp | 2 -- GPU/GLES/DrawEngineGLES.cpp | 2 -- GPU/Software/TransformUnit.cpp | 2 -- GPU/Vulkan/DrawEngineVulkan.cpp | 2 -- 8 files changed, 6 insertions(+), 22 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index abe7e7cf2d..60c250533a 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -34,7 +34,6 @@ enum { }; DrawEngineCommon::DrawEngineCommon() : decoderMap_(16) { - quadIndices_ = new u16[6 * QUAD_INDICES_MAX]; decJitCache_ = new VertexDecoderJitCache(); transformed = (TransformedVertex *)AllocateMemoryPages(TRANSFORMED_VERTEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); transformedExpanded = (TransformedVertex *)AllocateMemoryPages(3 * TRANSFORMED_VERTEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); @@ -43,7 +42,6 @@ DrawEngineCommon::DrawEngineCommon() : decoderMap_(16) { DrawEngineCommon::~DrawEngineCommon() { FreeMemoryPages(transformed, TRANSFORMED_VERTEX_BUFFER_SIZE); FreeMemoryPages(transformedExpanded, 3 * TRANSFORMED_VERTEX_BUFFER_SIZE); - delete[] quadIndices_; delete decJitCache_; decoderMap_.Iterate([&](const uint32_t vtype, VertexDecoder *decoder) { delete decoder; diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 349b9ff958..353b3dd7d0 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -34,7 +34,6 @@ enum { VERTEX_BUFFER_MAX = 65536, DECODED_VERTEX_BUFFER_SIZE = VERTEX_BUFFER_MAX * 64, DECODED_INDEX_BUFFER_SIZE = VERTEX_BUFFER_MAX * 16, - SPLINE_BUFFER_SIZE = VERTEX_BUFFER_MAX * 26, // At least, this buffer needs greater than 1679616 bytes for Mist Dragon morphing in FF4CC. }; // Avoiding the full include of TextureDecoder.h. @@ -170,9 +169,6 @@ protected: int decodedVerts_ = 0; GEPrimitiveType prevPrim_ = GE_PRIM_INVALID; - // Fixed index buffer for easy quad generation from spline/bezier - u16 *quadIndices_ = nullptr; - // Shader blending state bool fboTexNeedBind_ = false; bool fboTexBound_ = false; diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index ee4b26a6b9..a1f96fed32 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -528,8 +528,8 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi points[idx] = simplified_control_points + (indices ? ConvertIndex(idx) : idx); OutputBuffers output; - output.vertices = (SimpleVertex *)splineBuffer; - output.indices = quadIndices_; + output.vertices = (SimpleVertex *)(decoded + DECODED_VERTEX_BUFFER_SIZE / 2); + output.indices = decIndex; output.count = 0; SplineSurface surface; @@ -543,7 +543,7 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi surface.num_patches_v = count_v - 3; surface.primType = prim_type; surface.patchFacing = patchFacing; - surface.Init(SPLINE_BUFFER_SIZE / vertexSize); + surface.Init(DECODED_VERTEX_BUFFER_SIZE / 2 / vertexSize); if (CanUseHardwareTessellation(prim_type)) { HardwareTessellation(output, surface, origVertType, points, tessDataTransfer); @@ -618,8 +618,8 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi points[idx] = simplified_control_points + (indices ? ConvertIndex(idx) : idx); OutputBuffers output; - output.vertices = (SimpleVertex *)splineBuffer; - output.indices = quadIndices_; + output.vertices = (SimpleVertex *)(decoded + DECODED_VERTEX_BUFFER_SIZE / 2); + output.indices = decIndex; output.count = 0; BezierSurface surface; @@ -631,7 +631,7 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi surface.num_patches_v = (count_v - 1) / 3; surface.primType = prim_type; surface.patchFacing = patchFacing; - surface.Init(SPLINE_BUFFER_SIZE / vertexSize); + surface.Init(DECODED_VERTEX_BUFFER_SIZE / 2 / vertexSize); if (CanUseHardwareTessellation(prim_type)) { HardwareTessellation(output, surface, origVertType, points, tessDataTransfer); diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 3a37cb63d1..e7752017dc 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -89,7 +89,6 @@ DrawEngineD3D11::DrawEngineD3D11(Draw::DrawContext *draw, ID3D11Device *device, // All this is a LOT of memory, need to see if we can cut down somehow. decoded = (u8 *)AllocateMemoryPages(DECODED_VERTEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); decIndex = (u16 *)AllocateMemoryPages(DECODED_INDEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); - splineBuffer = (u8 *)AllocateMemoryPages(SPLINE_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); indexGen.Setup(decIndex); @@ -104,7 +103,6 @@ DrawEngineD3D11::~DrawEngineD3D11() { DestroyDeviceObjects(); FreeMemoryPages(decoded, DECODED_VERTEX_BUFFER_SIZE); FreeMemoryPages(decIndex, DECODED_INDEX_BUFFER_SIZE); - FreeMemoryPages(splineBuffer, SPLINE_BUFFER_SIZE); } void DrawEngineD3D11::InitDeviceObjects() { diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index 3dec358faa..0f1c0b62d3 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -95,7 +95,6 @@ DrawEngineDX9::DrawEngineDX9(Draw::DrawContext *draw) : vai_(256), vertexDeclMap // All this is a LOT of memory, need to see if we can cut down somehow. decoded = (u8 *)AllocateMemoryPages(DECODED_VERTEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); decIndex = (u16 *)AllocateMemoryPages(DECODED_INDEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); - splineBuffer = (u8 *)AllocateMemoryPages(SPLINE_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); indexGen.Setup(decIndex); @@ -115,7 +114,6 @@ DrawEngineDX9::~DrawEngineDX9() { DestroyDeviceObjects(); FreeMemoryPages(decoded, DECODED_VERTEX_BUFFER_SIZE); FreeMemoryPages(decIndex, DECODED_INDEX_BUFFER_SIZE); - FreeMemoryPages(splineBuffer, SPLINE_BUFFER_SIZE); vertexDeclMap_.Iterate([&](const uint32_t &key, IDirect3DVertexDeclaration9 *decl) { if (decl) { decl->Release(); diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 937ab0bca8..a2bb108860 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -81,7 +81,6 @@ DrawEngineGLES::DrawEngineGLES(Draw::DrawContext *draw) : vai_(256), draw_(draw) // All this is a LOT of memory, need to see if we can cut down somehow. decoded = (u8 *)AllocateMemoryPages(DECODED_VERTEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); decIndex = (u16 *)AllocateMemoryPages(DECODED_INDEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); - splineBuffer = (u8 *)AllocateMemoryPages(SPLINE_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); indexGen.Setup(decIndex); @@ -95,7 +94,6 @@ DrawEngineGLES::~DrawEngineGLES() { DestroyDeviceObjects(); FreeMemoryPages(decoded, DECODED_VERTEX_BUFFER_SIZE); FreeMemoryPages(decIndex, DECODED_INDEX_BUFFER_SIZE); - FreeMemoryPages(splineBuffer, SPLINE_BUFFER_SIZE); delete tessDataTransferGLES; } diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 45fc87ccde..e72e9a85cb 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -42,13 +42,11 @@ SoftwareDrawEngine::SoftwareDrawEngine() { // All this is a LOT of memory, need to see if we can cut down somehow. Used for splines. decoded = (u8 *)AllocateMemoryPages(DECODED_VERTEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); decIndex = (u16 *)AllocateMemoryPages(DECODED_INDEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); - splineBuffer = (u8 *)AllocateMemoryPages(SPLINE_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); } SoftwareDrawEngine::~SoftwareDrawEngine() { FreeMemoryPages(decoded, DECODED_VERTEX_BUFFER_SIZE); FreeMemoryPages(decIndex, DECODED_INDEX_BUFFER_SIZE); - FreeMemoryPages(splineBuffer, SPLINE_BUFFER_SIZE); } void SoftwareDrawEngine::DispatchFlush() { diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 407580e16f..654b8a1a41 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -89,7 +89,6 @@ DrawEngineVulkan::DrawEngineVulkan(VulkanContext *vulkan, Draw::DrawContext *dra // All this is a LOT of memory, need to see if we can cut down somehow. decoded = (u8 *)AllocateMemoryPages(DECODED_VERTEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); decIndex = (u16 *)AllocateMemoryPages(DECODED_INDEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); - splineBuffer = (u8 *)AllocateMemoryPages(SPLINE_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); indexGen.Setup(decIndex); @@ -184,7 +183,6 @@ void DrawEngineVulkan::InitDeviceObjects() { DrawEngineVulkan::~DrawEngineVulkan() { FreeMemoryPages(decoded, DECODED_VERTEX_BUFFER_SIZE); FreeMemoryPages(decIndex, DECODED_INDEX_BUFFER_SIZE); - FreeMemoryPages(splineBuffer, SPLINE_BUFFER_SIZE); DestroyDeviceObjects(); } From 46d30d02cfa2a6c0d3f9ceadc1a0b1c8783796fa Mon Sep 17 00:00:00 2001 From: xebra Date: Tue, 2 Oct 2018 21:13:40 +0900 Subject: [PATCH 072/347] [spline/bezier]minor fix --- 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 a1f96fed32..77427b99ee 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -496,7 +496,7 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi if (count_u < 4 || count_v < 4) return; - SimpleBufferManager managedBuf(decoded, DECODED_VERTEX_BUFFER_SIZE); + SimpleBufferManager managedBuf(decoded, DECODED_VERTEX_BUFFER_SIZE / 2); int num_points = count_u * count_v; u16 index_lower_bound = 0; @@ -585,7 +585,7 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi if (count_u < 4 || count_v < 4) return; - SimpleBufferManager managedBuf(decoded, DECODED_VERTEX_BUFFER_SIZE); + SimpleBufferManager managedBuf(decoded, DECODED_VERTEX_BUFFER_SIZE / 2); int num_points = count_u * count_v; u16 index_lower_bound = 0; From 0d7a5cd093397ebae5c06c55e824a871c04548ff Mon Sep 17 00:00:00 2001 From: xebra Date: Mon, 8 Oct 2018 00:29:41 +0900 Subject: [PATCH 073/347] GLES: Fix to delete subimage data since #11447. --- ext/native/thin3d/GLQueueRunner.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/ext/native/thin3d/GLQueueRunner.cpp b/ext/native/thin3d/GLQueueRunner.cpp index 5db058262a..7349a2d625 100644 --- a/ext/native/thin3d/GLQueueRunner.cpp +++ b/ext/native/thin3d/GLQueueRunner.cpp @@ -490,7 +490,19 @@ void GLQueueRunner::RunSteps(const std::vector &steps, bool skipGLCal const GLRStep &step = *steps[i]; switch (step.stepType) { case GLRStepType::RENDER: - // TODO: With #11425 there'll be a case where we should really free spline data here. + for (const auto &c : step.commands) { + switch (c.cmd) { + case GLRRenderCommand::TEXTURE_SUBIMAGE: + if (c.texture_subimage.data) { + if (c.texture_subimage.allocType == GLRAllocType::ALIGNED) { + FreeAlignedMemory(c.texture_subimage.data); + } else if (c.texture_subimage.allocType == GLRAllocType::NEW) { + delete[] c.texture_subimage.data; + } + } + break; + } + } break; } delete steps[i]; From 6b89b6a4bbc6a244b861fb368e1ac2deecd89c8d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 28 Oct 2018 11:13:05 -0700 Subject: [PATCH 074/347] Qt: Add GLES defines if USING_GLES2. See #11495 - thanks to Jan Beich. --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5193b756a2..d29f688fa9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -784,6 +784,9 @@ elseif(USING_QT_UI) Qt/mainwindow.h ) add_definitions(-DUSING_QT_UI) + if(USING_GLES2) + add_definitions(-DQT_OPENGL_ES -DQT_OPENGL_ES_2) + endif() include_directories(${CMAKE_CURRENT_BINARY_DIR} Qt) set(nativeExtraLibs ${nativeExtraLibs} Qt5::OpenGL Qt5::Gui Qt5::Core) set(TargetBin PPSSPPQt) From f81dd83aa053316f1be7b12b627cf528b4cdc801 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 28 Oct 2018 11:33:25 -0700 Subject: [PATCH 075/347] Core: Format CMakeLists.txt consistently. --- CMakeLists.txt | 449 ++++++++++++++++++++++++++----------------------- 1 file changed, 238 insertions(+), 211 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d29f688fa9..4c15cba0d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,9 +3,9 @@ cmake_minimum_required(VERSION 3.6) project(PPSSPP) #This is supposed to work but doesn't! -if (NOT ANDROID) -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED ON) +if(NOT ANDROID) + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED ON) endif() enable_language(ASM) @@ -15,13 +15,13 @@ add_definitions(-D__STDC_CONSTANT_MACROS) if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") - set(CLANG ON) - message("Clang enabled") + set(CLANG ON) + message("Clang enabled") endif() if(FORCED_CPU) - message("Detected CPU (${CMAKE_SYSTEM_PROCESSOR}) overridden as: ${FORCED_CPU}") - set(CMAKE_SYSTEM_PROCESSOR ${FORCED_CPU}) + message("Detected CPU (${CMAKE_SYSTEM_PROCESSOR}) overridden as: ${FORCED_CPU}") + set(CMAKE_SYSTEM_PROCESSOR ${FORCED_CPU}) endif() # Detect CPU from CMAKE configuration. Toolchains should set this up @@ -40,22 +40,22 @@ if(CMAKE_SYSTEM_PROCESSOR) set(ARMV7 ON) add_compile_options(-mfpu=neon) # Horrifying workaround for bug in android cmake stuff for asm files - if (ANDROID) + if(ANDROID) set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -target armv7a-none-linux-android") endif() endif() elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^aarch64") - set(ARM64 ON) - add_definitions(-DARM64) + set(ARM64 ON) + add_definitions(-DARM64) elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^amd64" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "^x86_64" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "^AMD64") set(X86 ON) - set(X86_64 ON) + set(X86_64 ON) elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^x86" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "i.86") set(X86 ON) elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^mips") set(MIPS ON) else() - message("Unknown CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}") + message("Unknown CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}") endif() endif() @@ -146,10 +146,10 @@ if(UNIX AND NOT (APPLE OR ANDROID) AND VULKAN) endif() # add_definitions(-DVK_USE_PLATFORM_XCB_KHR) find_package(Wayland) - if (USE_WAYLAND_WSI AND NOT WAYLAND_FOUND) + if(USE_WAYLAND_WSI AND NOT WAYLAND_FOUND) message(FATAL_ERROR "Could not find libwayland, but USE_WAYLAND_WSI was enabled. Failing.") endif() - if (WAYLAND_FOUND) + if(WAYLAND_FOUND) include_directories(${WAYLAND_INCLUDE_DIR}) add_definitions(-DVK_USE_PLATFORM_WAYLAND_KHR) endif() @@ -215,7 +215,7 @@ if(MOBILE_DEVICE) add_definitions(-DMOBILE_DEVICE) endif() -if (NOT CMAKE_BUILD_TYPE) +if(NOT CMAKE_BUILD_TYPE) message(STATUS "No build type selected, default to Release") set(CMAKE_BUILD_TYPE "Release") endif() @@ -245,10 +245,10 @@ if(ARM64) message("Generating for ARMv8, ${CMAKE_BUILD_TYPE}") endif() if(NOT MSVC) - if (ANDROID) + if(ANDROID) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") endif() - if (CLANG) + if(CLANG) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-switch -Wno-uninitialized") endif() @@ -280,7 +280,7 @@ if(NOT MSVC) # Don't compile with strict aliasing, we're not 100% aliasing-safe add_compile_options(-fno-strict-aliasing) - if (${CMAKE_C_COMPILER_ID} STREQUAL "Intel") + if(${CMAKE_C_COMPILER_ID} STREQUAL "Intel") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -parallel -fopenmp") else() add_compile_options(-ffast-math) @@ -304,7 +304,7 @@ if(NOT MSVC) set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") elseif(NOT ANDROID) # TODO: See if we can get rid of no-psabi - if (NOT ${CMAKE_C_COMPILER_ID} STREQUAL "Intel" AND NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") + if(NOT ${CMAKE_C_COMPILER_ID} STREQUAL "Intel" AND NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") add_definitions(-Wno-psabi) endif() add_definitions(-D_XOPEN_SOURCE=700) @@ -359,14 +359,16 @@ set(CommonX86 Common/x64Analyzer.cpp Common/x64Analyzer.h Common/x64Emitter.cpp - Common/x64Emitter.h) + Common/x64Emitter.h +) source_group(x86 FILES ${CommonX86}) set(CommonARM Common/ArmCPUDetect.cpp Common/ArmEmitter.h Common/ArmEmitter.cpp - Common/ColorConvNEON.cpp) + Common/ColorConvNEON.cpp +) source_group(ARM FILES ${CommonARM}) set(CommonARM64 @@ -374,25 +376,29 @@ set(CommonARM64 Common/Arm64Emitter.cpp Common/ArmEmitter.h Common/ArmEmitter.cpp - Core/Util/DisArm64.cpp) + Core/Util/DisArm64.cpp +) source_group(ARM64 FILES ${CommonARM64}) set(CommonMIPS Common/MipsCPUDetect.cpp Common/MipsEmitter.cpp - Common/MipsEmitter.h) + Common/MipsEmitter.h +) source_group(MIPS FILES ${CommonMIPS}) if(NOT (X86 OR ARM OR MIPS)) set(CommonFake Common/FakeCPUDetect.cpp - Common/FakeEmitter.h) + Common/FakeEmitter.h + ) source_group(Fake FILES ${CommonFake}) endif() set(CommonWindows Common/stdafx.cpp - Common/stdafx.h) + Common/stdafx.h +) source_group(Windows FILES ${CommonWindows}) set(CommonVulkan ${CommonExtra} @@ -407,7 +413,8 @@ set(CommonVulkan ${CommonExtra} Common/Vulkan/VulkanLoader.cpp Common/Vulkan/VulkanLoader.h Common/Vulkan/VulkanMemory.cpp - Common/Vulkan/VulkanMemory.h) + Common/Vulkan/VulkanMemory.h +) add_library(Common STATIC ${CommonX86} @@ -454,7 +461,8 @@ add_library(Common STATIC Common/ThreadPools.h Common/ThreadSafeList.h Common/Timer.cpp - Common/Timer.h) + Common/Timer.h +) add_subdirectory(ext) @@ -491,56 +499,57 @@ add_library(gason STATIC add_library(rg_etc1 STATIC ext/native/ext/rg_etc1/rg_etc1.cpp - ext/native/ext/rg_etc1/rg_etc1.h) + ext/native/ext/rg_etc1/rg_etc1.h +) include_directories(ext/native/ext/rg_etc1) if(USE_FFMPEG) - if(NOT FFMPEG_DIR) - if(NOT USE_SYSTEM_FFMPEG) - if(ANDROID) - if(ARMV7) - set(PLATFORM_ARCH "android/armv7") - elseif(ARM64) - set(PLATFORM_ARCH "android/arm64") - elseif(X86_64) - set(PLATFORM_ARCH "android/x86_64") - elseif(X86) - set(PLATFORM_ARCH "android/x86") - endif() - elseif(IOS) - set(PLATFORM_ARCH "ios/universal") - elseif(MACOSX) - set(PLATFORM_ARCH "macosx/x86_64") - elseif(LINUX) - if(ARMV7) - set(PLATFORM_ARCH "linux/armv7") - elseif(ARM64) - set(PLATFORM_ARCH "linux/aarch64") - elseif(ARM) - set(PLATFORM_ARCH "linux/arm") - elseif(MIPS) - set(PLATFORM_ARCH "linux/mips32") - elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(PLATFORM_ARCH "linux/x86_64") - elseif(X86) - set(PLATFORM_ARCH "linux/x86") - endif() - elseif(WIN32) - if(X86_64) - set(PLATFORM_ARCH "Windows/x86_64") - elseif(X86) - set(PLATFORM_ARCH "Windows/x86") - endif() - endif() - if(PLATFORM_ARCH) - set(FFMPEG_DIR "ffmpeg/${PLATFORM_ARCH}") - else() - message("Couldn't find an internal FFmpeg build, using system FFmpeg instead") - endif() - endif() - endif() + if(NOT FFMPEG_DIR) + if(NOT USE_SYSTEM_FFMPEG) + if(ANDROID) + if(ARMV7) + set(PLATFORM_ARCH "android/armv7") + elseif(ARM64) + set(PLATFORM_ARCH "android/arm64") + elseif(X86_64) + set(PLATFORM_ARCH "android/x86_64") + elseif(X86) + set(PLATFORM_ARCH "android/x86") + endif() + elseif(IOS) + set(PLATFORM_ARCH "ios/universal") + elseif(MACOSX) + set(PLATFORM_ARCH "macosx/x86_64") + elseif(LINUX) + if(ARMV7) + set(PLATFORM_ARCH "linux/armv7") + elseif(ARM64) + set(PLATFORM_ARCH "linux/aarch64") + elseif(ARM) + set(PLATFORM_ARCH "linux/arm") + elseif(MIPS) + set(PLATFORM_ARCH "linux/mips32") + elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(PLATFORM_ARCH "linux/x86_64") + elseif(X86) + set(PLATFORM_ARCH "linux/x86") + endif() + elseif(WIN32) + if(X86_64) + set(PLATFORM_ARCH "Windows/x86_64") + elseif(X86) + set(PLATFORM_ARCH "Windows/x86") + endif() + endif() + if(PLATFORM_ARCH) + set(FFMPEG_DIR "ffmpeg/${PLATFORM_ARCH}") + else() + message("Couldn't find an internal FFmpeg build, using system FFmpeg instead") + endif() + endif() + endif() - find_package(FFmpeg REQUIRED avcodec avformat avutil swresample swscale) + find_package(FFmpeg REQUIRED avcodec avformat avutil swresample swscale) endif(USE_FFMPEG) find_package(ZLIB) @@ -588,7 +597,7 @@ add_library(cityhash STATIC ) include_directories(ext/cityhash) -if (NOT MSVC) +if(NOT MSVC) # These can be fast even for debug. set_target_properties(udis86 PROPERTIES COMPILE_FLAGS "-O3") set_target_properties(cityhash PROPERTIES COMPILE_FLAGS "-O3") @@ -657,7 +666,8 @@ else() ext/native/ext/libzip/zip_unchange.c ext/native/ext/libzip/zip_unchange_all.c ext/native/ext/libzip/zip_unchange_archive.c - ext/native/ext/libzip/zip_unchange_data.c) + ext/native/ext/libzip/zip_unchange_data.c + ) target_link_libraries(libzip) include_directories(ext/native/ext/libzip) set(LIBZIP_LIBRARY libzip) @@ -668,15 +678,15 @@ find_path(PNG_PNG_INCLUDE_DIR NAMES "libpng17/png.h") find_library(PNG_LIBRARY NAMES png17 libpng17) find_package(PackageHandleStandardArgs) find_package_handle_standard_args(PNG REQUIRED_VARS PNG_LIBRARY PNG_PNG_INCLUDE_DIR) -if (PNG_FOUND) +if(PNG_FOUND) include_directories(${PNG_PNG_INCLUDE_DIR}) else() if(ARM) set(PNG_ARM_INCLUDES - ext/native/ext/libpng17/arm/arm_init.c - ext/native/ext/libpng17/arm/filter_neon.S - ext/native/ext/libpng17/arm/filter_neon_intrinsics.c - ) + ext/native/ext/libpng17/arm/arm_init.c + ext/native/ext/libpng17/arm/filter_neon.S + ext/native/ext/libpng17/arm/filter_neon_intrinsics.c + ) endif() add_library(png17 STATIC ext/native/ext/libpng17/pngconf.h @@ -701,7 +711,8 @@ else() ext/native/ext/libpng17/pngwrite.c ext/native/ext/libpng17/pngwtran.c ext/native/ext/libpng17/pngwutil.c - ${PNG_ARM_INCLUDES} ) + ${PNG_ARM_INCLUDES} + ) set(PNG_LIBRARY png17) include_directories(ext/native/ext) endif() @@ -710,13 +721,14 @@ set(nativeExtra) set(nativeExtraLibs) if(ANDROID) - set(nativeExtra ${nativeExtra} - Common/GL/GLInterface/EGLAndroid.cpp - Common/GL/GLInterface/EGLAndroid.h - Common/GL/GLInterface/EGL.cpp - Common/GL/GLInterface/EGL.h - Common/GL/GLInterface/GLInterface.cpp - Common/GL/GLInterfaceBase.h) + set(nativeExtra ${nativeExtra} + Common/GL/GLInterface/EGLAndroid.cpp + Common/GL/GLInterface/EGLAndroid.h + Common/GL/GLInterface/EGL.cpp + Common/GL/GLInterface/EGL.h + Common/GL/GLInterface/GLInterface.cpp + Common/GL/GLInterfaceBase.h + ) set(nativeExtra ${nativeExtra} ext/native/base/NativeApp.h @@ -731,7 +743,8 @@ if(ANDROID) android/jni/native_audio.cpp android/jni/native_audio.h android/jni/native-audio-so.cpp - android/jni/native-audio-so.h) + android/jni/native-audio-so.h + ) # No target elseif(IOS) set(nativeExtra ${nativeExtra} @@ -750,7 +763,8 @@ elseif(IOS) ios/SubtleVolume.mm ios/iCade/iCadeReaderView.h ios/iCade/iCadeReaderView.m - ios/iCade/iCadeState.h) + ios/iCade/iCadeState.h + ) set(nativeExtraLibs ${nativeExtraLibs} "-framework Foundation -framework MediaPlayer -framework AudioToolbox -framework CoreGraphics -framework QuartzCore -framework UIKit -framework GLKit -framework OpenAL -framework AVFoundation") if(EXISTS "${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks/GameController.framework") set(nativeExtraLibs ${nativeExtraLibs} "-weak_framework GameController") @@ -770,37 +784,38 @@ elseif(IOS) set(TargetBin PPSSPP) elseif(USING_QT_UI) - set(CMAKE_AUTOMOC ON) - find_package(Qt5 COMPONENTS OpenGL Gui Core) - if(NOT SDL2_FOUND) - find_package(Qt5 COMPONENTS Multimedia) - endif(NOT SDL2_FOUND) - list(APPEND NativeAppSource - Qt/QtMain.cpp - Qt/QtMain.h - Qt/QtHost.cpp - Qt/QtHost.h - Qt/mainwindow.cpp - Qt/mainwindow.h - ) - add_definitions(-DUSING_QT_UI) - if(USING_GLES2) - add_definitions(-DQT_OPENGL_ES -DQT_OPENGL_ES_2) - endif() - include_directories(${CMAKE_CURRENT_BINARY_DIR} Qt) + set(CMAKE_AUTOMOC ON) + find_package(Qt5 COMPONENTS OpenGL Gui Core) + if(NOT SDL2_FOUND) + find_package(Qt5 COMPONENTS Multimedia) + endif(NOT SDL2_FOUND) + list(APPEND NativeAppSource + Qt/QtMain.cpp + Qt/QtMain.h + Qt/QtHost.cpp + Qt/QtHost.h + Qt/mainwindow.cpp + Qt/mainwindow.h + ) + add_definitions(-DUSING_QT_UI) + if(USING_GLES2) + add_definitions(-DQT_OPENGL_ES -DQT_OPENGL_ES_2) + endif() + include_directories(${CMAKE_CURRENT_BINARY_DIR} Qt) set(nativeExtraLibs ${nativeExtraLibs} Qt5::OpenGL Qt5::Gui Qt5::Core) set(TargetBin PPSSPPQt) - # Enable SDL if found - if (SDL2_FOUND) - add_definitions(-DSDL) - set(nativeExtra ${nativeExtra} - SDL/SDLJoystick.h - SDL/SDLJoystick.cpp) - set(nativeExtraLibs ${nativeExtraLibs} SDL2::SDL2) - else(SDL2_FOUND) - set(nativeExtraLibs ${nativeExtraLibs} Qt5::Multimedia) - endif() + # Enable SDL if found + if(SDL2_FOUND) + add_definitions(-DSDL) + set(nativeExtra ${nativeExtra} + SDL/SDLJoystick.h + SDL/SDLJoystick.cpp + ) + set(nativeExtraLibs ${nativeExtraLibs} SDL2::SDL2) + else(SDL2_FOUND) + set(nativeExtraLibs ${nativeExtraLibs} Qt5::Multimedia) + endif() elseif(WIN32) # Don't care about SDL. @@ -810,25 +825,26 @@ elseif(WIN32) else() link_directories(dx9sdk/Lib/x86) endif() - set(nativeExtra ${nativeExtra} ext/native/base/logging.cpp) + set(nativeExtra ${nativeExtra} ext/native/base/logging.cpp) elseif(TARGET SDL2::SDL2) - set(TargetBin PPSSPPSDL) - # Require SDL - add_definitions(-DSDL) - set(nativeExtra ${nativeExtra} - SDL/SDLJoystick.h - SDL/SDLJoystick.cpp - SDL/SDLMain.cpp - SDL/SDLGLGraphicsContext.cpp - SDL/SDLVulkanGraphicsContext.cpp) - set(nativeExtraLibs ${nativeExtraLibs} SDL2::SDL2) - if(APPLE) - set(nativeExtra ${nativeExtra} SDL/SDLMain.h SDL/SDLMain.mm) - set(nativeExtraLibs ${nativeExtraLibs} ${COCOA_LIBRARY}) - elseif(USING_EGL) - set(nativeExtraLibs ${nativeExtraLibs} pthread) - endif() - set(TargetBin PPSSPPSDL) + set(TargetBin PPSSPPSDL) + # Require SDL + add_definitions(-DSDL) + set(nativeExtra ${nativeExtra} + SDL/SDLJoystick.h + SDL/SDLJoystick.cpp + SDL/SDLMain.cpp + SDL/SDLGLGraphicsContext.cpp + SDL/SDLVulkanGraphicsContext.cpp + ) + set(nativeExtraLibs ${nativeExtraLibs} SDL2::SDL2) + if(APPLE) + set(nativeExtra ${nativeExtra} SDL/SDLMain.h SDL/SDLMain.mm) + set(nativeExtraLibs ${nativeExtraLibs} ${COCOA_LIBRARY}) + elseif(USING_EGL) + set(nativeExtraLibs ${nativeExtraLibs} pthread) + endif() + set(TargetBin PPSSPPSDL) else() message(FATAL_ERROR "Could not find SDL2. Failing.") endif() @@ -864,12 +880,13 @@ list(APPEND NativeAppSource UI/ProfilerDraw.cpp UI/ui_atlas.cpp UI/TextureUtil.cpp - UI/ComboKeyMappingScreen.cpp) + UI/ComboKeyMappingScreen.cpp +) if(ANDROID) - if (ARM) + if(ARM) set(NativeAppSource ${NativeAppSource} android/jni/ArmEmitterTest.cpp) - elseif (ARM64) + elseif(ARM64) set(NativeAppSource ${NativeAppSource} android/jni/Arm64EmitterTest.cpp) endif() set(nativeExtra ${nativeExtra} ${NativeAppSource}) @@ -881,7 +898,8 @@ set(THIN3D_PLATFORMS ext/native/thin3d/thin3d_gl.cpp ext/native/thin3d/GLQueueRunner.cpp ext/native/thin3d/GLQueueRunner.h ext/native/thin3d/DataFormatGL.cpp - ext/native/thin3d/DataFormatGL.h) + ext/native/thin3d/DataFormatGL.h +) set(THIN3D_PLATFORMS ${THIN3D_PLATFORMS} ext/native/thin3d/thin3d_vulkan.cpp @@ -889,16 +907,18 @@ set(THIN3D_PLATFORMS ${THIN3D_PLATFORMS} ext/native/thin3d/VulkanRenderManager.h ext/native/thin3d/VulkanQueueRunner.cpp ext/native/thin3d/VulkanQueueRunner.h - ext/native/thin3d/DataFormat.h) + ext/native/thin3d/DataFormat.h +) if(WIN32) - set(THIN3D_PLATFORMS ${THIN3D_PLATFORMS} - ext/native/thin3d/thin3d_d3d9.cpp - ext/native/thin3d/thin3d_d3d11.cpp - ext/native/thin3d/d3dx9_loader.cpp - ext/native/thin3d/d3dx9_loader.h - ext/native/thin3d/d3d11_loader.cpp - ext/native/thin3d/d3d11_loader.h) + set(THIN3D_PLATFORMS ${THIN3D_PLATFORMS} + ext/native/thin3d/thin3d_d3d9.cpp + ext/native/thin3d/thin3d_d3d11.cpp + ext/native/thin3d/d3dx9_loader.cpp + ext/native/thin3d/d3dx9_loader.h + ext/native/thin3d/d3d11_loader.cpp + ext/native/thin3d/d3d11_loader.h + ) endif() add_library(native STATIC @@ -1055,21 +1075,22 @@ add_library(native STATIC ext/native/ext/jpge/jpgd.cpp ext/native/ext/jpge/jpgd.h ext/native/ext/jpge/jpge.cpp - ext/native/ext/jpge/jpge.h) + ext/native/ext/jpge/jpge.h +) include_directories(ext/native) -if (LINUX AND NOT ANDROID) - SET(RT_LIB rt) +if(LINUX AND NOT ANDROID) + set(RT_LIB rt) endif() -SET(ATOMIC_LIB) +set(ATOMIC_LIB) if(ANDROID) - SET(ATOMIC_LIB atomic) + set(ATOMIC_LIB atomic) endif() target_link_libraries(native ${LIBZIP_LIBRARY} ${PNG_LIBRARY} ${ZLIB_LIBRARY} rg_etc1 gason udis86 ${RT_LIB} ${nativeExtraLibs} ${ATOMIC_LIB}) if(TARGET Ext::GLEW) - target_link_libraries(native Ext::GLEW) + target_link_libraries(native Ext::GLEW) endif() if(ANDROID) @@ -1091,7 +1112,8 @@ add_library(kirk STATIC ext/libkirk/bn.c ext/libkirk/ec.c ext/libkirk/kirk_engine.c - ext/libkirk/kirk_engine.h) + ext/libkirk/kirk_engine.h +) include_directories(ext/libkirk) add_library(sfmt19937 STATIC @@ -1136,7 +1158,7 @@ set(CoreExtra ${CoreExtra} Core/MIPS/IR/IRPassSimplify.h Core/MIPS/IR/IRRegCache.cpp Core/MIPS/IR/IRRegCache.h - ) +) list(APPEND CoreExtra Core/MIPS/ARM/ArmAsm.cpp @@ -1172,7 +1194,8 @@ list(APPEND CoreExtra Core/MIPS/ARM64/Arm64RegCacheFPU.cpp Core/MIPS/ARM64/Arm64RegCacheFPU.h GPU/Common/VertexDecoderArm64.cpp - Core/Util/DisArm64.cpp) + Core/Util/DisArm64.cpp +) list(APPEND CoreExtra Core/MIPS/x86/Asm.cpp @@ -1200,12 +1223,13 @@ list(APPEND CoreExtra GPU/Common/VertexDecoderFake.cpp ) -if (NOT MOBILE_DEVICE) +if(NOT MOBILE_DEVICE) set(CoreExtra ${CoreExtra} Core/AVIDump.cpp Core/AVIDump.h Core/WaveFile.cpp - Core/WaveFile.h) + Core/WaveFile.h + ) endif() set(GPU_GLES @@ -1235,7 +1259,7 @@ set(GPU_GLES ) set(GPU_VULKAN - GPU/Vulkan/DepalettizeShaderVulkan.cpp + GPU/Vulkan/DepalettizeShaderVulkan.cpp GPU/Vulkan/DepalettizeShaderVulkan.h GPU/Vulkan/DebugVisVulkan.cpp GPU/Vulkan/DebugVisVulkan.h @@ -1265,7 +1289,7 @@ set(GPU_VULKAN ) set(GPU_D3D9 - GPU/Directx9/DepalettizeShaderDX9.cpp + GPU/Directx9/DepalettizeShaderDX9.cpp GPU/Directx9/DepalettizeShaderDX9.h GPU/Directx9/DrawEngineDX9.cpp GPU/Directx9/DrawEngineDX9.h @@ -1289,7 +1313,7 @@ set(GPU_D3D9 ) set(GPU_D3D11 - GPU/D3D11/DepalettizeShaderD3D11.cpp + GPU/D3D11/DepalettizeShaderD3D11.cpp GPU/D3D11/DepalettizeShaderD3D11.h GPU/D3D11/DrawEngineD3D11.cpp GPU/D3D11/DrawEngineD3D11.h @@ -1398,7 +1422,8 @@ set(GPU_SOURCES GPU/Software/SoftGpu.h GPU/Software/TransformUnit.cpp GPU/Software/TransformUnit.h - GPU/ge_constants.h) + GPU/ge_constants.h +) # 'ppsspp_jni' on ANDROID, 'Core' everywhere else # SHARED on ANDROID, STATIC everywhere else @@ -1736,13 +1761,14 @@ add_library(${CoreLibName} ${CoreLinkType} ${CORE_NEON} ${GPU_SOURCES} ext/disarm.cpp - git-version.cpp) + git-version.cpp +) if(ANDROID) - set(CoreExtraLibs ${CoreExtraLibs} android) - if(X86_64) - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-Bsymbolic") - endif() + set(CoreExtraLibs ${CoreExtraLibs} android) + if(X86_64) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-Bsymbolic") + endif() endif() set(CoreExtraLibs ${CoreExtraLibs} armips) @@ -1756,27 +1782,27 @@ set(CoreExtraLibs ${CoreExtraLibs} armips) set(GlslangLibs glslang OGLCompiler OSDependent SPIRV SPVRemapper spirv-cross-glsl) if(WIN32) - set(GlslangLibs ${GlslangLibs} spirv-cross-hlsl) + set(GlslangLibs ${GlslangLibs} spirv-cross-hlsl) endif() target_link_libraries(${CoreLibName} Common native kirk cityhash sfmt19937 xbrz xxhash ${GlslangLibs} ${CoreExtraLibs} ${OPENGL_LIBRARIES} ${X11_LIBRARIES} ${CMAKE_DL_LIBS}) if(FFmpeg_FOUND) - target_compile_definitions(${CoreLibName} PRIVATE USE_FFMPEG=1) - target_link_libraries(${CoreLibName} - FFmpeg::avcodec - FFmpeg::avformat - FFmpeg::avutil - FFmpeg::swresample - FFmpeg::swscale - ${ZLIB_LIBRARY} - ) + target_compile_definitions(${CoreLibName} PRIVATE USE_FFMPEG=1) + target_link_libraries(${CoreLibName} + FFmpeg::avcodec + FFmpeg::avformat + FFmpeg::avutil + FFmpeg::swresample + FFmpeg::swscale + ${ZLIB_LIBRARY} + ) endif() # Discord integration if(NOT IOS) -target_link_libraries(${CoreLibName} discord-rpc) + target_link_libraries(${CoreLibName} discord-rpc) endif() setup_target_project(${CoreLibName} Core) @@ -1888,7 +1914,8 @@ set(WindowsFiles Windows/ppsspp.rc Windows/resource.h Windows/stdafx.cpp - Windows/stdafx.h) + Windows/stdafx.h +) list(APPEND LinkCommon ${CoreLibName} ${CMAKE_THREAD_LIBS_INIT}) @@ -1910,7 +1937,8 @@ set(NativeAssets assets/ppge_atlas.zim assets/rargray.png assets/unknown.png - assets/zip.png) + assets/zip.png +) if(HEADLESS) @@ -1921,9 +1949,9 @@ if(HEADLESS) headless/Compare.cpp headless/Compare.h headless/SDLHeadlessHost.cpp - headless/SDLHeadlessHost.h) - target_link_libraries(PPSSPPHeadless - ${COCOA_LIBRARY} ${LinkCommon}) + headless/SDLHeadlessHost.h + ) + target_link_libraries(PPSSPPHeadless ${COCOA_LIBRARY} ${LinkCommon}) setup_target_project(PPSSPPHeadless headless) endif() @@ -1938,8 +1966,7 @@ if(UNITTEST) Core/MIPS/ARM/ArmRegCache.cpp Core/MIPS/ARM/ArmRegCacheFPU.cpp ) - target_link_libraries(unitTest - ${COCOA_LIBRARY} ${LinkCommon} Common) + target_link_libraries(unitTest ${COCOA_LIBRARY} ${LinkCommon} Common) setup_target_project(unitTest unittest) endif() @@ -1947,12 +1974,12 @@ if(LIBRETRO) add_subdirectory(libretro) endif() -if (TargetBin) - if (IOS OR APPLE) - if (APPLE AND NOT IOS) - set(ICON_PATH_ABS ${CMAKE_CURRENT_SOURCE_DIR}/icons/ppsspp.icns) - set( MACOSX_BUNDLE_ICON_FILE ppsspp.icns ) - set_source_files_properties(${ICON_PATH_ABS} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") +if(TargetBin) + if(IOS OR APPLE) + if(APPLE AND NOT IOS) + set(ICON_PATH_ABS ${CMAKE_CURRENT_SOURCE_DIR}/icons/ppsspp.icns) + set(MACOSX_BUNDLE_ICON_FILE ppsspp.icns) + set_source_files_properties(${ICON_PATH_ABS} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") endif() # TODO: there must a native way to copy these. @@ -1962,17 +1989,17 @@ if (TargetBin) file(GLOB_RECURSE LANG_FILES assets/lang/*) file(GLOB_RECURSE SHADER_FILES assets/shaders/*) - if (APPLE AND NOT IOS) - set_source_files_properties(${NativeAssets} PROPERTIES MACOSX_PACKAGE_LOCATION "MacOS/assets") - set_source_files_properties(${FLASH0_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION "MacOS/assets/flash0/font") - set_source_files_properties(${LANG_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION "MacOS/assets/lang") - set_source_files_properties(${SHADER_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION "MacOS/assets/shaders") + if(APPLE AND NOT IOS) + set_source_files_properties(${NativeAssets} PROPERTIES MACOSX_PACKAGE_LOCATION "MacOS/assets") + set_source_files_properties(${FLASH0_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION "MacOS/assets/flash0/font") + set_source_files_properties(${LANG_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION "MacOS/assets/lang") + set_source_files_properties(${SHADER_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION "MacOS/assets/shaders") endif() - if (IOS) - add_executable(${TargetBin} MACOSX_BUNDLE ${ICON_PATH_ABS} ${NativeAssets} ${SHADER_FILES} ${FLASH0_FILES} ${LANG_FILES} ${NativeAppSource} "ios/Launch Screen.storyboard") + if(IOS) + add_executable(${TargetBin} MACOSX_BUNDLE ${ICON_PATH_ABS} ${NativeAssets} ${SHADER_FILES} ${FLASH0_FILES} ${LANG_FILES} ${NativeAppSource} "ios/Launch Screen.storyboard") else() - add_executable(${TargetBin} MACOSX_BUNDLE ${ICON_PATH_ABS} ${NativeAssets} ${SHADER_FILES} ${FLASH0_FILES} ${LANG_FILES} ${NativeAppSource}) + add_executable(${TargetBin} MACOSX_BUNDLE ${ICON_PATH_ABS} ${NativeAssets} ${SHADER_FILES} ${FLASH0_FILES} ${LANG_FILES} ${NativeAppSource}) endif() elseif(WIN32) add_executable(${TargetBin} WIN32 ${NativeAppSource}) @@ -1990,8 +2017,8 @@ endif() # installs if(NOT ANDROID) -file(INSTALL ${NativeAssets} DESTINATION assets) -file(INSTALL assets/flash0 DESTINATION assets) + file(INSTALL ${NativeAssets} DESTINATION assets) + file(INSTALL assets/flash0 DESTINATION assets) endif() # packaging and code signing if(IOS) @@ -2002,7 +2029,7 @@ if(IOS) file(INSTALL ${IOSAssets} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/assets) file(GLOB IOSAssets ios/assets/Default-568h@*.png) file(INSTALL ${IOSAssets} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) - if (IOS_DEBUG) + if(IOS_DEBUG) file(INSTALL pspautotests DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/assets) endif() set(RSRC_XIB_FILES assets/Icon@2x.png) @@ -2010,11 +2037,11 @@ if(IOS) set_source_files_properties(${RSRC_XIB_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources ) - if(CMAKE_GENERATOR STREQUAL "Xcode") - set(APP_DIR_NAME "$(TARGET_BUILD_DIR)/$(FULL_PRODUCT_NAME)") - else() - set(APP_DIR_NAME "$") - endif() + if(CMAKE_GENERATOR STREQUAL "Xcode") + set(APP_DIR_NAME "$(TARGET_BUILD_DIR)/$(FULL_PRODUCT_NAME)") + else() + set(APP_DIR_NAME "$") + endif() add_custom_command(TARGET PPSSPP POST_BUILD COMMAND mkdir -p \"${APP_DIR_NAME}\" COMMAND tar -c -C ${CMAKE_CURRENT_BINARY_DIR} --exclude .DS_Store --exclude .git assets *.png | tar -x -C \"${APP_DIR_NAME}\" @@ -2025,8 +2052,8 @@ if(IOS) RESOURCE "ios/Launch Screen.storyboard" XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET} XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "iPhone/iPad" - XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES - XCODE_ATTRIBUTE_ENABLE_BITCODE NO - XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-" + XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES + XCODE_ATTRIBUTE_ENABLE_BITCODE NO + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-" ) endif() From 9ee6203545a04daa0f49f55aa580883a75aad065 Mon Sep 17 00:00:00 2001 From: Aaron Kling Date: Mon, 29 Oct 2018 21:38:21 -0500 Subject: [PATCH 076/347] Squash of a few libretro makeile fixes Fix https://github.com/libretro/ppsspp/issues/5#issuecomment-383238875 Add missing file Bump this, in case you are building without .git/ folder Libretro: remove override directive. (#4) --- libretro/Makefile | 4 ++-- libretro/Makefile.common | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/libretro/Makefile b/libretro/Makefile index 4fdb2ea929..8970ddc036 100644 --- a/libretro/Makefile +++ b/libretro/Makefile @@ -15,9 +15,9 @@ ifeq (,$(TARGET_ARCH)) endif ifneq (,$(findstring 64,$(TARGET_ARCH))) - override TARGET_ARCH := x86_64 + TARGET_ARCH := x86_64 else ifneq (,$(findstring 86,$(TARGET_ARCH))) - override TARGET_ARCH := x86 + TARGET_ARCH := x86 endif ifeq ($(platform),) diff --git a/libretro/Makefile.common b/libretro/Makefile.common index 3bc9ab9726..f127fab167 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -216,6 +216,7 @@ SOURCES_CXX += \ $(EXTDIR)/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp \ $(EXTDIR)/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp \ $(EXTDIR)/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp \ + $(EXTDIR)/glslang/glslang/MachineIndependent/attribute.cpp \ $(EXTDIR)/glslang/glslang/MachineIndependent/Constant.cpp \ $(EXTDIR)/glslang/glslang/MachineIndependent/InfoSink.cpp \ $(EXTDIR)/glslang/glslang/MachineIndependent/Initialize.cpp \ @@ -409,6 +410,7 @@ SOURCES_CXX += $(NATIVEDIR)/math/dataconv.cpp \ $(COREDIR)/HLE/sceSsl.cpp \ $(COREDIR)/HLE/sceUmd.cpp \ $(COREDIR)/HLE/sceUsb.cpp \ + $(COREDIR)/HLE/sceUsbAcc.cpp \ $(COREDIR)/HLE/sceUsbCam.cpp \ $(COREDIR)/HLE/sceUtility.cpp \ $(COREDIR)/HLE/sceVaudio.cpp \ @@ -454,6 +456,7 @@ SOURCES_CXX += $(NATIVEDIR)/math/dataconv.cpp \ $(COREDIR)/MemMap.cpp \ $(COREDIR)/MemMapFunctions.cpp \ $(COREDIR)/PSPLoaders.cpp \ + $(COREDIR)/Replay.cpp \ $(COREDIR)/Reporting.cpp \ $(COREDIR)/SaveState.cpp \ $(COREDIR)/Screenshot.cpp \ @@ -675,7 +678,7 @@ SOURCES_C += \ endif GIT_VERSION_SRC = $(CORE_DIR)/git-version.cpp -GIT_VERSION := $(shell git describe --always || echo v1.4.2-git) +GIT_VERSION := $(shell git describe --always || echo v1.7.0-git) GIT_VERSION_NO_UPDATE = $(findstring 1,$(shell grep -s PPSSPP_GIT_VERSION_NO_UPDATE $(GIT_VERSION_SRC))) ifneq (,$(findstring $(GIT_VERSION),$(shell grep -s char $(GIT_VERSION_SRC)))) GIT_VERSION_NO_UPDATE = 1 From b296bc1802d8ea87684dc4bb5e0596947f34698c Mon Sep 17 00:00:00 2001 From: hunterk Date: Sat, 21 Apr 2018 14:58:10 -0500 Subject: [PATCH 077/347] add texture filtering core option --- libretro/libretro.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index cca5331e86..b9ab47c66a 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -178,6 +178,7 @@ static RetroOption ppsspp_fast_memory("ppsspp_fast_memory", "Fast Memory ( static RetroOption ppsspp_block_transfer_gpu("ppsspp_block_transfer_gpu", "Block Transfer GPU", true); static RetroOption ppsspp_texture_scaling_level("ppsspp_texture_scaling_level", "Texture Scaling Level", { { "1", 1 }, { "2", 2 }, { "3", 3 }, { "4", 4 }, { "5", 5 }, { "0", 0 } }); static RetroOption ppsspp_texture_scaling_type("ppsspp_texture_scaling_type", "Texture Scaling Type", { { "xbrz", TextureScalerCommon::XBRZ }, { "hybrid", TextureScalerCommon::HYBRID }, { "bicubic", TextureScalerCommon::BICUBIC }, { "hybrid_bicubic", TextureScalerCommon::HYBRID_BICUBIC } }); +static RetroOption ppsspp_texture_filtering("ppsspp_texture_filtering", "Texture Filtering", { { "auto", 1 }, { "nearest", 2 }, { "linear", 3 }, { "linear(FMV)", 4 } }); static RetroOption ppsspp_texture_anisotropic_filtering("ppsspp_texture_anisotropic_filtering", "Anisotropic Filtering", { "off", "1x", "2x", "4x", "8x", "16x" }); static RetroOption ppsspp_texture_deposterize("ppsspp_texture_deposterize", "Texture Deposterize", false); static RetroOption ppsspp_gpu_hardware_transform("ppsspp_gpu_hardware_transform", "GPU Hardware T&L", true); @@ -204,6 +205,7 @@ void retro_set_environment(retro_environment_t cb) { vars.push_back(ppsspp_block_transfer_gpu.GetOptions()); vars.push_back(ppsspp_texture_scaling_level.GetOptions()); vars.push_back(ppsspp_texture_scaling_type.GetOptions()); + vars.push_back(ppsspp_texture_filtering.GetOptions()); vars.push_back(ppsspp_texture_anisotropic_filtering.GetOptions()); vars.push_back(ppsspp_texture_deposterize.GetOptions()); vars.push_back(ppsspp_gpu_hardware_transform.GetOptions()); @@ -268,6 +270,7 @@ static void check_variables(CoreParameter &coreParam) { ppsspp_true_color.Update(&g_Config.bTrueColor); ppsspp_auto_frameskip.Update(&g_Config.bAutoFrameSkip); ppsspp_block_transfer_gpu.Update(&g_Config.bBlockTransferGPU); + ppsspp_texture_filtering.Update(&g_Config.iTexFiltering); ppsspp_texture_anisotropic_filtering.Update(&g_Config.iAnisotropyLevel); ppsspp_texture_deposterize.Update(&g_Config.bTexDeposterize); ppsspp_separate_io_thread.Update(&g_Config.bSeparateIOThread); From 157b4aa7bf7af5631b7511b781c89bed617b1991 Mon Sep 17 00:00:00 2001 From: Aaron Kling Date: Sat, 27 Oct 2018 20:52:54 -0500 Subject: [PATCH 078/347] Add texture replacement option This allows use of texture packs placed in $savedir/PSP/TEXTURES --- libretro/libretro.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index b9ab47c66a..3c656fe55b 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -181,6 +181,7 @@ static RetroOption ppsspp_texture_scaling_type("ppsspp_texture_scaling_type static RetroOption ppsspp_texture_filtering("ppsspp_texture_filtering", "Texture Filtering", { { "auto", 1 }, { "nearest", 2 }, { "linear", 3 }, { "linear(FMV)", 4 } }); static RetroOption ppsspp_texture_anisotropic_filtering("ppsspp_texture_anisotropic_filtering", "Anisotropic Filtering", { "off", "1x", "2x", "4x", "8x", "16x" }); static RetroOption ppsspp_texture_deposterize("ppsspp_texture_deposterize", "Texture Deposterize", false); +static RetroOption ppsspp_texture_replacement("ppsspp_texture_replacement", "Texture Replacement", false); static RetroOption ppsspp_gpu_hardware_transform("ppsspp_gpu_hardware_transform", "GPU Hardware T&L", true); static RetroOption ppsspp_vertex_cache("ppsspp_vertex_cache", "Vertex Cache (Speedhack)", true); static RetroOption ppsspp_separate_io_thread("ppsspp_separate_io_thread", "IO Threading", false); @@ -208,6 +209,7 @@ void retro_set_environment(retro_environment_t cb) { vars.push_back(ppsspp_texture_filtering.GetOptions()); vars.push_back(ppsspp_texture_anisotropic_filtering.GetOptions()); vars.push_back(ppsspp_texture_deposterize.GetOptions()); + vars.push_back(ppsspp_texture_replacement.GetOptions()); vars.push_back(ppsspp_gpu_hardware_transform.GetOptions()); vars.push_back(ppsspp_vertex_cache.GetOptions()); vars.push_back(ppsspp_separate_io_thread.GetOptions()); @@ -273,6 +275,7 @@ static void check_variables(CoreParameter &coreParam) { ppsspp_texture_filtering.Update(&g_Config.iTexFiltering); ppsspp_texture_anisotropic_filtering.Update(&g_Config.iAnisotropyLevel); ppsspp_texture_deposterize.Update(&g_Config.bTexDeposterize); + ppsspp_texture_replacement.Update(&g_Config.bReplaceTextures); ppsspp_separate_io_thread.Update(&g_Config.bSeparateIOThread); ppsspp_unsafe_func_replacements.Update(&g_Config.bFuncReplacements); ppsspp_sound_speedhack.Update(&g_Config.bSoundSpeedHack); From d66f1b03721312ec2f5d2eaaf0b24c5d50be9b54 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Mon, 29 Oct 2018 21:54:42 -0500 Subject: [PATCH 079/347] Libretro d3d11 build fix --- libretro/LibretroD3D11Context.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libretro/LibretroD3D11Context.cpp b/libretro/LibretroD3D11Context.cpp index 7e6a939d7c..cd46e66858 100644 --- a/libretro/LibretroD3D11Context.cpp +++ b/libretro/LibretroD3D11Context.cpp @@ -1,4 +1,5 @@ +#include "Core/ConfigValues.h" #include "libretro/LibretroD3D11Context.h" #include "thin3d/d3d11_loader.h" #include @@ -17,6 +18,8 @@ bool LibretroD3D11Context::Init() { } void LibretroD3D11Context::CreateDrawContext() { + std::vector adapterNames; + if (!Libretro::environ_cb(RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE, (void **)&d3d11_) || !d3d11_) { ERROR_LOG(G3D, "Failed to get HW rendering interface!\n"); return; @@ -35,7 +38,7 @@ void LibretroD3D11Context::CreateDrawContext() { ID3D11DeviceContext1 *context1 = nullptr; d3d11_->context->QueryInterface(__uuidof(ID3D11DeviceContext1), (void **)&context1); - draw_ = Draw::T3DCreateD3D11Context(d3d11_->device, d3d11_->context, device1, context1, d3d11_->featureLevel, NULL); + draw_ = Draw::T3DCreateD3D11Context(d3d11_->device, d3d11_->context, device1, context1, d3d11_->featureLevel, NULL, adapterNames); } void LibretroD3D11Context::DestroyDrawContext() { From d9198ff039302353a6a56dbec4f34534a191da2c Mon Sep 17 00:00:00 2001 From: Aaron Kling Date: Tue, 30 Oct 2018 17:57:54 -0500 Subject: [PATCH 080/347] Fix libretro Windows build 1103acd added a reference to std::vector without adding the include --- Common/OSVersion.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Common/OSVersion.cpp b/Common/OSVersion.cpp index eb65b3fabf..1103fb8ad6 100644 --- a/Common/OSVersion.cpp +++ b/Common/OSVersion.cpp @@ -7,6 +7,7 @@ #endif #include +#include #include "OSVersion.h" #include "Common/CommonWindows.h" From c19d3fe06a1f3cab3760fac1972f6c4164f9b622 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 3 Nov 2018 01:33:41 +0000 Subject: [PATCH 081/347] MRFIXIT2001: This patch adds a second frameskip setting, one for setting the # of frames to skip, one for setting the % of frames to skip based off fps --- Core/Config.cpp | 1 + Core/Config.h | 1 + Core/HLE/sceDisplay.cpp | 19 ++++++++++++++++--- Qt/mainwindow.cpp | 2 ++ Qt/mainwindow.h | 1 + UI/GameSettingsScreen.cpp | 2 ++ Windows/MainWindow.h | 3 +++ Windows/MainWindowMenu.cpp | 36 ++++++++++++++++++++++++++++++++++++ Windows/ppsspp.rc | 5 +++++ Windows/resource.h | 2 ++ libretro/libretro.cpp | 3 +++ 11 files changed, 72 insertions(+), 3 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 8ff95fcde5..22b88a7604 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -621,6 +621,7 @@ static ConfigSetting graphicsSettings[] = { ReportedConfigSetting("AndroidHwScale", &g_Config.iAndroidHwScale, &DefaultAndroidHwScale), ReportedConfigSetting("HighQualityDepth", &g_Config.bHighQualityDepth, true, true, true), ReportedConfigSetting("FrameSkip", &g_Config.iFrameSkip, 0, true, true), + ReportedConfigSetting("FrameSkipType", &g_Config.iFrameSkipType, 0, true, true), ReportedConfigSetting("AutoFrameSkip", &g_Config.bAutoFrameSkip, false, true, true), ConfigSetting("FrameRate", &g_Config.iFpsLimit1, 0, true, true), ConfigSetting("FrameRate2", &g_Config.iFpsLimit2, -1, true, true), diff --git a/Core/Config.h b/Core/Config.h index 715800c79a..311516d769 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -143,6 +143,7 @@ public: bool bSustainedPerformanceMode; // Android: Slows clocks down to avoid overheating/speed fluctuations. bool bVSync; int iFrameSkip; + int iFrameSkipType; bool bAutoFrameSkip; bool bFrameSkipUnthrottle; diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 9d8bfe0990..da3bf70f86 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -503,6 +503,17 @@ static void DoFrameDropLogging(float scaledTimestep) { } } +static int CalculateFrameSkip() { + // Used to calculate the FPS to skip if the user sets the type to percent of fps + int frameSkipNum; + if (g_Config.iFrameSkipType == 1) { + frameSkipNum = ceil( flips * (static_cast(g_Config.iFrameSkip) / 100.00) ); + } else { + frameSkipNum = g_Config.iFrameSkip; + } + return frameSkipNum; +} + // Let's collect all the throttling and frameskipping logic here. static void DoFrameTiming(bool &throttle, bool &skipFrame, float timestep) { PROFILE_THIS_SCOPE("timing"); @@ -553,15 +564,16 @@ static void DoFrameTiming(bool &throttle, bool &skipFrame, float timestep) { // Auto-frameskip automatically if speed limit is set differently than the default. bool useAutoFrameskip = g_Config.bAutoFrameSkip && g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; bool forceFrameskip = (fpsLimiter == FPSLimit::CUSTOM1 && g_Config.iFpsLimit1 > 60) || (fpsLimiter == FPSLimit::CUSTOM2 && g_Config.iFpsLimit2 > 60); + int frameSkipNum = CalculateFrameSkip(); if (g_Config.bAutoFrameSkip || forceFrameskip) { // autoframeskip // Argh, we are falling behind! Let's skip a frame and see if we catch up. if (curFrameTime > nextFrameTime && doFrameSkip) { skipFrame = true; } - } else if (g_Config.iFrameSkip >= 1) { + } else if (frameSkipNum >= 1) { // fixed frameskip - if (numSkippedFrames >= g_Config.iFrameSkip) + if (numSkippedFrames >= frameSkipNum) skipFrame = false; else skipFrame = true; @@ -734,9 +746,10 @@ void __DisplayFlip(int cyclesLate) { DoFrameTiming(throttle, skipFrame, (float)numVBlanksSinceFlip * timePerVblank); int maxFrameskip = 8; + int frameSkipNum = CalculateFrameSkip(); if (throttle) { // 4 here means 1 drawn, 4 skipped - so 12 fps minimum. - maxFrameskip = g_Config.iFrameSkip; + maxFrameskip = frameSkipNum; } if (numSkippedFrames >= maxFrameskip || GPURecord::IsActivePending()) { skipFrame = false; diff --git a/Qt/mainwindow.cpp b/Qt/mainwindow.cpp index 123f6605c8..f2d7723d79 100644 --- a/Qt/mainwindow.cpp +++ b/Qt/mainwindow.cpp @@ -511,6 +511,8 @@ void MainWindow::createMenus() ->addEventChecked(&g_Config.bVertexCache); videoMenu->add(new MenuAction(this, SLOT(frameskipAct()), QT_TR_NOOP("&Frameskip"))) ->addEventChecked(&g_Config.iFrameSkip); + videoMenu->add(new MenuAction(this, SLOT(frameskipTypeAct()), QT_TR_NOOP("&FrameSkipType"))) + ->addEventChecked(&g_Config.iFrameSkipType); optionsMenu->add(new MenuAction(this, SLOT(audioAct()), QT_TR_NOOP("&Audio"))) ->addEventChecked(&g_Config.bEnableSound); optionsMenu->addSeparator(); diff --git a/Qt/mainwindow.h b/Qt/mainwindow.h index 90ab051b91..2745d73183 100644 --- a/Qt/mainwindow.h +++ b/Qt/mainwindow.h @@ -114,6 +114,7 @@ private slots: void transformAct() { g_Config.bHardwareTransform = !g_Config.bHardwareTransform; } void vertexCacheAct() { g_Config.bVertexCache = !g_Config.bVertexCache; } void frameskipAct() { g_Config.iFrameSkip = !g_Config.iFrameSkip; } + void frameskipTypeAct() { g_Config.iFrameSkipType = !g_Config.iFrameSkipType; } // Sound void audioAct() { g_Config.bEnableSound = !g_Config.bEnableSound; } diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 43bb8dd58a..a1db27bd3b 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -275,6 +275,8 @@ void GameSettingsScreen::CreateViews() { graphicsSettings->Add(new ItemHeader(gr->T("Frame Rate Control"))); static const char *frameSkip[] = {"Off", "1", "2", "3", "4", "5", "6", "7", "8"}; graphicsSettings->Add(new PopupMultiChoice(&g_Config.iFrameSkip, gr->T("Frame Skipping"), frameSkip, 0, ARRAY_SIZE(frameSkip), gr->GetName(), screenManager())); + static const char *frameSkipType[] = {"Number of Frames", "Percent of FPS"}; + graphicsSettings->Add(new PopupMultiChoice(&g_Config.iFrameSkipType, gr->T("Frame Skipping Type"), frameSkipType, 0, ARRAY_SIZE(frameSkipType), gr->GetName(), screenManager())); frameSkipAuto_ = graphicsSettings->Add(new CheckBox(&g_Config.bAutoFrameSkip, gr->T("Auto FrameSkip"))); frameSkipAuto_->OnClick.Handle(this, &GameSettingsScreen::OnAutoFrameskip); graphicsSettings->Add(new CheckBox(&cap60FPS_, gr->T("Force max 60 FPS (helps GoW)"))); diff --git a/Windows/MainWindow.h b/Windows/MainWindow.h index bf879b1bc1..835d22cb2e 100644 --- a/Windows/MainWindow.h +++ b/Windows/MainWindow.h @@ -35,6 +35,9 @@ namespace MainWindow FRAMESKIP_8 = 8, FRAMESKIP_MAX = FRAMESKIP_8, + FRAMESKIPTYPE_0 = 0, + FRAMESKIPTYPE_1 = 1, + RESOLUTION_AUTO = 0, RESOLUTION_NATIVE = 1, RESOLUTION_2X = 2, diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index 470599f71f..ba25f60bed 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -337,6 +337,7 @@ namespace MainWindow { TranslateSubMenu(menu, "Frame Skipping", MENU_OPTIONS, SUBMENU_FRAME_SKIPPING, L"\tF7"); TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIP_AUTO); TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIP_0); + TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIPTYPE_0); // Skip frameskipping 1-8.. TranslateSubMenu(menu, "Texture Filtering", MENU_OPTIONS, SUBMENU_TEXTURE_FILTERING); TranslateMenuItem(menu, ID_OPTIONS_TEXTUREFILTERING_AUTO); @@ -542,6 +543,26 @@ namespace MainWindow { osm.Show(messageStream.str()); } + static void setFrameSkippingType(int fskipType = -1) { + if (fskipType >= 0 && fskipType <= 1) { + g_Config.iFrameSkipType = fskipType; + } else { + g_Config.iFrameSkipType = 0; + } + + I18NCategory *gr = GetI18NCategory("Graphics"); + + std::ostringstream messageStream; + messageStream << gr->T("Frame Skipping Type") << ":" << " "; + + if (g_Config.iFrameSkipType == 0) + messageStream << gr->T("Number of Frames"); + else + messageStream << gr->T("Percent of FPS"); + + osm.Show(messageStream.str()); + } + static void enableCheats(bool cheats) { g_Config.bEnableCheats = cheats; } @@ -825,8 +846,12 @@ namespace MainWindow { case ID_OPTIONS_FRAMESKIP_7: setFrameSkipping(FRAMESKIP_7); break; case ID_OPTIONS_FRAMESKIP_8: setFrameSkipping(FRAMESKIP_MAX); break; + case ID_OPTIONS_FRAMESKIPTYPE_0: setFrameSkippingType(FRAMESKIPTYPE_0); break; + case ID_OPTIONS_FRAMESKIPTYPE_1: setFrameSkippingType(FRAMESKIPTYPE_1); break; + case ID_OPTIONS_FRAMESKIPDUMMY: setFrameSkipping(); + setFrameSkippingType(); break; case ID_FILE_EXIT: @@ -1076,6 +1101,7 @@ namespace MainWindow { CHECKITEM(ID_OPTIONS_SHOWFPS, g_Config.iShowFPSCounter); CHECKITEM(ID_OPTIONS_FRAMESKIP_AUTO, g_Config.bAutoFrameSkip); CHECKITEM(ID_OPTIONS_FRAMESKIP, g_Config.iFrameSkip != FRAMESKIP_OFF); + CHECKITEM(ID_OPTIONS_FRAMESKIPTYPE, g_Config.iFrameSkipType); CHECKITEM(ID_OPTIONS_VSYNC, g_Config.bVSync); CHECKITEM(ID_OPTIONS_TOPMOST, g_Config.bTopMost); CHECKITEM(ID_OPTIONS_PAUSE_FOCUS, g_Config.bPauseOnLostFocus); @@ -1248,6 +1274,12 @@ namespace MainWindow { ID_OPTIONS_FRAMESKIP_7, ID_OPTIONS_FRAMESKIP_8, }; + + static const int frameskippingType[] = { + ID_OPTIONS_FRAMESKIPTYPE_0, + ID_OPTIONS_FRAMESKIPTYPE_1, + }; + if (g_Config.iFrameSkip < FRAMESKIP_OFF) g_Config.iFrameSkip = FRAMESKIP_OFF; @@ -1258,6 +1290,10 @@ namespace MainWindow { CheckMenuItem(menu, frameskipping[i], MF_BYCOMMAND | ((i == g_Config.iFrameSkip) ? MF_CHECKED : MF_UNCHECKED)); } + for (int i = 0; i < ARRAY_SIZE(frameskippingType); i++) { + CheckMenuItem(menu, frameskippingType[i], MF_BYCOMMAND | ((i == g_Config.iFrameSkipType) ? MF_CHECKED : MF_UNCHECKED)); + } + static const int savestateSlot[] = { ID_FILE_SAVESTATE_SLOT_1, ID_FILE_SAVESTATE_SLOT_2, diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index 6fdcdaf9e9..64ebceda3f 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -589,6 +589,11 @@ BEGIN MENUITEM "&7", ID_OPTIONS_FRAMESKIP_7 MENUITEM "&8", ID_OPTIONS_FRAMESKIP_8 END + POPUP "Frame Skipping Type" + BEGIN + MENUITEM "Skip Number of Frames", ID_OPTIONS_FRAMESKIPTYPE_0 + MENUITEM "Skip Percent of FPS", ID_OPTIONS_FRAMESKIPTYPE_1 + END POPUP "Texture Filtering" BEGIN MENUITEM "Auto", ID_OPTIONS_TEXTUREFILTERING_AUTO diff --git a/Windows/resource.h b/Windows/resource.h index 0c78739113..2dddf88dd4 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -343,6 +343,8 @@ #define ID_EMULATION_PAUSE 40177 #define ID_HELP_DISCORD 40178 #define IDC_GEDBG_STEPCURVE 40179 +#define ID_OPTIONS_FRAMESKIPTYPE_0 40180 +#define ID_OPTIONS_FRAMESKIPTYPE_1 40181 // Dummy option to let the buffered rendering hotkey cycle through all the options. #define ID_OPTIONS_BUFFEREDRENDERINGDUMMY 40500 diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index 3c656fe55b..22615e27f4 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -170,6 +170,7 @@ static RetroOption ppsspp_rendering_mode("ppsspp_rendering_mode", "Renderin static RetroOption ppsspp_true_color("ppsspp_true_color", "True Color Depth", true); static RetroOption ppsspp_auto_frameskip("ppsspp_auto_frameskip", "Auto Frameskip", false); static RetroOption ppsspp_frameskip("ppsspp_frameskip", "Frameskip", 0, 10); +static RetroOption ppsspp_frameskiptype("ppsspp_frameskiptype", "Frameskip Type", 0, 10); static RetroOption ppsspp_force_max_fps("ppsspp_force_max_fps", "Force Max FPS", { { "disabled", 0 }, { "enabled", 60 } }); static RetroOption ppsspp_audio_latency("ppsspp_audio_latency", "Audio latency", { "low", "medium", "high" }); static RetroOption ppsspp_internal_resolution("ppsspp_internal_resolution", "Internal Resolution", 1, { "480x272", "960x544", "1440x816", "1920x1088", "2400x1360", "2880x1632", "3360x1904", "3840x2176", "4320x2448", "4800x2720" }); @@ -198,6 +199,7 @@ void retro_set_environment(retro_environment_t cb) { vars.push_back(ppsspp_true_color.GetOptions()); vars.push_back(ppsspp_auto_frameskip.GetOptions()); vars.push_back(ppsspp_frameskip.GetOptions()); + vars.push_back(ppsspp_frameskiptype.GetOptions()); vars.push_back(ppsspp_force_max_fps.GetOptions()); vars.push_back(ppsspp_audio_latency.GetOptions()); vars.push_back(ppsspp_internal_resolution.GetOptions()); @@ -268,6 +270,7 @@ static void check_variables(CoreParameter &coreParam) { ppsspp_vertex_cache.Update(&g_Config.bVertexCache); ppsspp_gpu_hardware_transform.Update(&g_Config.bHardwareTransform); ppsspp_frameskip.Update(&g_Config.iFrameSkip); + ppsspp_frameskiptype.Update(&g_Config.iFrameSkipType); ppsspp_audio_latency.Update(&g_Config.iAudioLatency); ppsspp_true_color.Update(&g_Config.bTrueColor); ppsspp_auto_frameskip.Update(&g_Config.bAutoFrameSkip); From 9929eedbc972b27088064e8b87c4e57d811fed31 Mon Sep 17 00:00:00 2001 From: LunaMoo Date: Sat, 3 Nov 2018 08:13:22 +0100 Subject: [PATCH 082/347] Fix database comments ending the cheat import. --- UI/CwCheatScreen.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/UI/CwCheatScreen.cpp b/UI/CwCheatScreen.cpp index da39f104e6..3aabf8571e 100644 --- a/UI/CwCheatScreen.cpp +++ b/UI/CwCheatScreen.cpp @@ -223,13 +223,13 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) { do { newList.push_back(line); getline(fs, line); - } while (line[0] == '_' && line[1] == 'L'); + } while ((line[0] == '_' && line[1] == 'L') || line[0] == '/' || line[0] == '#'); finished = true; } else { continue; } loop:; - } while (fs.good() && line[0] == '_' && line[1] != 'S'); + } while (fs.good() && (line[0] == '_' && line[1] != 'S') || line[0] == '/' || line[0] == '#'); finished = true; } if (finished == true) @@ -243,7 +243,7 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) { File::OpenCPPFile(fs, activeCheatFile, std::ios::out | std::ios::app); auto it = title.begin(); - if (title2[0] == '_' && title2[1] != 'S' && it != title.end() && (++it) != title.end()) { + if ((title2[0] == '_' && title2[1] != 'S') || title2[0] == '/' || title2[0] == '#' && it != title.end() && (++it) != title.end()) { fs << title[0] << "\n" << title[1]; } From 6bc9a96e38d784fcf720ad2944d34ec18e4681fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 3 Nov 2018 17:35:21 +0100 Subject: [PATCH 083/347] Comply with new Google Play policy that is not happy with "Support PPSSPP" leading to the PPSSPP Gold app in Play --- UI/MainScreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index 1a5d31cee7..6956f95b50 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -922,7 +922,7 @@ void MainScreen::CreateViews() { rightColumnItems->Add(new Choice(mm->T("Credits")))->OnClick.Handle(this, &MainScreen::OnCredits); rightColumnItems->Add(new Choice(mm->T("www.ppsspp.org")))->OnClick.Handle(this, &MainScreen::OnPPSSPPOrg); if (!System_GetPropertyBool(SYSPROP_APP_GOLD)) { - Choice *gold = rightColumnItems->Add(new Choice(mm->T("Support PPSSPP"))); + Choice *gold = rightColumnItems->Add(new Choice(mm->T("Buy PPSSPP Gold"))); gold->OnClick.Handle(this, &MainScreen::OnSupport); gold->SetIcon(I_ICONGOLD); } From c9aa0396950eefc189692e267b8042c613f77cc2 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 1 Nov 2018 21:42:12 -0700 Subject: [PATCH 084/347] Windows: Check for devices on Windows events only. A user reported stuttering after the periodic checks, and devices failing until unplug/replug. Presumably, this is caused by poor drivers reacting badly to periodic DirectInput queries, so less queries should help. --- Windows/DinputDevice.cpp | 6 ++++-- Windows/DinputDevice.h | 5 +++++ Windows/MainWindow.cpp | 5 +++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Windows/DinputDevice.cpp b/Windows/DinputDevice.cpp index c72b7c0dbc..5d89e4ab54 100644 --- a/Windows/DinputDevice.cpp +++ b/Windows/DinputDevice.cpp @@ -39,6 +39,7 @@ unsigned int DinputDevice::pInstances = 0; LPDIRECTINPUT8 DinputDevice::pDI = NULL; std::vector DinputDevice::devices; +bool DinputDevice::needsCheck_ = true; // In order from 0. There can be 128, but most controllers do not have that many. static const int dinput_buttons[] = { @@ -120,7 +121,7 @@ BOOL CALLBACK DinputDevice::DevicesCallback( void DinputDevice::getDevices(bool refresh) { - if (devices.empty() || refresh) + if (refresh) { getPDI()->EnumDevices(DI8DEVCLASS_GAMECTRL, &DinputDevice::DevicesCallback, NULL, DIEDFL_ATTACHEDONLY); } @@ -368,6 +369,7 @@ void DinputDevice::ApplyButtons(DIJOYSTATE2 &state) { size_t DinputDevice::getNumPads() { - getDevices(true); + getDevices(needsCheck_); + needsCheck_ = false; return devices.size(); } diff --git a/Windows/DinputDevice.h b/Windows/DinputDevice.h index 366805c856..6314a055ed 100644 --- a/Windows/DinputDevice.h +++ b/Windows/DinputDevice.h @@ -35,6 +35,10 @@ public: virtual int UpdateState(); virtual bool IsPad() { return true; } static size_t getNumPads(); + static void CheckDevices() { + needsCheck_ = true; + } + private: void ApplyButtons(DIJOYSTATE2 &state); //unfortunate and unclean way to keep only one DirectInput instance around @@ -52,6 +56,7 @@ private: static unsigned int pInstances; static std::vector devices; static LPDIRECTINPUT8 pDI; + static bool needsCheck_; int pDevNum; LPDIRECTINPUTDEVICE8 pJoystick; DIJOYSTATE2 pPrevState; diff --git a/Windows/MainWindow.cpp b/Windows/MainWindow.cpp index 848b8cb5fa..9cf3eedfd3 100644 --- a/Windows/MainWindow.cpp +++ b/Windows/MainWindow.cpp @@ -54,6 +54,7 @@ #include "Windows/GEDebugger/GEDebugger.h" #include "Windows/main.h" +#include "Windows/DinputDevice.h" #include "Windows/EmuThread.h" #include "Windows/resource.h" @@ -814,6 +815,10 @@ namespace MainWindow case WM_CHAR: return WindowsRawInput::ProcessChar(hWnd, wParam, lParam); + case WM_DEVICECHANGE: + DinputDevice::CheckDevices(); + return DefWindowProc(hWnd, message, wParam, lParam); + case WM_VERYSLEEPY_MSG: switch (wParam) { case VERYSLEEPY_WPARAM_SUPPORTED: From 640973ff4705dff816c435b240566987c399fdad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 3 Nov 2018 17:35:21 +0100 Subject: [PATCH 085/347] Comply with new Google Play policy that is not happy with "Support PPSSPP" leading to the PPSSPP Gold app in Play --- UI/MainScreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index 1a5d31cee7..6956f95b50 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -922,7 +922,7 @@ void MainScreen::CreateViews() { rightColumnItems->Add(new Choice(mm->T("Credits")))->OnClick.Handle(this, &MainScreen::OnCredits); rightColumnItems->Add(new Choice(mm->T("www.ppsspp.org")))->OnClick.Handle(this, &MainScreen::OnPPSSPPOrg); if (!System_GetPropertyBool(SYSPROP_APP_GOLD)) { - Choice *gold = rightColumnItems->Add(new Choice(mm->T("Support PPSSPP"))); + Choice *gold = rightColumnItems->Add(new Choice(mm->T("Buy PPSSPP Gold"))); gold->OnClick.Handle(this, &MainScreen::OnSupport); gold->SetIcon(I_ICONGOLD); } From 886a1e031b2e8a88bc755fd4c7d6b80fca6fa07f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 3 Nov 2018 17:52:09 +0100 Subject: [PATCH 086/347] Update lang --- assets/lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/lang b/assets/lang index f60be494a4..3f5e33f843 160000 --- a/assets/lang +++ b/assets/lang @@ -1 +1 @@ -Subproject commit f60be494a43a49fd7ff61603e132c1e24c160d88 +Subproject commit 3f5e33f84319ab4d8b8e19612d46db431907706f From 42c50a0ab024326469cf12b69377416dafbb7a50 Mon Sep 17 00:00:00 2001 From: root Date: Sun, 4 Nov 2018 01:59:37 +0000 Subject: [PATCH 087/347] Fixes for Unknown --- Windows/MainWindow.h | 4 ++-- Windows/MainWindowMenu.cpp | 14 ++++++++------ Windows/ppsspp.rc | 4 ++-- Windows/resource.h | 4 ++-- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Windows/MainWindow.h b/Windows/MainWindow.h index 835d22cb2e..0341e897e7 100644 --- a/Windows/MainWindow.h +++ b/Windows/MainWindow.h @@ -35,8 +35,8 @@ namespace MainWindow FRAMESKIP_8 = 8, FRAMESKIP_MAX = FRAMESKIP_8, - FRAMESKIPTYPE_0 = 0, - FRAMESKIPTYPE_1 = 1, + FRAMESKIPTYPE_COUNT = 0, + FRAMESKIPTYPE_PRCNT = 1, RESOLUTION_AUTO = 0, RESOLUTION_NATIVE = 1, diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index ba25f60bed..aff87ebd21 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -337,7 +337,8 @@ namespace MainWindow { TranslateSubMenu(menu, "Frame Skipping", MENU_OPTIONS, SUBMENU_FRAME_SKIPPING, L"\tF7"); TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIP_AUTO); TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIP_0); - TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIPTYPE_0); + TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIPTYPE_COUNT); + TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIPTYPE_PRCNT); // Skip frameskipping 1-8.. TranslateSubMenu(menu, "Texture Filtering", MENU_OPTIONS, SUBMENU_TEXTURE_FILTERING); TranslateMenuItem(menu, ID_OPTIONS_TEXTUREFILTERING_AUTO); @@ -846,8 +847,8 @@ namespace MainWindow { case ID_OPTIONS_FRAMESKIP_7: setFrameSkipping(FRAMESKIP_7); break; case ID_OPTIONS_FRAMESKIP_8: setFrameSkipping(FRAMESKIP_MAX); break; - case ID_OPTIONS_FRAMESKIPTYPE_0: setFrameSkippingType(FRAMESKIPTYPE_0); break; - case ID_OPTIONS_FRAMESKIPTYPE_1: setFrameSkippingType(FRAMESKIPTYPE_1); break; + case ID_OPTIONS_FRAMESKIPTYPE_COUNT: setFrameSkippingType(FRAMESKIPTYPE_COUNT); break; + case ID_OPTIONS_FRAMESKIPTYPE_PRCNT: setFrameSkippingType(FRAMESKIPTYPE_PRCNT); break; case ID_OPTIONS_FRAMESKIPDUMMY: setFrameSkipping(); @@ -1101,7 +1102,8 @@ namespace MainWindow { CHECKITEM(ID_OPTIONS_SHOWFPS, g_Config.iShowFPSCounter); CHECKITEM(ID_OPTIONS_FRAMESKIP_AUTO, g_Config.bAutoFrameSkip); CHECKITEM(ID_OPTIONS_FRAMESKIP, g_Config.iFrameSkip != FRAMESKIP_OFF); - CHECKITEM(ID_OPTIONS_FRAMESKIPTYPE, g_Config.iFrameSkipType); + CHECKITEM(ID_OPTIONS_FRAMESKIPTYPE_COUNT, g_Config.iFrameSkipType == FRAMESKIPTYPE_COUNT); + CHECKITEM(ID_OPTIONS_FRAMESKIPTYPE_PRCNT, g_Config.iFrameSkipType == FRAMESKIPTYPE_PRCNT); CHECKITEM(ID_OPTIONS_VSYNC, g_Config.bVSync); CHECKITEM(ID_OPTIONS_TOPMOST, g_Config.bTopMost); CHECKITEM(ID_OPTIONS_PAUSE_FOCUS, g_Config.bPauseOnLostFocus); @@ -1276,8 +1278,8 @@ namespace MainWindow { }; static const int frameskippingType[] = { - ID_OPTIONS_FRAMESKIPTYPE_0, - ID_OPTIONS_FRAMESKIPTYPE_1, + ID_OPTIONS_FRAMESKIPTYPE_COUNT, + ID_OPTIONS_FRAMESKIPTYPE_PRCNT, }; if (g_Config.iFrameSkip < FRAMESKIP_OFF) diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index 64ebceda3f..f4cc79c8f1 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -591,8 +591,8 @@ BEGIN END POPUP "Frame Skipping Type" BEGIN - MENUITEM "Skip Number of Frames", ID_OPTIONS_FRAMESKIPTYPE_0 - MENUITEM "Skip Percent of FPS", ID_OPTIONS_FRAMESKIPTYPE_1 + MENUITEM "Skip Number of Frames", ID_OPTIONS_FRAMESKIPTYPE_COUNT + MENUITEM "Skip Percent of FPS", ID_OPTIONS_FRAMESKIPTYPE_PRCNT END POPUP "Texture Filtering" BEGIN diff --git a/Windows/resource.h b/Windows/resource.h index 2dddf88dd4..d6394a20bb 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -343,8 +343,8 @@ #define ID_EMULATION_PAUSE 40177 #define ID_HELP_DISCORD 40178 #define IDC_GEDBG_STEPCURVE 40179 -#define ID_OPTIONS_FRAMESKIPTYPE_0 40180 -#define ID_OPTIONS_FRAMESKIPTYPE_1 40181 +#define ID_OPTIONS_FRAMESKIPTYPE_COUNT 40180 +#define ID_OPTIONS_FRAMESKIPTYPE_PRCNT 40181 // Dummy option to let the buffered rendering hotkey cycle through all the options. #define ID_OPTIONS_BUFFEREDRENDERINGDUMMY 40500 From 38eb9d12d0e0e3c49d5b2f5229e8236f7df157e5 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 4 Nov 2018 08:09:13 -0800 Subject: [PATCH 088/347] TexCache: Don't swizzle DXT1 colors. Hardware tests show that this shouldn't happen. May be important for color tests, etc. --- GPU/Common/TextureDecoder.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/GPU/Common/TextureDecoder.cpp b/GPU/Common/TextureDecoder.cpp index ea2df36d89..5c86f2dc77 100644 --- a/GPU/Common/TextureDecoder.cpp +++ b/GPU/Common/TextureDecoder.cpp @@ -357,12 +357,12 @@ static inline int mul_3_8(int c) { void DXTDecoder::DecodeColors(const DXT1Block *src, bool ignore1bitAlpha) { u16 c1 = src->color1; u16 c2 = src->color2; - int red1 = Convert5To8(c1 & 0x1F); - int red2 = Convert5To8(c2 & 0x1F); - int green1 = Convert6To8((c1 >> 5) & 0x3F); - int green2 = Convert6To8((c2 >> 5) & 0x3F); - int blue1 = Convert5To8((c1 >> 11) & 0x1F); - int blue2 = Convert5To8((c2 >> 11) & 0x1F); + int red1 = (c1 << 3) & 0xF8; + int red2 = (c2 << 3) & 0xF8; + int green1 = (c1 >> 3) & 0xFC; + int green2 = (c2 >> 3) & 0xFC; + int blue1 = (c1 >> 8) & 0xF8; + int blue2 = (c2 >> 8) & 0xF8; // Keep alpha zero for non-DXT1 to skip masking the colors. int alpha = ignore1bitAlpha ? 0 : 255; From 35a1d8a1ef2404f3862e819fb221c7f29faed368 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 4 Nov 2018 08:09:56 -0800 Subject: [PATCH 089/347] TexCache: Decode DXT1 zero alpha as black. Hardware tests show this is how it decodes, which is more like standard DXT1 decoding. --- GPU/Common/TextureDecoder.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/GPU/Common/TextureDecoder.cpp b/GPU/Common/TextureDecoder.cpp index 5c86f2dc77..4a84fb264a 100644 --- a/GPU/Common/TextureDecoder.cpp +++ b/GPU/Common/TextureDecoder.cpp @@ -381,8 +381,7 @@ void DXTDecoder::DecodeColors(const DXT1Block *src, bool ignore1bitAlpha) { int green3 = (green1 + green2 + 1) / 2; int blue3 = (blue1 + blue2 + 1) / 2; colors_[2] = makecol(red3, green3, blue3, 255); - // Color2 but transparent - colors_[3] = makecol(red2, green2, blue2, 0); + colors_[3] = makecol(0, 0, 0, 0); } } From 11ab4e86344f1823153a3f03b0092785ab47fb13 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 4 Nov 2018 08:37:24 -0800 Subject: [PATCH 090/347] TexCache: Mix DXT colors using 2/3 not 3/8. Hardware draws using 2/3. Adding this way matches rounding, too. --- GPU/Common/TextureDecoder.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/GPU/Common/TextureDecoder.cpp b/GPU/Common/TextureDecoder.cpp index 4a84fb264a..8f40cc13f4 100644 --- a/GPU/Common/TextureDecoder.cpp +++ b/GPU/Common/TextureDecoder.cpp @@ -348,9 +348,8 @@ static inline u32 makecol(int r, int g, int b, int a) { return (a << 24) | (r << 16) | (g << 8) | b; } -static inline int mul_3_8(int c) { - // This is 3/8 * c = 4/8 * c - 1/8 * c. - return (c >> 1) - (c >> 3); +static inline int mix_2_3(int c1, int c2) { + return (c1 + c1 + c2) / 3; } // This could probably be done faster by decoding two or four blocks at a time with SSE/NEON. @@ -370,16 +369,13 @@ void DXTDecoder::DecodeColors(const DXT1Block *src, bool ignore1bitAlpha) { colors_[0] = makecol(red1, green1, blue1, alpha); colors_[1] = makecol(red2, green2, blue2, alpha); if (c1 > c2 || ignore1bitAlpha) { - int red3 = mul_3_8(red2 - red1); - int green3 = mul_3_8(green2 - green1); - int blue3 = mul_3_8(blue2 - blue1); - colors_[2] = makecol(red1 + red3, green1 + green3, blue1 + blue3, alpha); - colors_[3] = makecol(red2 - red3, green2 - green3, blue2 - blue3, alpha); + colors_[2] = makecol(mix_2_3(red1, red2), mix_2_3(green1, green2), mix_2_3(blue1, blue2), alpha); + colors_[3] = makecol(mix_2_3(red2, red1), mix_2_3(green2, green1), mix_2_3(blue2, blue1), alpha); } else { - // Average - int red3 = (red1 + red2 + 1) / 2; - int green3 = (green1 + green2 + 1) / 2; - int blue3 = (blue1 + blue2 + 1) / 2; + // Average - these are always left shifted, so no need to worry about ties. + int red3 = (red1 + red2) / 2; + int green3 = (green1 + green2) / 2; + int blue3 = (blue1 + blue2) / 2; colors_[2] = makecol(red3, green3, blue3, 255); colors_[3] = makecol(0, 0, 0, 0); } From c31e01771ea4501e2b100aa6cbb8aa85707a64f0 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 4 Nov 2018 08:53:16 -0800 Subject: [PATCH 091/347] TexCache: Respect color order in DXT3/5. Hardware is still doing DXT1 style colors in this scenario. --- GPU/Common/TextureDecoder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/Common/TextureDecoder.cpp b/GPU/Common/TextureDecoder.cpp index 8f40cc13f4..af98b62cb6 100644 --- a/GPU/Common/TextureDecoder.cpp +++ b/GPU/Common/TextureDecoder.cpp @@ -368,7 +368,7 @@ void DXTDecoder::DecodeColors(const DXT1Block *src, bool ignore1bitAlpha) { colors_[0] = makecol(red1, green1, blue1, alpha); colors_[1] = makecol(red2, green2, blue2, alpha); - if (c1 > c2 || ignore1bitAlpha) { + if (c1 > c2) { colors_[2] = makecol(mix_2_3(red1, red2), mix_2_3(green1, green2), mix_2_3(blue1, blue2), alpha); colors_[3] = makecol(mix_2_3(red2, red1), mix_2_3(green2, green1), mix_2_3(blue2, blue1), alpha); } else { @@ -376,7 +376,7 @@ void DXTDecoder::DecodeColors(const DXT1Block *src, bool ignore1bitAlpha) { int red3 = (red1 + red2) / 2; int green3 = (green1 + green2) / 2; int blue3 = (blue1 + blue2) / 2; - colors_[2] = makecol(red3, green3, blue3, 255); + colors_[2] = makecol(red3, green3, blue3, alpha); colors_[3] = makecol(0, 0, 0, 0); } } From df200fc3d2ad5405497914921a66c9c312223eda Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 4 Nov 2018 08:55:42 -0800 Subject: [PATCH 092/347] TexCache: In DXT3, don't swizzle alpha. Hardware doesn't seem to. --- GPU/Common/TextureDecoder.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/GPU/Common/TextureDecoder.cpp b/GPU/Common/TextureDecoder.cpp index af98b62cb6..d729ab976e 100644 --- a/GPU/Common/TextureDecoder.cpp +++ b/GPU/Common/TextureDecoder.cpp @@ -431,8 +431,7 @@ void DXTDecoder::WriteColorsDXT3(u32 *dst, const DXT3Block *src, int pitch, int int colordata = src->color.lines[y]; u32 alphadata = src->alphaLines[y]; for (int x = 0; x < 4; x++) { - const u8 a4 = alphadata & 0xF; - dst[x] = colors_[colordata & 3] | (a4 << 24) | (a4 << 28); + dst[x] = colors_[colordata & 3] | (alphadata << 28); colordata >>= 2; alphadata >>= 4; } From bd294f658f7abc95d946d096e64f355ff6dc67fd Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 4 Nov 2018 09:31:30 -0800 Subject: [PATCH 093/347] TexCache: Round DXT5 alpha up. This isn't quite right, but it seems better than rounding down. Experimented with a lower round up value, but none were right - the weighting must be more complex. --- GPU/Common/TextureDecoder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/Common/TextureDecoder.cpp b/GPU/Common/TextureDecoder.cpp index d729ab976e..9e896872fe 100644 --- a/GPU/Common/TextureDecoder.cpp +++ b/GPU/Common/TextureDecoder.cpp @@ -385,13 +385,13 @@ static inline u8 lerp8(const DXT5Block *src, int n) { // These weights translate alpha1/alpha2 to fixed 8.8 point, pre-divided by 7. int weight1 = ((7 - n) << 8) / 7; int weight2 = (n << 8) / 7; - return (u8)((src->alpha1 * weight1 + src->alpha2 * weight2) >> 8); + return (u8)((src->alpha1 * weight1 + src->alpha2 * weight2 + 255) >> 8); } static inline u8 lerp6(const DXT5Block *src, int n) { int weight1 = ((5 - n) << 8) / 5; int weight2 = (n << 8) / 5; - return (u8)((src->alpha1 * weight1 + src->alpha2 * weight2) >> 8); + return (u8)((src->alpha1 * weight1 + src->alpha2 * weight2 + 255) >> 8); } void DXTDecoder::DecodeAlphaDXT5(const DXT5Block *src) { From d9ad57e91821907cdcb71c725bb21f9be35cfb08 Mon Sep 17 00:00:00 2001 From: mrfixit2001 <38842252+mrfixit2001@users.noreply.github.com> Date: Sun, 4 Nov 2018 13:33:42 -0500 Subject: [PATCH 094/347] Move comments in function to be more relevant --- Core/HLE/sceDisplay.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index da3bf70f86..b570aa4aeb 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -504,11 +504,12 @@ static void DoFrameDropLogging(float scaledTimestep) { } static int CalculateFrameSkip() { - // Used to calculate the FPS to skip if the user sets the type to percent of fps int frameSkipNum; if (g_Config.iFrameSkipType == 1) { + // Calculate the frames to skip dynamically using the set percentage of the current fps frameSkipNum = ceil( flips * (static_cast(g_Config.iFrameSkip) / 100.00) ); } else { + // Use the set number of frames to skip frameSkipNum = g_Config.iFrameSkip; } return frameSkipNum; From 67d6e3d384784ac052a9fdf63c5da3a9be14abca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 5 Nov 2018 00:27:29 +0100 Subject: [PATCH 095/347] Framebuffer blit: Clip src rectangle as well --- GPU/Vulkan/FramebufferVulkan.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp index 7851238090..91dd924a15 100644 --- a/GPU/Vulkan/FramebufferVulkan.cpp +++ b/GPU/Vulkan/FramebufferVulkan.cpp @@ -468,6 +468,13 @@ void FramebufferManagerVulkan::BlitFramebuffer(VirtualFramebuffer *dst, int dstX if (dstY + h > dst->bufferHeight) { h -= dstY + h - dst->bufferHeight; } + if (srcX + w > src->bufferWidth) { + w -= srcX + w - src->bufferWidth; + } + if (srcY + h > src->bufferHeight) { + h -= srcY + h - src->bufferHeight; + } + if (w == 0 || h == 0) return; From 3bc89f3d1c2f0355fed05884a6d62ef8a36d0292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Tue, 6 Nov 2018 10:59:22 +0100 Subject: [PATCH 096/347] CMake: Allow disabling Wayland support with USE_WAYLAND_WSI This change means that USE_WAYLAND_WSI=ON no longer triggers a fatal error if Wayland libraries are missing though, it will just show a message and continue building without Wayand WSI support. Closes #11536. --- CMakeLists.txt | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c15cba0d0..b572ba7817 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,6 +122,7 @@ option(USING_FBDEV "Set to ON if target environment uses fbdev (eg. Pandora)" ${ option(USING_GLES2 "Set to ON if target device uses OpenGL ES 2.0" ${USING_GLES2}) option(RASPBIAN "Set to ON to workaround threading issues when building for ARMV7 on Raspbian" ${RASPBIAN}) option(USING_X11_VULKAN "Set to OFF if target environment doesn't use X11 for Vulkan" ON) +option(USE_WAYLAND_WSI "Enable or disable Wayland WSI support for Vulkan" ON) # :: Frontends option(USING_QT_UI "Set to ON if you wish to use the Qt frontend wrapper" ${USING_QT_UI}) option(MOBILE_DEVICE "Set to ON when targeting a mobile device" ${MOBILE_DEVICE}) @@ -134,7 +135,6 @@ option(USE_FFMPEG "Build with FFMPEG support" ${USE_FFMPEG}) option(USE_SYSTEM_SNAPPY "Dynamically link against system snappy" ${USE_SYSTEM_SNAPPY}) option(USE_SYSTEM_FFMPEG "Dynamically link against system FFMPEG" ${USE_SYSTEM_FFMPEG}) option(USE_SYSTEM_LIBZIP "Dynamically link against system libzip" ${USE_SYSTEM_LIBZIP}) -option(USE_WAYLAND_WSI "Set to ON to require Wayland support for Vulkan" ${USE_WAYLAND_WSI}) option(USE_ADDRESS_SANITIZER "Use Clang memory sanitizer" ${USE_ADDRESS_SANITIZER}) if(UNIX AND NOT (APPLE OR ANDROID) AND VULKAN) @@ -145,13 +145,14 @@ if(UNIX AND NOT (APPLE OR ANDROID) AND VULKAN) message("NOT using X11 for Vulkan") endif() # add_definitions(-DVK_USE_PLATFORM_XCB_KHR) - find_package(Wayland) - if(USE_WAYLAND_WSI AND NOT WAYLAND_FOUND) - message(FATAL_ERROR "Could not find libwayland, but USE_WAYLAND_WSI was enabled. Failing.") - endif() - if(WAYLAND_FOUND) - include_directories(${WAYLAND_INCLUDE_DIR}) - add_definitions(-DVK_USE_PLATFORM_WAYLAND_KHR) + if(USE_WAYLAND_WSI) + find_package(Wayland) + if(NOT WAYLAND_FOUND) + message(STATUS "Could not find Wayland libraries, disabling Wayland WSI support for Vulkan.") + else() + include_directories(${WAYLAND_INCLUDE_DIR}) + add_definitions(-DVK_USE_PLATFORM_WAYLAND_KHR) + endif() endif() endif() From ea2025c291854c2d2cbc03b1adb90de4079035a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Tue, 6 Nov 2018 14:31:44 +0100 Subject: [PATCH 097/347] CMake: Link against OpenGL when using EGL but not GLES2 At least for Linux armv7hl this seems to be necessary, otherwise build fails with: /usr/bin/ld: lib/libnative.a(GLQueueRunner.cpp.o): undefined reference to symbol 'glStencilOp' --- CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c15cba0d0..5cbb9ecdd0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -182,6 +182,10 @@ if(NOT OPENGL_LIBRARIES AND USING_GLES2) set(OPENGL_LIBRARIES GLESv2 EGL) endif() +if(NOT OPENGL_LIBRARIES) + find_package(OpenGL REQUIRED) +endif() + if(USING_EGL) if(NOT EGL_LIBRARIES) set(EGL_LIBRARIES EGL) @@ -189,10 +193,6 @@ if(USING_EGL) set(OPENGL_LIBRARIES ${OPENGL_LIBRARIES} ${EGL_LIBRARIES}) endif() -if(NOT OPENGL_LIBRARIES) - find_package(OpenGL REQUIRED) -endif() - find_package(SDL2) include(FindThreads) From 3cc7054831235a7baca2f5d37c35a141f2faa1aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Tue, 6 Nov 2018 18:31:05 +0100 Subject: [PATCH 098/347] CMake: Fix linking X11 when using EGL and not fbdev Co-authored-by: Unknown W. Brackets --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f6536a9ab3..025152e551 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -489,7 +489,7 @@ if(TARGET SDL2::SDL2) target_link_libraries(Common SDL2::SDL2) endif() -if(USING_GLES2) +if(USING_GLES2 OR (USING_EGL AND NOT USING_FBDEV)) find_package(X11) endif() From 340460f01ceba7dd1c0ac9efec1fb596957a9c5c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 6 Nov 2018 19:28:22 -0800 Subject: [PATCH 099/347] Io: Add missing error code on file open. Doesn't affect Windows. --- Core/FileSystems/DirectoryFileSystem.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp index 27a15f352e..20dc6565c0 100644 --- a/Core/FileSystems/DirectoryFileSystem.cpp +++ b/Core/FileSystems/DirectoryFileSystem.cpp @@ -281,8 +281,10 @@ bool DirectoryFileHandle::Open(std::string &basePath, std::string &fileName, Fil #if HOST_IS_CASE_SENSITIVE if (!success && !(access & FILEACCESS_CREATE)) { - if (!FixPathCase(basePath,fileName, FPC_PATH_MUST_EXIST) ) - return 0; // or go on and attempt (for a better error code than just 0?) + if (!FixPathCase(basePath, fileName, FPC_PATH_MUST_EXIST)) { + error = SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND; + return false; + } fullName = GetLocalPath(basePath,fileName); const char *fullNameC = fullName.c_str(); From 4996084665c6d09da1a713b95168c340268f303a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 6 Nov 2018 21:16:51 -0800 Subject: [PATCH 100/347] GPU: Dirty frag shader on depth write. We use this flag to determine whether we use discard, so it changes shader ids. Fixes the layering part of #11535. --- GPU/GPUCommon.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 1d8266d500..2fb07c9ae9 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -120,8 +120,8 @@ const CommonCommandTableEntry commonCommandTable[] = { { GE_CMD_MASKRGB, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE }, { GE_CMD_MASKALPHA, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE }, { GE_CMD_ZTEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHSTENCIL_STATE }, - { GE_CMD_ZTESTENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHSTENCIL_STATE }, - { GE_CMD_ZWRITEDISABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHSTENCIL_STATE }, + { GE_CMD_ZTESTENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHSTENCIL_STATE | DIRTY_FRAGMENTSHADER_STATE }, + { GE_CMD_ZWRITEDISABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHSTENCIL_STATE | DIRTY_FRAGMENTSHADER_STATE }, { GE_CMD_LOGICOP, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE }, { GE_CMD_LOGICOPENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE }, From 8694c331198a3e90bcee7cdbecb6a219b653d5f4 Mon Sep 17 00:00:00 2001 From: Florin9doi Date: Wed, 31 Oct 2018 23:36:38 +0200 Subject: [PATCH 101/347] F-droid lite version - create stubs for Moga Controller --- android/build.gradle | 10 ++++- .../com/bda/controller/Controller.java | 39 +++++++++++++++++++ .../bda/controller/ControllerListener.java | 9 +++++ .../bda/controller/IControllerService.java | 4 ++ .../com/bda/controller/KeyEvent.java | 20 ++++++++++ .../com/bda/controller/MotionEvent.java | 14 +++++++ .../com/bda/controller/StateEvent.java | 19 +++++++++ .../src/org/ppsspp/ppsspp/NativeGLView.java | 6 ++- .../org/ppsspp/ppsspp/NativeSurfaceView.java | 6 ++- 9 files changed, 123 insertions(+), 4 deletions(-) create mode 100644 android/libs/MogaStubs/com/bda/controller/Controller.java create mode 100644 android/libs/MogaStubs/com/bda/controller/ControllerListener.java create mode 100644 android/libs/MogaStubs/com/bda/controller/IControllerService.java create mode 100644 android/libs/MogaStubs/com/bda/controller/KeyEvent.java create mode 100644 android/libs/MogaStubs/com/bda/controller/MotionEvent.java create mode 100644 android/libs/MogaStubs/com/bda/controller/StateEvent.java diff --git a/android/build.gradle b/android/build.gradle index 51b4eb9317..93aeaaf75b 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -144,6 +144,12 @@ android { afterEvaluate { android.sourceSets.main.assets.getSrcDirs().each { println it } } -dependencies { - implementation files('libs/com.bda.controller.jar') + +// F-Droid lite version can be created with : ./gradlew assembleOptimized -Pf_droid +if (project.hasProperty("f_droid")) { + project.android.sourceSets.main.java.srcDirs += 'libs/MogaStubs' +} else { + project.dependencies { + implementation files('libs/com.bda.controller.jar') + } } diff --git a/android/libs/MogaStubs/com/bda/controller/Controller.java b/android/libs/MogaStubs/com/bda/controller/Controller.java new file mode 100644 index 0000000000..c30cae357b --- /dev/null +++ b/android/libs/MogaStubs/com/bda/controller/Controller.java @@ -0,0 +1,39 @@ +package com.bda.controller; + +import android.app.Activity; +import android.os.Handler; +import android.view.SurfaceView; + +public class Controller { + public static final int ACTION_VERSION_MOGA = 0; + public static final int STATE_CURRENT_PRODUCT_VERSION = 1; + + static Controller sInstance; + + private Controller() {} + + public static Controller getInstance(Activity activity) { + if (sInstance == null) { + sInstance = new Controller(); + } + return sInstance; + } + public int getState(int val) { + return 0; + } + public int setListener(SurfaceView view, Handler handler) { + return 0; + } + public int init() { + return 0; + } + public int onPause() { + return 0; + } + public int onResume() { + return 0; + } + public int exit() { + return 0; + } +} diff --git a/android/libs/MogaStubs/com/bda/controller/ControllerListener.java b/android/libs/MogaStubs/com/bda/controller/ControllerListener.java new file mode 100644 index 0000000000..c1bde2b583 --- /dev/null +++ b/android/libs/MogaStubs/com/bda/controller/ControllerListener.java @@ -0,0 +1,9 @@ +package com.bda.controller; + +public interface ControllerListener { + public abstract void onKeyEvent(KeyEvent event); + + public abstract void onMotionEvent(MotionEvent event); + + public abstract void onStateEvent(StateEvent state); +} diff --git a/android/libs/MogaStubs/com/bda/controller/IControllerService.java b/android/libs/MogaStubs/com/bda/controller/IControllerService.java new file mode 100644 index 0000000000..2fe7a5c3f6 --- /dev/null +++ b/android/libs/MogaStubs/com/bda/controller/IControllerService.java @@ -0,0 +1,4 @@ +package com.bda.controller; + +public class IControllerService { +} diff --git a/android/libs/MogaStubs/com/bda/controller/KeyEvent.java b/android/libs/MogaStubs/com/bda/controller/KeyEvent.java new file mode 100644 index 0000000000..2a6a108921 --- /dev/null +++ b/android/libs/MogaStubs/com/bda/controller/KeyEvent.java @@ -0,0 +1,20 @@ +package com.bda.controller; + +public class KeyEvent { + public static final int ACTION_DOWN = 0; + public static final int ACTION_UP = 1; + public static final int KEYCODE_DPAD_UP = 2; + public static final int KEYCODE_DPAD_DOWN = 3; + public static final int KEYCODE_DPAD_LEFT = 4; + public static final int KEYCODE_DPAD_RIGHT = 5; + + public int getAction() { + return 0; + } + public int getState(int val) { + return 0; + } + public int getKeyCode() { + return 0; + } +} diff --git a/android/libs/MogaStubs/com/bda/controller/MotionEvent.java b/android/libs/MogaStubs/com/bda/controller/MotionEvent.java new file mode 100644 index 0000000000..35d8816ff2 --- /dev/null +++ b/android/libs/MogaStubs/com/bda/controller/MotionEvent.java @@ -0,0 +1,14 @@ +package com.bda.controller; + +public class MotionEvent { + public static final int AXIS_X = 0; + public static final int AXIS_Y = 1; + public static final int AXIS_Z = 2; + public static final int AXIS_RZ = 3; + public static final int AXIS_LTRIGGER = 4; + public static final int AXIS_RTRIGGER = 5; + + public int getAxisValue(int val) { + return 0; + } +} diff --git a/android/libs/MogaStubs/com/bda/controller/StateEvent.java b/android/libs/MogaStubs/com/bda/controller/StateEvent.java new file mode 100644 index 0000000000..230e8b7172 --- /dev/null +++ b/android/libs/MogaStubs/com/bda/controller/StateEvent.java @@ -0,0 +1,19 @@ +package com.bda.controller; + +public class StateEvent { + public static final int STATE_POWER_LOW = 0; + public static final int STATE_CONNECTION = 1; + + public static final int ACTION_FALSE = 0; + public static final int ACTION_TRUE = 1; + public static final int ACTION_DISCONNECTED = 2; + public static final int ACTION_CONNECTING = 3; + public static final int ACTION_CONNECTED = 4; + + public int getAction() { + return 0; + } + public int getState() { + return 0; + } +} diff --git a/android/src/org/ppsspp/ppsspp/NativeGLView.java b/android/src/org/ppsspp/ppsspp/NativeGLView.java index ce2e4be677..af5b738be6 100644 --- a/android/src/org/ppsspp/ppsspp/NativeGLView.java +++ b/android/src/org/ppsspp/ppsspp/NativeGLView.java @@ -18,7 +18,11 @@ import android.os.Build; import android.os.Handler; import android.util.Log; import android.view.MotionEvent; -import com.bda.controller.*; + +import com.bda.controller.Controller; +import com.bda.controller.ControllerListener; +import com.bda.controller.KeyEvent; +import com.bda.controller.StateEvent; public class NativeGLView extends GLSurfaceView implements SensorEventListener, ControllerListener { private static String TAG = "NativeGLView"; diff --git a/android/src/org/ppsspp/ppsspp/NativeSurfaceView.java b/android/src/org/ppsspp/ppsspp/NativeSurfaceView.java index d09952b6b5..1efc71fd8e 100644 --- a/android/src/org/ppsspp/ppsspp/NativeSurfaceView.java +++ b/android/src/org/ppsspp/ppsspp/NativeSurfaceView.java @@ -16,7 +16,11 @@ import android.os.Handler; import android.util.Log; import android.view.MotionEvent; import android.view.SurfaceView; -import com.bda.controller.*; + +import com.bda.controller.Controller; +import com.bda.controller.ControllerListener; +import com.bda.controller.KeyEvent; +import com.bda.controller.StateEvent; public class NativeSurfaceView extends SurfaceView implements SensorEventListener, ControllerListener { private static String TAG = "NativeSurfaceView"; From 6bd6b86c0514151509d04854a6cebf1f11f93b57 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Nov 2018 07:39:27 -0800 Subject: [PATCH 102/347] Discord: Add cmake option to disable. --- CMakeLists.txt | 4 +++- UI/DiscordIntegration.cpp | 4 ++++ ext/CMakeLists.txt | 6 +++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c15cba0d0..27f4b45720 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -131,6 +131,7 @@ option(SIMULATOR "Set to ON when targeting an x86 simulator of an ARM platform" option(LIBRETRO "Set to ON to generate the libretro target" OFF) # :: Options option(USE_FFMPEG "Build with FFMPEG support" ${USE_FFMPEG}) +option(USE_DISCORD "Build with Discord support" ON) option(USE_SYSTEM_SNAPPY "Dynamically link against system snappy" ${USE_SYSTEM_SNAPPY}) option(USE_SYSTEM_FFMPEG "Dynamically link against system FFMPEG" ${USE_SYSTEM_FFMPEG}) option(USE_SYSTEM_LIBZIP "Dynamically link against system libzip" ${USE_SYSTEM_LIBZIP}) @@ -1801,7 +1802,8 @@ if(FFmpeg_FOUND) endif() # Discord integration -if(NOT IOS) +if(USE_DISCORD AND NOT IOS) + add_definitions(-DUSE_DISCORD=1) target_link_libraries(${CoreLibName} discord-rpc) endif() diff --git a/UI/DiscordIntegration.cpp b/UI/DiscordIntegration.cpp index 54ee337e3f..b07adf518a 100644 --- a/UI/DiscordIntegration.cpp +++ b/UI/DiscordIntegration.cpp @@ -9,7 +9,11 @@ #if (PPSSPP_PLATFORM(WINDOWS) || PPSSPP_PLATFORM(MAC) || PPSSPP_PLATFORM(LINUX)) && !PPSSPP_PLATFORM(ANDROID) +#ifdef _MSC_VER #define ENABLE_DISCORD +#elif USE_DISCORD +#define ENABLE_DISCORD +#endif #else diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt index ade6594e8f..b259a6f059 100644 --- a/ext/CMakeLists.txt +++ b/ext/CMakeLists.txt @@ -2,7 +2,7 @@ set(ARMIPS_REGEXP OFF CACHE BOOL "" FORCE) add_subdirectory(armips) if(NOT USING_GLES2) - add_subdirectory(glew) + add_subdirectory(glew) endif() set(ENABLE_GLSLANG_BINARIES OFF CACHE BOOL "let's not build binaries we don't need" FORCE) @@ -12,6 +12,6 @@ add_subdirectory(glslang) add_subdirectory(snappy) add_subdirectory(udis86) add_subdirectory(SPIRV-Cross-build) -if(NOT IOS) -add_subdirectory(discord-rpc-build) +if(USE_DISCORD AND NOT IOS) + add_subdirectory(discord-rpc-build) endif() From c96748f0e222c126ea0796af0b0bda6dedfe52a6 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Nov 2018 07:48:04 -0800 Subject: [PATCH 103/347] Discord: Attempt to explicitly cleanup on exit. --- UI/DiscordIntegration.cpp | 9 +++++++++ UI/DiscordIntegration.h | 1 + UI/EmuScreen.cpp | 6 +++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/UI/DiscordIntegration.cpp b/UI/DiscordIntegration.cpp index b07adf518a..34fc4d00b5 100644 --- a/UI/DiscordIntegration.cpp +++ b/UI/DiscordIntegration.cpp @@ -134,3 +134,12 @@ void Discord::SetPresenceMenu() { Discord_UpdatePresence(&discordPresence); #endif } + +void Discord::ClearPresence() { + if (!IsEnabled() || !initialized_) + return; + +#ifdef ENABLE_DISCORD + Discord_ClearPresence(); +#endif +} diff --git a/UI/DiscordIntegration.h b/UI/DiscordIntegration.h index cd700d59ea..a2911d6877 100644 --- a/UI/DiscordIntegration.h +++ b/UI/DiscordIntegration.h @@ -17,6 +17,7 @@ public: void SetPresenceGame(const char *gameTitle); void SetPresenceMenu(); + void ClearPresence(); private: void Init(); diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index b638661074..fe82bf2373 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -346,7 +346,11 @@ EmuScreen::~EmuScreen() { startDumping = false; } #endif - g_Discord.SetPresenceMenu(); + + if (GetUIState() == UISTATE_EXIT) + g_Discord.ClearPresence(); + else + g_Discord.SetPresenceMenu(); } void EmuScreen::dialogFinished(const Screen *dialog, DialogResult result) { From ca8681f59cc7579f529192e763ada96c82aa9bfb Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Nov 2018 07:47:50 -0800 Subject: [PATCH 104/347] UI: Fix incorrect 3D API. If the string doesn't exist (e.g. OpenGL ES), the std::string goes out of scope, and we end up with a bad string. Oops. --- UI/DevScreens.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index 11863bd210..a81bc8c60b 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -388,7 +388,8 @@ void SystemInfoScreen::CreateViews() { DrawContext *draw = screenManager()->getDrawContext(); - const char *apiName = gr->T(screenManager()->getDrawContext()->GetInfoString(InfoField::APINAME)); + const std::string apiNameKey = draw->GetInfoString(InfoField::APINAME); + const char *apiName = gr->T(apiNameKey); deviceSpecs->Add(new InfoItem(si->T("3D API"), apiName)); deviceSpecs->Add(new InfoItem(si->T("Vendor"), draw->GetInfoString(InfoField::VENDORSTRING))); std::string vendor = draw->GetInfoString(InfoField::VENDOR); From 9c6f7000b76be1a25f5cec674f6c0f7322324c10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 11 Nov 2018 22:49:40 +0100 Subject: [PATCH 105/347] New spline stuff seems to need bigger storage buffer pools --- GPU/Vulkan/DrawEngineVulkan.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 654b8a1a41..330f138b46 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -355,7 +355,7 @@ VkResult DrawEngineVulkan::RecreateDescriptorPool(FrameData &frame, int newSize) dpTypes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; dpTypes[1].descriptorCount = frame.descPoolSize * 3; // Don't use these for tess anymore, need max three per set. dpTypes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - dpTypes[2].descriptorCount = frame.descPoolSize; + dpTypes[2].descriptorCount = frame.descPoolSize * 3; // TODO: Use a separate layout when no spline stuff is needed to reduce the need for these. dpTypes[2].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; VkDescriptorPoolCreateInfo dp{ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; From d8f4a703967b906279d8365ee7d174995271052d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 11 Nov 2018 10:54:28 +0100 Subject: [PATCH 106/347] Remove constraint that virtual framebuffers have to represent VRAM. Prerequisite for #11531, virtual readbacks. --- GPU/Common/FramebufferCommon.cpp | 45 ++++++++++++++------------- GPU/Common/FramebufferCommon.h | 5 ++- GPU/Common/TextureCacheCommon.cpp | 9 +++--- GPU/D3D11/FramebufferManagerD3D11.cpp | 2 +- GPU/Directx9/FramebufferDX9.cpp | 10 +++--- GPU/GLES/DrawEngineGLES.cpp | 2 +- 6 files changed, 37 insertions(+), 36 deletions(-) diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index d0ae91c2d0..c654f3f7ce 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -253,10 +253,10 @@ void FramebufferManagerCommon::EstimateDrawingSize(u32 fb_address, GEBufferForma if (viewport_width != region_width) { // The majority of the time, these are equal. If not, let's check what we know. - const u32 fb_normalized_address = fb_address | 0x44000000; + const u32 fb_normalized_address = fb_address & 0x3FFFFFFF; u32 nearest_address = 0xFFFFFFFF; for (size_t i = 0; i < vfbs_.size(); ++i) { - const u32 other_address = vfbs_[i]->fb_address | 0x44000000; + const u32 other_address = vfbs_[i]->fb_address & 0x3FFFFFFF; if (other_address > fb_normalized_address && other_address < nearest_address) { nearest_address = other_address; } @@ -282,11 +282,10 @@ void FramebufferManagerCommon::EstimateDrawingSize(u32 fb_address, GEBufferForma } void GetFramebufferHeuristicInputs(FramebufferHeuristicParams *params, const GPUgstate &gstate) { - params->fb_addr = gstate.getFrameBufAddress(); - params->fb_address = gstate.getFrameBufRawAddress(); + params->fb_address = (gstate.getFrameBufRawAddress() & 0x3FFFFFFF) | 0x04000000; // GetFramebufferHeuristicInputs is only called from rendering, and thus, it's VRAM. params->fb_stride = gstate.FrameBufStride(); - params->z_address = gstate.getDepthBufRawAddress(); + params->z_address = (gstate.getDepthBufRawAddress() & 0x3FFFFFFF) | 0x04000000; params->z_stride = gstate.DepthBufStride(); params->fmt = gstate.FrameBufFormat(); @@ -440,9 +439,9 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame SetColorUpdated(vfb, skipDrawReason); u32 byteSize = FramebufferByteSize(vfb); - u32 fb_address_mem = (params.fb_address & 0x3FFFFFFF) | 0x04000000; - if (Memory::IsVRAMAddress(fb_address_mem) && fb_address_mem + byteSize > framebufRangeEnd_) { - framebufRangeEnd_ = fb_address_mem + byteSize; + // FB heuristics always produce an address in VRAM (this is during rendering) so we don't need to poke in the 0x04000000 flag here. + if (Memory::IsVRAMAddress(params.fb_address) && params.fb_address + byteSize > framebufRangeEnd_) { + framebufRangeEnd_ = params.fb_address + byteSize; } ResizeFramebufFBO(vfb, drawing_width, drawing_height, true); @@ -456,8 +455,8 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame currentRenderVfb_ = vfb; if (useBufferedRendering_ && !g_Config.bDisableSlowFramebufEffects) { - gpu->PerformMemoryUpload(fb_address_mem, byteSize); - NotifyStencilUpload(fb_address_mem, byteSize, true); + gpu->PerformMemoryUpload(params.fb_address, byteSize); + NotifyStencilUpload(params.fb_address, byteSize, true); // TODO: Is it worth trying to upload the depth buffer? } @@ -680,7 +679,8 @@ void FramebufferManagerCommon::NotifyVideoUpload(u32 addr, int size, int width, } void FramebufferManagerCommon::UpdateFromMemory(u32 addr, int size, bool safe) { - addr &= ~0x40000000; + // Take off the uncached flag from the address. Not to be confused with the start of VRAM. + addr &= 0x3FFFFFFF; // TODO: Could go through all FBOs, but probably not important? // TODO: Could also check for inner changes, but video is most important. bool isDisplayBuf = addr == DisplayFramebufAddr() || addr == PrevDisplayFramebufAddr(); @@ -700,7 +700,7 @@ void FramebufferManagerCommon::UpdateFromMemory(u32 addr, int size, bool safe) { // If we're not rendering to it, format may be wrong. Use displayFormat_ instead. fmt = displayFormat_; } - DrawPixels(vfb, 0, 0, Memory::GetPointer(addr | 0x04000000), fmt, vfb->fb_stride, vfb->width, vfb->height); + DrawPixels(vfb, 0, 0, Memory::GetPointer(addr), fmt, vfb->fb_stride, vfb->width, vfb->height); SetColorUpdated(vfb, gstate_c.skipDrawReason); } else { INFO_LOG(FRAMEBUF, "Invalidating FBO for %08x (%i x %i x %i)", vfb->fb_address, vfb->width, vfb->height, vfb->format); @@ -866,11 +866,13 @@ void FramebufferManagerCommon::CopyDisplayToOutput() { VirtualFramebuffer *vfb = GetVFBAt(displayFramebufPtr_); if (!vfb) { - // Let's search for a framebuf within this range. - const u32 addr = (displayFramebufPtr_ & 0x03FFFFFF) | 0x04000000; + // Let's search for a framebuf within this range. Note that we also look for + // "framebuffers" sitting in RAM so we only take off the kernel and uncached bits of the address + // when comparing. + const u32 addr = displayFramebufPtr_ & 0x3FFFFFFF; for (size_t i = 0; i < vfbs_.size(); ++i) { VirtualFramebuffer *v = vfbs_[i]; - const u32 v_addr = (v->fb_address & 0x03FFFFFF) | 0x04000000; + const u32 v_addr = v->fb_address & 0x3FFFFFFF; const u32 v_size = FramebufferByteSize(v); if (addr >= v_addr && addr < v_addr + v_size) { const u32 dstBpp = v->format == GE_FORMAT_8888 ? 4 : 2; @@ -1241,7 +1243,8 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, continue; } - const u32 vfb_address = (0x04000000 | vfb->fb_address) & 0x3FFFFFFF; + // We only remove the kernel and uncached bits when comparing. + const u32 vfb_address = vfb->fb_address & 0x3FFFFFFF; const u32 vfb_size = FramebufferByteSize(vfb); const u32 vfb_bpp = vfb->format == GE_FORMAT_8888 ? 4 : 2; const u32 vfb_byteStride = vfb->fb_stride * vfb_bpp; @@ -1352,7 +1355,7 @@ void FramebufferManagerCommon::FindTransferFramebuffers(VirtualFramebuffer *&dst for (size_t i = 0; i < vfbs_.size(); ++i) { VirtualFramebuffer *vfb = vfbs_[i]; - const u32 vfb_address = (0x04000000 | vfb->fb_address) & 0x3FFFFFFF; + const u32 vfb_address = vfb->fb_address & 0x3FFFFFFF; const u32 vfb_size = FramebufferByteSize(vfb); const u32 vfb_bpp = vfb->format == GE_FORMAT_8888 ? 4 : 2; const u32 vfb_byteStride = vfb->fb_stride * vfb_bpp; @@ -1915,7 +1918,7 @@ bool FramebufferManagerCommon::GetFramebuffer(u32 fb_address, int fb_stride, GEB if (!vfb) { // If there's no vfb and we're drawing there, must be memory? - buffer = GPUDebugBuffer(Memory::GetPointer(fb_address | 0x04000000), fb_stride, 512, format); + buffer = GPUDebugBuffer(Memory::GetPointer(fb_address), fb_stride, 512, format); return true; } @@ -1969,7 +1972,7 @@ bool FramebufferManagerCommon::GetDepthbuffer(u32 fb_address, int fb_stride, u32 if (!vfb) { // If there's no vfb and we're drawing there, must be memory? - buffer = GPUDebugBuffer(Memory::GetPointer(z_address | 0x04000000), z_stride, 512, GPU_DBG_FORMAT_16BIT); + buffer = GPUDebugBuffer(Memory::GetPointer(z_address), z_stride, 512, GPU_DBG_FORMAT_16BIT); return true; } @@ -2005,7 +2008,7 @@ bool FramebufferManagerCommon::GetStencilbuffer(u32 fb_address, int fb_stride, G if (!vfb) { // If there's no vfb and we're drawing there, must be memory? // TODO: Actually get the stencil. - buffer = GPUDebugBuffer(Memory::GetPointer(fb_address | 0x04000000), fb_stride, 512, GPU_DBG_FORMAT_8888); + buffer = GPUDebugBuffer(Memory::GetPointer(fb_address), fb_stride, 512, GPU_DBG_FORMAT_8888); return true; } @@ -2057,7 +2060,7 @@ void FramebufferManagerCommon::PackFramebufferSync_(VirtualFramebuffer *vfb, int return; } - const u32 fb_address = (0x04000000) | vfb->fb_address; + const u32 fb_address = vfb->fb_address & 0x3FFFFFFF; Draw::DataFormat destFormat = GEFormatToThin3D(vfb->format); const int dstBpp = (int)DataFormatSizeInBytes(destFormat); diff --git a/GPU/Common/FramebufferCommon.h b/GPU/Common/FramebufferCommon.h index 4f19debd01..9397c94b0a 100644 --- a/GPU/Common/FramebufferCommon.h +++ b/GPU/Common/FramebufferCommon.h @@ -119,7 +119,6 @@ struct VirtualFramebuffer { }; struct FramebufferHeuristicParams { - u32 fb_addr; u32 fb_address; int fb_stride; u32 z_address; @@ -243,10 +242,10 @@ public: size_t NumVFBs() const { return vfbs_.size(); } u32 PrevDisplayFramebufAddr() { - return prevDisplayFramebuf_ ? (0x04000000 | prevDisplayFramebuf_->fb_address) : 0; + return prevDisplayFramebuf_ ? prevDisplayFramebuf_->fb_address : 0; } u32 DisplayFramebufAddr() { - return displayFramebuf_ ? (0x04000000 | displayFramebuf_->fb_address) : 0; + return displayFramebuf_ ? displayFramebuf_->fb_address : 0; } u32 DisplayFramebufStride() { diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 1409a6b403..9889fda271 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -635,9 +635,9 @@ void TextureCacheCommon::HandleTextureChange(TexCacheEntry *const entry, const c } void TextureCacheCommon::NotifyFramebuffer(u32 address, VirtualFramebuffer *framebuffer, FramebufferNotification msg) { - // Must be in VRAM so | 0x04000000 it is. Also, ignore memory mirrors. + // Mask to ignore the Z memory mirrors. // These checks are mainly to reduce scanning all textures. - const u32 addr = (address | 0x04000000) & 0x3F9FFFFF; + const u32 addr = address & 0x3F9FFFFF; const u32 bpp = framebuffer->format == GE_FORMAT_8888 ? 4 : 2; const u64 cacheKey = (u64)addr << 32; // If it has a clut, those are the low 32 bits, so it'll be inside this range. @@ -750,8 +750,7 @@ bool TextureCacheCommon::AttachFramebuffer(TexCacheEntry *entry, u32 address, Vi AttachedFramebufferInfo fbInfo = { 0 }; const u64 mirrorMask = 0x00600000; - // Must be in VRAM so | 0x04000000 it is. Also, ignore memory mirrors. - const u32 addr = (address | 0x04000000) & 0x3FFFFFFF & ~mirrorMask; + const u32 addr = (address & 0x3FFFFFFF) & ~mirrorMask; const u32 texaddr = ((entry->addr + texaddrOffset) & ~mirrorMask); const bool noOffset = texaddr == addr; const bool exactMatch = noOffset && entry->format < 4; @@ -990,7 +989,7 @@ void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) { clutRenderOffset_ = MAX_CLUT_OFFSET; for (size_t i = 0, n = fbCache_.size(); i < n; ++i) { auto framebuffer = fbCache_[i]; - const u32 fb_address = framebuffer->fb_address | 0x04000000; + const u32 fb_address = framebuffer->fb_address & 0x3FFFFFFF; const u32 bpp = framebuffer->drawnFormat == GE_FORMAT_8888 ? 4 : 2; u32 offset = clutFramebufAddr - fb_address; diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index bb6ee6b660..01bfd06fb6 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -687,7 +687,7 @@ void FramebufferManagerD3D11::PackDepthbuffer(VirtualFramebuffer *vfb, int x, in return; } - const u32 z_address = (0x04000000) | vfb->z_address; + const u32 z_address = vfb->z_address; // TODO } diff --git a/GPU/Directx9/FramebufferDX9.cpp b/GPU/Directx9/FramebufferDX9.cpp index 88bddb3bee..75a3beeb3a 100644 --- a/GPU/Directx9/FramebufferDX9.cpp +++ b/GPU/Directx9/FramebufferDX9.cpp @@ -585,7 +585,7 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { return; } - const u32 fb_address = (0x04000000) | vfb->fb_address; + const u32 fb_address = vfb->fb_address & 0x3FFFFFFF; const int dstBpp = vfb->format == GE_FORMAT_8888 ? 4 : 2; // We always need to convert from the framebuffer native format. @@ -627,7 +627,7 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { } // We always read the depth buffer in 24_8 format. - const u32 z_address = (0x04000000) | vfb->z_address; + const u32 z_address = vfb->z_address; DEBUG_LOG(FRAMEBUF, "Reading depthbuffer to mem at %08x for vfb=%08x", z_address, vfb->fb_address); @@ -732,7 +732,7 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { if (!vfb) { // If there's no vfb and we're drawing there, must be memory? - buffer = GPUDebugBuffer(Memory::GetPointer(fb_address | 0x04000000), fb_stride, 512, fb_format); + buffer = GPUDebugBuffer(Memory::GetPointer(fb_address), fb_stride, 512, fb_format); return true; } LPDIRECT3DSURFACE9 renderTarget = vfb->fbo ? (LPDIRECT3DSURFACE9)draw_->GetFramebufferAPITexture(vfb->fbo, Draw::FB_COLOR_BIT | Draw::FB_SURFACE_BIT, 0) : nullptr; @@ -809,7 +809,7 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { if (!vfb) { // If there's no vfb and we're drawing there, must be memory? - buffer = GPUDebugBuffer(Memory::GetPointer(z_address | 0x04000000), z_stride, 512, GPU_DBG_FORMAT_16BIT); + buffer = GPUDebugBuffer(Memory::GetPointer(z_address), z_stride, 512, GPU_DBG_FORMAT_16BIT); return true; } @@ -847,7 +847,7 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { if (!vfb) { // If there's no vfb and we're drawing there, must be memory? - buffer = GPUDebugBuffer(Memory::GetPointer(vfb->z_address | 0x04000000), vfb->z_stride, 512, GPU_DBG_FORMAT_16BIT); + buffer = GPUDebugBuffer(Memory::GetPointer(vfb->z_address), vfb->z_stride, 512, GPU_DBG_FORMAT_16BIT); return true; } diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index a2bb108860..30f71fdd99 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -311,7 +311,7 @@ void DrawEngineGLES::DoFlush() { gstate_c.Clean(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); textureNeedsApply = true; } else if (gstate.getTextureAddress(0) == ((gstate.getFrameBufRawAddress() | 0x04000000) & 0x3FFFFFFF)) { - // This catches the case of clearing a texture. + // This catches the case of clearing a texture. (#10957) gstate_c.Dirty(DIRTY_TEXTURE_IMAGE); } From 15f2e48887de92cf3ed61dd2aab212bb0d24a0a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 12 Nov 2018 07:41:01 +0100 Subject: [PATCH 107/347] Only mask away Z mirrors if inside VRAM --- GPU/Common/TextureCacheCommon.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 9889fda271..2da10add47 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -635,9 +635,10 @@ void TextureCacheCommon::HandleTextureChange(TexCacheEntry *const entry, const c } void TextureCacheCommon::NotifyFramebuffer(u32 address, VirtualFramebuffer *framebuffer, FramebufferNotification msg) { - // Mask to ignore the Z memory mirrors. + // Mask to ignore the Z memory mirrors if the address is in VRAM. // These checks are mainly to reduce scanning all textures. - const u32 addr = address & 0x3F9FFFFF; + const u32 mirrorMask = 0x00600000; + const u32 addr = Memory::IsVRAMAddress(address) ? (address & ~mirrorMask) : address; const u32 bpp = framebuffer->format == GE_FORMAT_8888 ? 4 : 2; const u64 cacheKey = (u64)addr << 32; // If it has a clut, those are the low 32 bits, so it'll be inside this range. @@ -749,9 +750,13 @@ bool TextureCacheCommon::AttachFramebuffer(TexCacheEntry *entry, u32 address, Vi AttachedFramebufferInfo fbInfo = { 0 }; - const u64 mirrorMask = 0x00600000; - const u32 addr = (address & 0x3FFFFFFF) & ~mirrorMask; - const u32 texaddr = ((entry->addr + texaddrOffset) & ~mirrorMask); + const u32 mirrorMask = 0x00600000; + u32 addr = address & 0x3FFFFFFF; + u32 texaddr = entry->addr + texaddrOffset; + if (entry->addr & 0x04000000) { + addr &= ~mirrorMask; + texaddr &= ~mirrorMask; + } const bool noOffset = texaddr == addr; const bool exactMatch = noOffset && entry->format < 4; const u32 w = 1 << ((entry->dim >> 0) & 0xf); From b17fc67c45a658959d6128c8c6f057e76b544fef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 12 Nov 2018 07:48:30 +0100 Subject: [PATCH 108/347] Get rid of MaskedEqual --- GPU/Common/FramebufferCommon.cpp | 10 +++------- GPU/Common/FramebufferCommon.h | 1 - GPU/D3D11/StencilBufferD3D11.cpp | 3 ++- GPU/Directx9/StencilBufferDX9.cpp | 3 ++- GPU/GLES/StencilBufferGLES.cpp | 3 ++- GPU/Vulkan/StencilBufferVulkan.cpp | 3 ++- 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index c654f3f7ce..355d1d4506 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -172,24 +172,20 @@ void FramebufferManagerCommon::SetDisplayFramebuffer(u32 framebuf, u32 stride, G } VirtualFramebuffer *FramebufferManagerCommon::GetVFBAt(u32 addr) { + addr &= 0x3FFFFFFF; VirtualFramebuffer *match = nullptr; for (size_t i = 0; i < vfbs_.size(); ++i) { VirtualFramebuffer *v = vfbs_[i]; - if (MaskedEqual(v->fb_address, addr)) { + if (v->fb_address == addr) { // Could check w too but whatever if (match == nullptr || match->last_frame_render < v->last_frame_render) { match = v; } } } - return match; } -bool FramebufferManagerCommon::MaskedEqual(u32 addr1, u32 addr2) { - return (addr1 & 0x03FFFFFF) == (addr2 & 0x03FFFFFF); -} - u32 FramebufferManagerCommon::FramebufferByteSize(const VirtualFramebuffer *vfb) const { return vfb->fb_stride * vfb->height * (vfb->format == GE_FORMAT_8888 ? 4 : 2); } @@ -691,7 +687,7 @@ void FramebufferManagerCommon::UpdateFromMemory(u32 addr, int size, bool safe) { for (size_t i = 0; i < vfbs_.size(); ++i) { VirtualFramebuffer *vfb = vfbs_[i]; - if (MaskedEqual(vfb->fb_address, addr)) { + if (vfb->fb_address == addr) { FlushBeforeCopy(); if (useBufferedRendering_ && vfb->fbo) { diff --git a/GPU/Common/FramebufferCommon.h b/GPU/Common/FramebufferCommon.h index 9397c94b0a..9f3f6d7251 100644 --- a/GPU/Common/FramebufferCommon.h +++ b/GPU/Common/FramebufferCommon.h @@ -331,7 +331,6 @@ protected: void EstimateDrawingSize(u32 fb_address, GEBufferFormat fb_format, int viewport_width, int viewport_height, int region_width, int region_height, int scissor_width, int scissor_height, int fb_stride, int &drawing_width, int &drawing_height); u32 FramebufferByteSize(const VirtualFramebuffer *vfb) const; - static bool MaskedEqual(u32 addr1, u32 addr2); void NotifyRenderFramebufferCreated(VirtualFramebuffer *vfb); void NotifyRenderFramebufferUpdated(VirtualFramebuffer *vfb, bool vfbFormatChanged); diff --git a/GPU/D3D11/StencilBufferD3D11.cpp b/GPU/D3D11/StencilBufferD3D11.cpp index f489f5838a..7c9e791cca 100644 --- a/GPU/D3D11/StencilBufferD3D11.cpp +++ b/GPU/D3D11/StencilBufferD3D11.cpp @@ -71,6 +71,7 @@ VS_OUT main(VS_IN In) { // TODO : If SV_StencilRef is available (D3D11.3) then this can be done in a single pass. bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZero) { + addr &= 0x3FFFFFFF; if (!MayIntersectFramebuffer(addr)) { return false; } @@ -78,7 +79,7 @@ bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZ VirtualFramebuffer *dstBuffer = 0; for (size_t i = 0; i < vfbs_.size(); ++i) { VirtualFramebuffer *vfb = vfbs_[i]; - if (MaskedEqual(vfb->fb_address, addr)) { + if (vfb->fb_address == addr) { dstBuffer = vfb; } } diff --git a/GPU/Directx9/StencilBufferDX9.cpp b/GPU/Directx9/StencilBufferDX9.cpp index 6f51582cf2..c6823cba63 100644 --- a/GPU/Directx9/StencilBufferDX9.cpp +++ b/GPU/Directx9/StencilBufferDX9.cpp @@ -65,6 +65,7 @@ static const char *stencil_vs = "}\n"; bool FramebufferManagerDX9::NotifyStencilUpload(u32 addr, int size, bool skipZero) { + addr &= 0x3FFFFFFF; if (!MayIntersectFramebuffer(addr)) { return false; } @@ -72,7 +73,7 @@ bool FramebufferManagerDX9::NotifyStencilUpload(u32 addr, int size, bool skipZer VirtualFramebuffer *dstBuffer = 0; for (size_t i = 0; i < vfbs_.size(); ++i) { VirtualFramebuffer *vfb = vfbs_[i]; - if (MaskedEqual(vfb->fb_address, addr)) { + if (vfb->fb_address == addr) { dstBuffer = vfb; } } diff --git a/GPU/GLES/StencilBufferGLES.cpp b/GPU/GLES/StencilBufferGLES.cpp index dee08b4577..17d7469dfa 100644 --- a/GPU/GLES/StencilBufferGLES.cpp +++ b/GPU/GLES/StencilBufferGLES.cpp @@ -62,6 +62,7 @@ static const char *stencil_vs = "}\n"; bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZero) { + addr &= 0x3FFFFFFF; if (!MayIntersectFramebuffer(addr)) { return false; } @@ -69,7 +70,7 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZe VirtualFramebuffer *dstBuffer = 0; for (size_t i = 0; i < vfbs_.size(); ++i) { VirtualFramebuffer *vfb = vfbs_[i]; - if (MaskedEqual(vfb->fb_address, addr)) { + if (vfb->fb_address == addr) { dstBuffer = vfb; } } diff --git a/GPU/Vulkan/StencilBufferVulkan.cpp b/GPU/Vulkan/StencilBufferVulkan.cpp index cf046fe43e..bbf4a6abef 100644 --- a/GPU/Vulkan/StencilBufferVulkan.cpp +++ b/GPU/Vulkan/StencilBufferVulkan.cpp @@ -97,6 +97,7 @@ void main() { // messing about with bitplane textures and the like. Or actually, maybe not... Let's start with // the traditional approach. bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, bool skipZero) { + addr &= 0x3FFFFFFF; if (!MayIntersectFramebuffer(addr)) { return false; } @@ -104,7 +105,7 @@ bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, bool skip VirtualFramebuffer *dstBuffer = 0; for (size_t i = 0; i < vfbs_.size(); ++i) { VirtualFramebuffer *vfb = vfbs_[i]; - if (MaskedEqual(vfb->fb_address, addr)) { + if (vfb->fb_address == addr) { dstBuffer = vfb; } } From cf653b763123985089982f300e901a3d012c285c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 12 Nov 2018 07:52:58 +0100 Subject: [PATCH 109/347] No need for fb_normalized_address --- GPU/Common/FramebufferCommon.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index 355d1d4506..582644a4a6 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -249,11 +249,10 @@ void FramebufferManagerCommon::EstimateDrawingSize(u32 fb_address, GEBufferForma if (viewport_width != region_width) { // The majority of the time, these are equal. If not, let's check what we know. - const u32 fb_normalized_address = fb_address & 0x3FFFFFFF; u32 nearest_address = 0xFFFFFFFF; for (size_t i = 0; i < vfbs_.size(); ++i) { const u32 other_address = vfbs_[i]->fb_address & 0x3FFFFFFF; - if (other_address > fb_normalized_address && other_address < nearest_address) { + if (other_address > fb_address && other_address < nearest_address) { nearest_address = other_address; } } @@ -262,7 +261,7 @@ void FramebufferManagerCommon::EstimateDrawingSize(u32 fb_address, GEBufferForma // This catches some cases where we can know this. // Hmm. The problem is that we could only catch it for the first of two buffers... const u32 bpp = fb_format == GE_FORMAT_8888 ? 4 : 2; - int avail_height = (nearest_address - fb_normalized_address) / (fb_stride * bpp); + int avail_height = (nearest_address - fb_address) / (fb_stride * bpp); if (avail_height < drawing_height && avail_height == region_height) { drawing_width = std::min(region_width, fb_stride); drawing_height = avail_height; From 7abbc1bebdcb3b160dd5bf4db2e3207f8b1c5ecf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 5 Nov 2018 00:28:01 +0100 Subject: [PATCH 110/347] Add compat flag to allow virtual framebuffer readbacks (auto-create fb from readback destination). Does not yet work outside VRAM but should fix Digimon Adventure. --- Core/Compatibility.cpp | 1 + Core/Compatibility.h | 1 + GPU/Common/FramebufferCommon.cpp | 39 +++++++++++++++++++++++++++++--- GPU/Common/FramebufferCommon.h | 2 +- assets/compat.ini | 8 ++++++- 5 files changed, 46 insertions(+), 5 deletions(-) diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp index 1cc0ccb219..692993973c 100644 --- a/Core/Compatibility.cpp +++ b/Core/Compatibility.cpp @@ -59,6 +59,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "DisableAccurateDepth", &flags_.DisableAccurateDepth); CheckSetting(iniFile, gameID, "MGS2AcidHack", &flags_.MGS2AcidHack); CheckSetting(iniFile, gameID, "SonicRivalsHack", &flags_.SonicRivalsHack); + CheckSetting(iniFile, gameID, "BlockTransferAllowCreateFB", &flags_.BlockTransferAllowCreateFB); } void Compatibility::CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag) { diff --git a/Core/Compatibility.h b/Core/Compatibility.h index f65c68efda..97373b9418 100644 --- a/Core/Compatibility.h +++ b/Core/Compatibility.h @@ -59,6 +59,7 @@ struct CompatFlags { bool DisableAccurateDepth; bool MGS2AcidHack; bool SonicRivalsHack; + bool BlockTransferAllowCreateFB; }; class IniFile; diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index 582644a4a6..7f8a85c3a5 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -412,8 +412,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame // None found? Create one. if (!vfb) { - vfb = new VirtualFramebuffer(); - memset(vfb, 0, sizeof(VirtualFramebuffer)); + vfb = new VirtualFramebuffer{}; vfb->fbo = nullptr; vfb->fb_address = params.fb_address; vfb->fb_stride = params.fb_stride; @@ -1282,6 +1281,7 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, // MotoGP workaround - it copies a framebuffer to memory and then displays it. // TODO: It's rare anyway, but the game could modify the RAM and then we'd display the wrong thing. // Unfortunately, that would force 1x render resolution. + // NOTE: With the BlockTransferAllowCreateFB hack, we might be able to remove this. if (Memory::IsRAMAddress(dst)) { knownFramebufferRAMCopies_.insert(std::pair(src, dst)); } @@ -1337,7 +1337,8 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, } } -void FramebufferManagerCommon::FindTransferFramebuffers(VirtualFramebuffer *&dstBuffer, VirtualFramebuffer *&srcBuffer, u32 dstBasePtr, int dstStride, int &dstX, int &dstY, u32 srcBasePtr, int srcStride, int &srcX, int &srcY, int &srcWidth, int &srcHeight, int &dstWidth, int &dstHeight, int bpp) const { +// Can't be const, in case it has to create a vfb unfortunately. +void FramebufferManagerCommon::FindTransferFramebuffers(VirtualFramebuffer *&dstBuffer, VirtualFramebuffer *&srcBuffer, u32 dstBasePtr, int dstStride, int &dstX, int &dstY, u32 srcBasePtr, int srcStride, int &srcX, int &srcY, int &srcWidth, int &srcHeight, int &dstWidth, int &dstHeight, int bpp) { u32 dstYOffset = -1; u32 dstXOffset = -1; u32 srcYOffset = -1; @@ -1417,6 +1418,38 @@ void FramebufferManagerCommon::FindTransferFramebuffers(VirtualFramebuffer *&dst } } + if (!dstBuffer && PSP_CoreParameter().compat.flags().BlockTransferAllowCreateFB) { + float renderWidthFactor = renderWidth_ / 480.0f; + float renderHeightFactor = renderHeight_ / 272.0f; + // A target for the destination is missing - so just create one! + // Make sure this one would be found by the algorithm above so we wouldn't + // create a new one each frame. + VirtualFramebuffer *vfb = new VirtualFramebuffer{}; + vfb->fbo = nullptr; + vfb->fb_address = dstBasePtr; // NOTE - not necessarily in VRAM! + vfb->fb_stride = dstStride; + vfb->z_address = 0; + vfb->z_stride =0; + vfb->width = std::max(dstWidth, dstStride); + vfb->height = dstHeight; + vfb->newWidth = vfb->width; + vfb->newHeight = vfb->height; + vfb->lastFrameNewSize = gpuStats.numFlips; + vfb->renderWidth = (u16)(vfb->width * renderWidthFactor); + vfb->renderHeight = (u16)(vfb->height * renderHeightFactor); + vfb->bufferWidth = vfb->width; + vfb->bufferHeight = vfb->height; + vfb->format = bpp == 4 ? GE_FORMAT_8888 : GE_FORMAT_5551; // TODO: We don't really know the 16-bit format here.. at all. Can only guess when it gets used later! + vfb->drawnFormat = GE_FORMAT_8888; + vfb->usageFlags = FB_USAGE_RENDERTARGET; + SetColorUpdated(vfb, 0); + textureCache_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_CREATED); + vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, (Draw::FBColorDepth)vfb->colorDepth }); + vfbs_.push_back(vfb); + dstBuffer = vfb; + } + dstBuffer->last_frame_used = gpuStats.numFlips; + if (dstYOffset != (u32)-1) { dstY += dstYOffset; dstX += dstXOffset; diff --git a/GPU/Common/FramebufferCommon.h b/GPU/Common/FramebufferCommon.h index 9f3f6d7251..68580d9b46 100644 --- a/GPU/Common/FramebufferCommon.h +++ b/GPU/Common/FramebufferCommon.h @@ -344,7 +344,7 @@ protected: bool ShouldDownloadFramebuffer(const VirtualFramebuffer *vfb) const; void DownloadFramebufferOnSwitch(VirtualFramebuffer *vfb); - void FindTransferFramebuffers(VirtualFramebuffer *&dstBuffer, VirtualFramebuffer *&srcBuffer, u32 dstBasePtr, int dstStride, int &dstX, int &dstY, u32 srcBasePtr, int srcStride, int &srcX, int &srcY, int &srcWidth, int &srcHeight, int &dstWidth, int &dstHeight, int bpp) const; + void FindTransferFramebuffers(VirtualFramebuffer *&dstBuffer, VirtualFramebuffer *&srcBuffer, u32 dstBasePtr, int dstStride, int &dstX, int &dstY, u32 srcBasePtr, int srcStride, int &srcX, int &srcY, int &srcWidth, int &srcHeight, int &dstWidth, int &dstHeight, int bpp); VirtualFramebuffer *FindDownloadTempBuffer(VirtualFramebuffer *vfb); virtual bool CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) = 0; virtual void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) = 0; diff --git a/assets/compat.ini b/assets/compat.ini index 72ac34b4c9..69e6f10a69 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -339,4 +339,10 @@ ULUS10077 = true ULES00622 = true # SR1 ULUS10195 = true # SR1 ULUS10323 = true # SR2 -ULES00940 = true # SR2 \ No newline at end of file +ULES00940 = true # SR2 + +[BlockTransferAllowCreateFB] +NPJH50686 = true # Digimon Adventures (JP) +ULJS00078 = true # MotoGP +ULUS10153 = true # MotoGP +UCES00373 = true # MotoGP From 6269d9b893470c89cf7657529533fb9e4ac4b004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 11 Nov 2018 22:50:15 +0100 Subject: [PATCH 111/347] Support virtual readbacks for detected-memcpy framebuffer copies, delete MotoGP hack. --- GPU/Common/FramebufferCommon.cpp | 96 ++++++++++++++++---------------- GPU/Common/FramebufferCommon.h | 3 +- assets/compat.ini | 2 +- 3 files changed, 52 insertions(+), 49 deletions(-) diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index 7f8a85c3a5..88986a1082 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -903,14 +903,6 @@ void FramebufferManagerCommon::CopyDisplayToOutput() { if (!vfb) { if (Memory::IsValidAddress(displayFramebufPtr_)) { // The game is displaying something directly from RAM. In GTA, it's decoded video. - - // First check that it's not a known RAM copy of a VRAM framebuffer though, as in MotoGP - for (auto iter = knownFramebufferRAMCopies_.begin(); iter != knownFramebufferRAMCopies_.end(); ++iter) { - if (iter->second == displayFramebufPtr_) { - vfb = GetVFBAt(iter->first); - } - } - if (!vfb) { shaderManager_->DirtyLastShader(); if (useBufferedRendering_) { @@ -1217,6 +1209,8 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, } } +// This is called from detected memcopies only. Not block transfers. +// MotoGP goes this path so we need to catch those copies here. bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, bool isMemset, u32 skipDrawReason) { if (size == 0) { return false; @@ -1277,16 +1271,6 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, } } - if (srcBuffer && srcY == 0 && srcH == srcBuffer->height && !dstBuffer) { - // MotoGP workaround - it copies a framebuffer to memory and then displays it. - // TODO: It's rare anyway, but the game could modify the RAM and then we'd display the wrong thing. - // Unfortunately, that would force 1x render resolution. - // NOTE: With the BlockTransferAllowCreateFB hack, we might be able to remove this. - if (Memory::IsRAMAddress(dst)) { - knownFramebufferRAMCopies_.insert(std::pair(src, dst)); - } - } - if (!useBufferedRendering_) { // If we're copying into a recently used display buf, it's probably destined for the screen. if (srcBuffer || (dstBuffer != displayFramebuf_ && dstBuffer != prevDisplayFramebuf_)) { @@ -1294,6 +1278,14 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, } } + if (!dstBuffer && srcBuffer && PSP_CoreParameter().compat.flags().BlockTransferAllowCreateFB) { + dstBuffer = CreateRAMFramebuffer(dst, srcBuffer->width, srcBuffer->height, srcBuffer->fb_stride, srcBuffer->format); + dstY = 0; + } + if (dstBuffer) { + dstBuffer->last_frame_used = gpuStats.numFlips; + } + if (dstBuffer && srcBuffer && !isMemset) { if (srcBuffer == dstBuffer) { WARN_LOG_REPORT_ONCE(dstsrccpy, G3D, "Intra-buffer memcpy (not supported) %08x -> %08x", src, dst); @@ -1419,36 +1411,14 @@ void FramebufferManagerCommon::FindTransferFramebuffers(VirtualFramebuffer *&dst } if (!dstBuffer && PSP_CoreParameter().compat.flags().BlockTransferAllowCreateFB) { - float renderWidthFactor = renderWidth_ / 480.0f; - float renderHeightFactor = renderHeight_ / 272.0f; - // A target for the destination is missing - so just create one! - // Make sure this one would be found by the algorithm above so we wouldn't - // create a new one each frame. - VirtualFramebuffer *vfb = new VirtualFramebuffer{}; - vfb->fbo = nullptr; - vfb->fb_address = dstBasePtr; // NOTE - not necessarily in VRAM! - vfb->fb_stride = dstStride; - vfb->z_address = 0; - vfb->z_stride =0; - vfb->width = std::max(dstWidth, dstStride); - vfb->height = dstHeight; - vfb->newWidth = vfb->width; - vfb->newHeight = vfb->height; - vfb->lastFrameNewSize = gpuStats.numFlips; - vfb->renderWidth = (u16)(vfb->width * renderWidthFactor); - vfb->renderHeight = (u16)(vfb->height * renderHeightFactor); - vfb->bufferWidth = vfb->width; - vfb->bufferHeight = vfb->height; - vfb->format = bpp == 4 ? GE_FORMAT_8888 : GE_FORMAT_5551; // TODO: We don't really know the 16-bit format here.. at all. Can only guess when it gets used later! - vfb->drawnFormat = GE_FORMAT_8888; - vfb->usageFlags = FB_USAGE_RENDERTARGET; - SetColorUpdated(vfb, 0); - textureCache_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_CREATED); - vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, (Draw::FBColorDepth)vfb->colorDepth }); - vfbs_.push_back(vfb); - dstBuffer = vfb; + GEBufferFormat ramFormat = bpp == 4 ? GE_FORMAT_8888 : GE_FORMAT_5551; + // TODO: We don't really know the 16-bit format here.. at all. Can only guess when it gets used later! + // But actually, the format of the source buffer is probably not a bad guess.. + dstBuffer = CreateRAMFramebuffer(dstBasePtr, dstWidth, dstHeight, dstStride, ramFormat); } - dstBuffer->last_frame_used = gpuStats.numFlips; + + if (dstBuffer) + dstBuffer->last_frame_used = gpuStats.numFlips; if (dstYOffset != (u32)-1) { dstY += dstYOffset; @@ -1460,6 +1430,38 @@ void FramebufferManagerCommon::FindTransferFramebuffers(VirtualFramebuffer *&dst } } +VirtualFramebuffer *FramebufferManagerCommon::CreateRAMFramebuffer(uint32_t fbAddress, int width, int height, int stride, GEBufferFormat format) { + float renderWidthFactor = renderWidth_ / 480.0f; + float renderHeightFactor = renderHeight_ / 272.0f; + + // A target for the destination is missing - so just create one! + // Make sure this one would be found by the algorithm above so we wouldn't + // create a new one each frame. + VirtualFramebuffer *vfb = new VirtualFramebuffer{}; + vfb->fbo = nullptr; + vfb->fb_address = fbAddress; // NOTE - not necessarily in VRAM! + vfb->fb_stride = stride; + vfb->z_address = 0; // marks that if anyone tries to render to this framebuffer, it should be dropped and recreated. + vfb->z_stride = 0; + vfb->width = std::max(width, stride); + vfb->height = height; + vfb->newWidth = vfb->width; + vfb->newHeight = vfb->height; + vfb->lastFrameNewSize = gpuStats.numFlips; + vfb->renderWidth = (u16)(vfb->width * renderWidthFactor); + vfb->renderHeight = (u16)(vfb->height * renderHeightFactor); + vfb->bufferWidth = vfb->width; + vfb->bufferHeight = vfb->height; + vfb->format = format; + vfb->drawnFormat = GE_FORMAT_8888; + vfb->usageFlags = FB_USAGE_RENDERTARGET; + SetColorUpdated(vfb, 0); + textureCache_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_CREATED); + vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, (Draw::FBColorDepth)vfb->colorDepth }); + vfbs_.push_back(vfb); + return vfb; +} + // 1:1 pixel sides buffers, we resize buffers to these before we read them back. VirtualFramebuffer *FramebufferManagerCommon::FindDownloadTempBuffer(VirtualFramebuffer *vfb) { // For now we'll keep these on the same struct as the ones that can get displayed diff --git a/GPU/Common/FramebufferCommon.h b/GPU/Common/FramebufferCommon.h index 68580d9b46..e2ee170f0e 100644 --- a/GPU/Common/FramebufferCommon.h +++ b/GPU/Common/FramebufferCommon.h @@ -348,6 +348,8 @@ protected: VirtualFramebuffer *FindDownloadTempBuffer(VirtualFramebuffer *vfb); virtual bool CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) = 0; virtual void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) = 0; + + VirtualFramebuffer *CreateRAMFramebuffer(uint32_t fbAddress, int width, int height, int stride, GEBufferFormat format); void OptimizeDownloadRange(VirtualFramebuffer *vfb, int &x, int &y, int &w, int &h); void UpdateFramebufUsage(VirtualFramebuffer *vfb); @@ -391,7 +393,6 @@ protected: std::vector vfbs_; std::vector bvfbs_; // blitting framebuffers (for download) - std::set> knownFramebufferRAMCopies_; bool gameUsesSequentialCopies_ = false; diff --git a/assets/compat.ini b/assets/compat.ini index 69e6f10a69..895db36663 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -342,7 +342,7 @@ ULUS10323 = true # SR2 ULES00940 = true # SR2 [BlockTransferAllowCreateFB] -NPJH50686 = true # Digimon Adventures (JP) +NPJH50686 = true # Digimon Adventures (JP, and English patches...) ULJS00078 = true # MotoGP ULUS10153 = true # MotoGP UCES00373 = true # MotoGP From 32cd6dfae643e63819cd3d3829d3b3a71a6d81b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 11 Nov 2018 23:13:53 +0100 Subject: [PATCH 112/347] Take care of most cases of render-to-virtual-readback-buffer, I think. --- GPU/Common/FramebufferCommon.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index 88986a1082..8675eec848 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -342,6 +342,13 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame vfb->fb_stride = params.fb_stride; vfb->format = params.fmt; } + + if (vfb->z_address == 0 && vfb->z_stride == 0) { + // Got one that was created by CreateRAMFramebuffer. Since it has no depth buffer, + // we just recreate it immediately. + ResizeFramebufFBO(vfb, vfb->width, vfb->height, true); + } + // Keep track, but this isn't really used. vfb->z_stride = params.z_stride; // Heuristic: In throughmode, a higher height could be used. Let's avoid shrinking the buffer. From 04708fe88afab5259f41bfdc0faf98e400146b64 Mon Sep 17 00:00:00 2001 From: xebra Date: Tue, 13 Nov 2018 17:12:41 +0900 Subject: [PATCH 113/347] [spline/bezier]Unify SubmitSpline/Bezier. --- GPU/Common/DrawEngineCommon.h | 4 +- GPU/Common/SplineCommon.cpp | 112 +++------------------------------- GPU/GPUCommon.cpp | 58 ++++++++++-------- GPU/Software/SoftGpu.cpp | 47 ++++++++------ 4 files changed, 73 insertions(+), 148 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 353b3dd7d0..21a3d06b2c 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -81,8 +81,8 @@ public: bool TestBoundingBox(void* control_points, int vertexCount, u32 vertType, int *bytesRead); void SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, int cullMode, int *bytesRead); - void SubmitSpline(const void *control_points, const void *indices, int tess_u, int tess_v, int count_u, int count_v, int type_u, int type_v, GEPatchPrimType prim_type, bool computeNormals, bool patchFacing, u32 vertType, int *bytesRead); - void SubmitBezier(const void *control_points, const void *indices, int tess_u, int tess_v, int count_u, int count_v, GEPatchPrimType prim_type, bool computeNormals, bool patchFacing, u32 vertType, int *bytesRead); + template + void SubmitCurve(const void *control_points, const void *indices, Surface &surface, u32 vertType, int *bytesRead, const char *scope); void ClearSplineBezierWeights(); std::vector DebugGetVertexLoaderIDs(); diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 77427b99ee..73104649e5 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -488,106 +488,23 @@ void DrawEngineCommon::ClearSplineBezierWeights() { Spline3DWeight::weightsCache.Clear(); } -void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indices, int tess_u, int tess_v, int count_u, int count_v, int type_u, int type_v, GEPatchPrimType prim_type, bool computeNormals, bool patchFacing, u32 vertType, int *bytesRead) { - PROFILE_THIS_SCOPE("spline"); - DispatchFlush(); +// Specialize to make instance (to avoid link error). +template void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indices, BezierSurface &surface, u32 vertType, int *bytesRead, const char *scope); +template void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indices, SplineSurface &surface, u32 vertType, int *bytesRead, const char *scope); - // Real hardware seems to draw nothing when given < 4 either U or V. - if (count_u < 4 || count_v < 4) - return; - - SimpleBufferManager managedBuf(decoded, DECODED_VERTEX_BUFFER_SIZE / 2); - - int num_points = count_u * count_v; - u16 index_lower_bound = 0; - u16 index_upper_bound = num_points - 1; - IndexConverter ConvertIndex(vertType, indices); - if (indices) - GetIndexBounds(indices, num_points, vertType, &index_lower_bound, &index_upper_bound); - - VertexDecoder *origVDecoder = GetVertexDecoder((vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24)); - *bytesRead = num_points * origVDecoder->VertexSize(); - - // Simplify away bones and morph before proceeding - SimpleVertex *simplified_control_points = (SimpleVertex *)managedBuf.Allocate(sizeof(SimpleVertex) * (index_upper_bound + 1)); - u8 *temp_buffer = managedBuf.Allocate(sizeof(SimpleVertex) * num_points); - - u32 origVertType = vertType; - vertType = NormalizeVertices((u8 *)simplified_control_points, temp_buffer, (u8 *)control_points, index_lower_bound, index_upper_bound, vertType); - - VertexDecoder *vdecoder = GetVertexDecoder(vertType); - - int vertexSize = vdecoder->VertexSize(); - if (vertexSize != sizeof(SimpleVertex)) { - ERROR_LOG(G3D, "Something went really wrong, vertex size: %i vs %i", vertexSize, (int)sizeof(SimpleVertex)); - } - - // Make an array of pointers to the control points, to get rid of indices. - const SimpleVertex **points = (const SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * num_points); - for (int idx = 0; idx < num_points; idx++) - points[idx] = simplified_control_points + (indices ? ConvertIndex(idx) : idx); - - OutputBuffers output; - output.vertices = (SimpleVertex *)(decoded + DECODED_VERTEX_BUFFER_SIZE / 2); - output.indices = decIndex; - output.count = 0; - - SplineSurface surface; - surface.tess_u = tess_u; - surface.tess_v = tess_v; - surface.type_u = type_u; - surface.type_v = type_v; - surface.num_points_u = count_u; - surface.num_points_v = count_v; - surface.num_patches_u = count_u - 3; - surface.num_patches_v = count_v - 3; - surface.primType = prim_type; - surface.patchFacing = patchFacing; - surface.Init(DECODED_VERTEX_BUFFER_SIZE / 2 / vertexSize); - - if (CanUseHardwareTessellation(prim_type)) { - HardwareTessellation(output, surface, origVertType, points, tessDataTransfer); - } else { - ControlPoints cpoints(points, num_points, managedBuf); - SoftwareTessellation(output, surface, origVertType, cpoints); - } - - u32 vertTypeWithIndex16 = (vertType & ~GE_VTYPE_IDX_MASK) | GE_VTYPE_IDX_16BIT; - - UVScale prevUVScale; - if ((origVertType & GE_VTYPE_TC_MASK) != 0) { - // We scaled during Normalize already so let's turn it off when drawing. - prevUVScale = gstate_c.uv; - gstate_c.uv.uScale = 1.0f; - gstate_c.uv.vScale = 1.0f; - gstate_c.uv.uOff = 0.0f; - gstate_c.uv.vOff = 0.0f; - } - - uint32_t vertTypeID = GetVertTypeID(vertTypeWithIndex16, gstate.getUVGenMode()); - - int generatedBytesRead; - DispatchSubmitPrim(output.vertices, output.indices, PatchPrimToPrim(prim_type), output.count, vertTypeID, &generatedBytesRead); - - DispatchFlush(); - - if ((origVertType & GE_VTYPE_TC_MASK) != 0) { - gstate_c.uv = prevUVScale; - } -} - -void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indices, int tess_u, int tess_v, int count_u, int count_v, GEPatchPrimType prim_type, bool computeNormals, bool patchFacing, u32 vertType, int *bytesRead) { - PROFILE_THIS_SCOPE("bezier"); +template +void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indices, Surface &surface, u32 vertType, int *bytesRead, const char *scope) { + PROFILE_THIS_SCOPE(scope); DispatchFlush(); // Real hardware seems to draw nothing when given < 4 either U or V. // This would result in num_patches_u / num_patches_v being 0. - if (count_u < 4 || count_v < 4) + if (surface.num_points_u < 4 || surface.num_points_v < 4) return; SimpleBufferManager managedBuf(decoded, DECODED_VERTEX_BUFFER_SIZE / 2); - int num_points = count_u * count_v; + int num_points = surface.num_points_u * surface.num_points_v; u16 index_lower_bound = 0; u16 index_upper_bound = num_points - 1; IndexConverter ConvertIndex(vertType, indices); @@ -622,18 +539,9 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi output.indices = decIndex; output.count = 0; - BezierSurface surface; - surface.tess_u = tess_u; - surface.tess_v = tess_v; - surface.num_points_u = count_u; - surface.num_points_v = count_v; - surface.num_patches_u = (count_u - 1) / 3; - surface.num_patches_v = (count_v - 1) / 3; - surface.primType = prim_type; - surface.patchFacing = patchFacing; surface.Init(DECODED_VERTEX_BUFFER_SIZE / 2 / vertexSize); - if (CanUseHardwareTessellation(prim_type)) { + if (CanUseHardwareTessellation(surface.primType)) { HardwareTessellation(output, surface, origVertType, points, tessDataTransfer); } else { ControlPoints cpoints(points, num_points, managedBuf); @@ -654,7 +562,7 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi uint32_t vertTypeID = GetVertTypeID(vertTypeWithIndex16, gstate.getUVGenMode()); int generatedBytesRead; - DispatchSubmitPrim(output.vertices, output.indices, PatchPrimToPrim(prim_type), output.count, vertTypeID, &generatedBytesRead); + DispatchSubmitPrim(output.vertices, output.indices, PatchPrimToPrim(surface.primType), output.count, vertTypeID, &generatedBytesRead); DispatchFlush(); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 2fb07c9ae9..1e58cb2a6e 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1747,33 +1747,37 @@ void GPUCommon::Execute_Bezier(u32 op, u32 diff) { DEBUG_LOG_REPORT(G3D, "Unusual bezier/spline vtype: %08x, morph: %d, bones: %d", gstate.vertType, (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT, vertTypeGetNumBoneWeights(gstate.vertType)); } - GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType(); - SetDrawType(DRAW_BEZIER, PatchPrimToPrim(patchPrim)); + Spline::BezierSurface surface; + surface.tess_u = gstate.getPatchDivisionU(); + surface.tess_v = gstate.getPatchDivisionV(); + surface.num_points_u = op & 0xFF; + surface.num_points_v = (op >> 8) & 0xFF; + surface.num_patches_u = (surface.num_points_u - 1) / 3; + surface.num_patches_v = (surface.num_points_v - 1) / 3; + surface.primType = gstate.getPatchPrimitiveType(); + surface.patchFacing = gstate.patchfacing & 1; - int bz_ucount = op & 0xFF; - int bz_vcount = (op >> 8) & 0xFF; - bool computeNormals = gstate.isLightingEnabled(); - bool patchFacing = gstate.patchfacing & 1; + SetDrawType(DRAW_BEZIER, PatchPrimToPrim(surface.primType)); - if (CanUseHardwareTessellation(patchPrim)) { + if (CanUseHardwareTessellation(surface.primType)) { gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); gstate_c.bezier = true; - if (gstate_c.spline_num_points_u != bz_ucount) { + if (gstate_c.spline_num_points_u != surface.num_points_u) { gstate_c.Dirty(DIRTY_BEZIERSPLINE); - gstate_c.spline_num_points_u = bz_ucount; + gstate_c.spline_num_points_u = surface.num_points_u; } } int bytesRead = 0; UpdateUVScaleOffset(); - drawEngineCommon_->SubmitBezier(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), bz_ucount, bz_vcount, patchPrim, computeNormals, patchFacing, gstate.vertType, &bytesRead); + drawEngineCommon_->SubmitCurve(control_points, indices, surface, gstate.vertType, &bytesRead, "bezier"); if (gstate_c.bezier) gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); gstate_c.bezier = false; // After drawing, we advance pointers - see SubmitPrim which does the same. - int count = bz_ucount * bz_vcount; + int count = surface.num_points_u * surface.num_points_v; AdvanceVerts(gstate.vertType, count, bytesRead); } @@ -1807,35 +1811,39 @@ void GPUCommon::Execute_Spline(u32 op, u32 diff) { DEBUG_LOG_REPORT(G3D, "Unusual bezier/spline vtype: %08x, morph: %d, bones: %d", gstate.vertType, (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT, vertTypeGetNumBoneWeights(gstate.vertType)); } - int sp_ucount = op & 0xFF; - int sp_vcount = (op >> 8) & 0xFF; - int sp_utype = (op >> 16) & 0x3; - int sp_vtype = (op >> 18) & 0x3; - GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType(); - SetDrawType(DRAW_SPLINE, PatchPrimToPrim(patchPrim)); - bool computeNormals = gstate.isLightingEnabled(); - bool patchFacing = gstate.patchfacing & 1; - u32 vertType = gstate.vertType; + Spline::SplineSurface surface; + surface.tess_u = gstate.getPatchDivisionU(); + surface.tess_v = gstate.getPatchDivisionV(); + surface.type_u = (op >> 16) & 0x3; + surface.type_v = (op >> 18) & 0x3; + surface.num_points_u = op & 0xFF; + surface.num_points_v = (op >> 8) & 0xFF; + surface.num_patches_u = surface.num_points_u - 3; + surface.num_patches_v = surface.num_points_v - 3; + surface.primType = gstate.getPatchPrimitiveType(); + surface.patchFacing = gstate.patchfacing & 1; - if (CanUseHardwareTessellation(patchPrim)) { + SetDrawType(DRAW_SPLINE, PatchPrimToPrim(surface.primType)); + + if (CanUseHardwareTessellation(surface.primType)) { gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); gstate_c.spline = true; - if (gstate_c.spline_num_points_u != sp_ucount) { + if (gstate_c.spline_num_points_u != surface.num_points_u) { gstate_c.Dirty(DIRTY_BEZIERSPLINE); - gstate_c.spline_num_points_u = sp_ucount; + gstate_c.spline_num_points_u = surface.num_points_u; } } int bytesRead = 0; UpdateUVScaleOffset(); - drawEngineCommon_->SubmitSpline(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), sp_ucount, sp_vcount, sp_utype, sp_vtype, patchPrim, computeNormals, patchFacing, vertType, &bytesRead); + drawEngineCommon_->SubmitCurve(control_points, indices, surface, gstate.vertType, &bytesRead, "spline"); if (gstate_c.spline) gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); gstate_c.spline = false; // After drawing, we advance pointers - see SubmitPrim which does the same. - int count = sp_ucount * sp_vcount; + int count = surface.num_points_u * surface.num_points_v; AdvanceVerts(gstate.vertType, count, bytesRead); } diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 2673ef4ab2..44771c197b 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -38,6 +38,7 @@ #include "GPU/Software/TransformUnit.h" #include "GPU/Common/DrawEngineCommon.h" #include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/SplineCommon.h" #include "GPU/Debugger/Debugger.h" #include "GPU/Debugger/Record.h" @@ -401,20 +402,24 @@ void SoftGPU::ExecuteOp(u32 op, u32 diff) { DEBUG_LOG_REPORT(G3D, "Unusual bezier/spline vtype: %08x, morph: %d, bones: %d", gstate.vertType, (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT, vertTypeGetNumBoneWeights(gstate.vertType)); } - GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType(); - SetDrawType(DRAW_BEZIER, PatchPrimToPrim(patchPrim)); + Spline::BezierSurface surface; + surface.tess_u = gstate.getPatchDivisionU(); + surface.tess_v = gstate.getPatchDivisionV(); + surface.num_points_u = op & 0xFF; + surface.num_points_v = (op >> 8) & 0xFF; + surface.num_patches_u = (surface.num_points_u - 1) / 3; + surface.num_patches_v = (surface.num_points_v - 1) / 3; + surface.primType = gstate.getPatchPrimitiveType(); + surface.patchFacing = gstate.patchfacing & 1; - int bz_ucount = op & 0xFF; - int bz_vcount = (op >> 8) & 0xFF; - bool computeNormals = gstate.isLightingEnabled(); - bool patchFacing = gstate.patchfacing & 1; + SetDrawType(DRAW_BEZIER, PatchPrimToPrim(surface.primType)); int bytesRead = 0; - drawEngineCommon_->SubmitBezier(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), bz_ucount, bz_vcount, patchPrim, computeNormals, patchFacing, gstate.vertType, &bytesRead); + drawEngineCommon_->SubmitCurve(control_points, indices, surface, gstate.vertType, &bytesRead, "bezier"); framebufferDirty_ = true; // After drawing, we advance pointers - see SubmitPrim which does the same. - int count = bz_ucount * bz_vcount; + int count = surface.num_points_u * surface.num_points_v; AdvanceVerts(gstate.vertType, count, bytesRead); } break; @@ -449,22 +454,26 @@ void SoftGPU::ExecuteOp(u32 op, u32 diff) { DEBUG_LOG_REPORT(G3D, "Unusual bezier/spline vtype: %08x, morph: %d, bones: %d", gstate.vertType, (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT, vertTypeGetNumBoneWeights(gstate.vertType)); } - int sp_ucount = op & 0xFF; - int sp_vcount = (op >> 8) & 0xFF; - int sp_utype = (op >> 16) & 0x3; - int sp_vtype = (op >> 18) & 0x3; - GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType(); - SetDrawType(DRAW_SPLINE, PatchPrimToPrim(patchPrim)); - bool computeNormals = gstate.isLightingEnabled(); - bool patchFacing = gstate.patchfacing & 1; - u32 vertType = gstate.vertType; + Spline::SplineSurface surface; + surface.tess_u = gstate.getPatchDivisionU(); + surface.tess_v = gstate.getPatchDivisionV(); + surface.type_u = (op >> 16) & 0x3; + surface.type_v = (op >> 18) & 0x3; + surface.num_points_u = op & 0xFF; + surface.num_points_v = (op >> 8) & 0xFF; + surface.num_patches_u = surface.num_points_u - 3; + surface.num_patches_v = surface.num_points_v - 3; + surface.primType = gstate.getPatchPrimitiveType(); + surface.patchFacing = gstate.patchfacing & 1; + + SetDrawType(DRAW_SPLINE, PatchPrimToPrim(surface.primType)); int bytesRead = 0; - drawEngineCommon_->SubmitSpline(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), sp_ucount, sp_vcount, sp_utype, sp_vtype, patchPrim, computeNormals, patchFacing, vertType, &bytesRead); + drawEngineCommon_->SubmitCurve(control_points, indices, surface, gstate.vertType, &bytesRead, "spline"); framebufferDirty_ = true; // After drawing, we advance pointers - see SubmitPrim which does the same. - int count = sp_ucount * sp_vcount; + int count = surface.num_points_u * surface.num_points_v; AdvanceVerts(gstate.vertType, count, bytesRead); } break; From 8506da14f07605c6846930d2be79439e89866e57 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 17 Nov 2018 08:54:29 -0800 Subject: [PATCH 114/347] Debugger: Prevent invalid address on syscall. --- Core/MIPS/MIPSAnalyst.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/MIPS/MIPSAnalyst.cpp b/Core/MIPS/MIPSAnalyst.cpp index 43e5019a66..7a3459f808 100644 --- a/Core/MIPS/MIPSAnalyst.cpp +++ b/Core/MIPS/MIPSAnalyst.cpp @@ -1531,7 +1531,7 @@ skip: } // lw, sh, ... - if ((opInfo & IN_MEM) || (opInfo & OUT_MEM)) { + if (!IsSyscall(op) && (opInfo & (IN_MEM | OUT_MEM)) != 0) { info.isDataAccess = true; switch (opInfo & MEMTYPE_MASK) { case MEMTYPE_BYTE: From 2201c65b000a4e8b03d09816d4e8a2803f421e33 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 17 Nov 2018 08:55:00 -0800 Subject: [PATCH 115/347] Core: Fix spurious error on Linux/Unix paths. CreateFullPath with an absolute path would try to create ''. --- Common/FileUtil.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/FileUtil.cpp b/Common/FileUtil.cpp index c6a19a2c00..e8dbc62091 100644 --- a/Common/FileUtil.cpp +++ b/Common/FileUtil.cpp @@ -336,7 +336,7 @@ bool CreateFullPath(const std::string &path) return true; } std::string subPath = fullPath.substr(0, position); - if (!File::Exists(subPath)) + if (position != 0 && !File::Exists(subPath)) File::CreateDir(subPath); // A safety check From d245e002c72fd05f16c9aa3159c777c8da49ea66 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 17 Nov 2018 08:55:54 -0800 Subject: [PATCH 116/347] GE Debugger: Record block transfer too. --- GPU/GPUCommon.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 1e58cb2a6e..39b2e7263d 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -2615,6 +2615,7 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) { const u8 *src = Memory::GetPointerUnchecked(srcLineStartAddr); u8 *dst = Memory::GetPointerUnchecked(dstLineStartAddr); memcpy(dst, src, width * height * bpp); + GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, width * height * bpp); } else { for (int y = 0; y < height; y++) { u32 srcLineStartAddr = srcBasePtr + ((y + srcY) * srcStride + srcX) * bpp; @@ -2623,6 +2624,7 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) { const u8 *src = Memory::GetPointerUnchecked(srcLineStartAddr); u8 *dst = Memory::GetPointerUnchecked(dstLineStartAddr); memcpy(dst, src, width * bpp); + GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, width * bpp); } } From 6cba46bd62a2a19ba919c35d06b27ee4c7e436dd Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 17 Nov 2018 08:56:32 -0800 Subject: [PATCH 117/347] GE Debugger: Fix handling for framebuf changes. --- GPU/GPUCommon.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 39b2e7263d..ecc9163f3f 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -2726,24 +2726,24 @@ bool GPUCommon::PerformStencilUpload(u32 dest, int size) { } bool GPUCommon::GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes) { - u32 fb_address = type == GPU_DBG_FRAMEBUF_RENDER ? gstate.getFrameBufRawAddress() : framebufferManager_->DisplayFramebufAddr(); + u32 fb_address = type == GPU_DBG_FRAMEBUF_RENDER ? (gstate.getFrameBufRawAddress() | 0x04000000) : framebufferManager_->DisplayFramebufAddr(); int fb_stride = type == GPU_DBG_FRAMEBUF_RENDER ? gstate.FrameBufStride() : framebufferManager_->DisplayFramebufStride(); GEBufferFormat format = type == GPU_DBG_FRAMEBUF_RENDER ? gstate.FrameBufFormat() : framebufferManager_->DisplayFramebufFormat(); return framebufferManager_->GetFramebuffer(fb_address, fb_stride, format, buffer, maxRes); } bool GPUCommon::GetCurrentDepthbuffer(GPUDebugBuffer &buffer) { - u32 fb_address = gstate.getFrameBufRawAddress(); + u32 fb_address = gstate.getFrameBufRawAddress() | 0x04000000; int fb_stride = gstate.FrameBufStride(); - u32 z_address = gstate.getDepthBufRawAddress(); + u32 z_address = gstate.getDepthBufRawAddress() | 0x04000000; int z_stride = gstate.DepthBufStride(); return framebufferManager_->GetDepthbuffer(fb_address, fb_stride, z_address, z_stride, buffer); } bool GPUCommon::GetCurrentStencilbuffer(GPUDebugBuffer &buffer) { - u32 fb_address = gstate.getFrameBufRawAddress(); + u32 fb_address = gstate.getFrameBufRawAddress() | 0x04000000; int fb_stride = gstate.FrameBufStride(); return framebufferManager_->GetStencilbuffer(fb_address, fb_stride, buffer); From 184ae2f93c672331ebff08e17ec65c13ed7e3ec8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 17 Nov 2018 08:57:59 -0800 Subject: [PATCH 118/347] GE Debugger: Fix type conversion warning. --- Windows/GEDebugger/VertexPreview.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Windows/GEDebugger/VertexPreview.cpp b/Windows/GEDebugger/VertexPreview.cpp index 79183d236f..b608754b66 100644 --- a/Windows/GEDebugger/VertexPreview.cpp +++ b/Windows/GEDebugger/VertexPreview.cpp @@ -204,7 +204,7 @@ static void ExpandBezier(int &count, int op, const std::vector &si cpoints.col = (Vec4f *)AllocateAlignedMemory(sizeof(Vec4f) * num_points, 16); cpoints.Convert(points.data(), num_points); - surface.Init(generatedVerts.size()); + surface.Init((int)generatedVerts.size()); SoftwareTessellation(output, surface, gstate.vertType, cpoints); count = output.count; @@ -256,7 +256,7 @@ static void ExpandSpline(int &count, int op, const std::vector &si cpoints.col = (Vec4f *)AllocateAlignedMemory(sizeof(Vec4f) * num_points, 16); cpoints.Convert(points.data(), num_points); - surface.Init(generatedVerts.size()); + surface.Init((int)generatedVerts.size()); SoftwareTessellation(output, surface, gstate.vertType, cpoints); count = output.count; From caf5bb278969a54fd4ce12339b4eae7c93536872 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 17 Nov 2018 09:59:39 -0800 Subject: [PATCH 119/347] Vulkan: Allow pre-transition from undefined. This seems like it can happen when download/upload operations break up a render, and happens now with dumps using the display at the right timing. --- ext/native/thin3d/VulkanQueueRunner.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp index 2e122de544..07cb01dca1 100644 --- a/ext/native/thin3d/VulkanQueueRunner.cpp +++ b/ext/native/thin3d/VulkanQueueRunner.cpp @@ -689,6 +689,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c VkPipelineStageFlags dstStage{}; switch (barrier.oldLayout) { case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + case VK_IMAGE_LAYOUT_UNDEFINED: barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; srcStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; break; From 169d2fa44410391ced08ae9cafb2bcb9fbaafceb Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 17 Nov 2018 08:59:00 -0800 Subject: [PATCH 120/347] GE Debugger: Preserve VRAM textures in dumps. Should allow for (some) reproduction of render-to-texture behavior. --- GPU/Debugger/Record.cpp | 96 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 88 insertions(+), 8 deletions(-) diff --git a/GPU/Debugger/Record.cpp b/GPU/Debugger/Record.cpp index 1fa237a600..6f42ff8f21 100644 --- a/GPU/Debugger/Record.cpp +++ b/GPU/Debugger/Record.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017- PPSSPP Project. +// Copyright (c) 2017- PPSSPP Project. // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include "base/stringutil.h" @@ -43,7 +44,11 @@ namespace GPURecord { static const char *HEADER = "PPSSPPGE"; -static const int VERSION = 2; +// Version 1: Uncompressed +// Version 2: Uses snappy +// Version 3: Adds FRAMEBUF0-FRAMEBUF9 +static const int VERSION = 3; +static const int MIN_VERSION = 2; static bool active = false; static bool nextFrame = false; @@ -70,6 +75,15 @@ enum class CommandType : u8 { TEXTURE5 = 0x15, TEXTURE6 = 0x16, TEXTURE7 = 0x17, + + FRAMEBUF0 = 0x18, + FRAMEBUF1 = 0x19, + FRAMEBUF2 = 0x1A, + FRAMEBUF3 = 0x1B, + FRAMEBUF4 = 0x1C, + FRAMEBUF5 = 0x1D, + FRAMEBUF6 = 0x1E, + FRAMEBUF7 = 0x1F, }; #pragma pack(push, 1) @@ -86,6 +100,7 @@ static std::vector pushbuf; static std::vector commands; static std::vector lastRegisters; static std::vector lastTextures; +static std::set lastRenderTargets; // TODO: Maybe move execute to another file? class DumpExecute { @@ -109,6 +124,7 @@ private: void MemcpyDest(u32 ptr, u32 sz); void Memcpy(u32 ptr, u32 sz); void Texture(int level, u32 ptr, u32 sz); + void Framebuf(int level, u32 ptr, u32 sz); void Display(u32 ptr, u32 sz); u32 execMemcpyDest = 0; @@ -358,7 +374,7 @@ static void FlushRegisters() { static std::string GenRecordingFilename() { const std::string dumpDir = GetSysDirectory(DIRECTORY_DUMP); - const std::string prefix = dumpDir + "/" + g_paramSFO.GetDiscID(); + const std::string prefix = dumpDir + g_paramSFO.GetDiscID(); File::CreateFullPath(dumpDir); @@ -528,13 +544,36 @@ static void EmitTextureData(int level, u32 texaddr) { int bufw = GetTextureBufw(level, texaddr, format); int extraw = w > bufw ? w - bufw : 0; u32 sizeInRAM = (textureBitsPerPixel[format] * (bufw * h + extraw)) / 8; + const bool isTarget = lastRenderTargets.find(texaddr) != lastRenderTargets.end(); + CommandType type = CommandType((int)CommandType::TEXTURE0 + level); + const u8 *p = Memory::GetPointerUnchecked(texaddr); u32 bytes = Memory::ValidSize(texaddr, sizeInRAM); - if (Memory::IsValidAddress(texaddr)) { - FlushRegisters(); + std::vector framebufData; - CommandType type = CommandType((int)CommandType::TEXTURE0 + level); - const u8 *p = Memory::GetPointerUnchecked(texaddr); + if (Memory::IsVRAMAddress(texaddr)) { + struct FramebufData { + u32 addr; + int bufw; + u32 flags; + u32 pad; + }; + + // The isTarget flag is mostly used for replay of dumps on a PSP. + u32 flags = isTarget ? 1 : 0; + FramebufData framebuf{ texaddr, bufw, flags }; + framebufData.resize(sizeof(framebuf) + bytes); + memcpy(&framebufData[0], &framebuf, sizeof(framebuf)); + memcpy(&framebufData[sizeof(framebuf)], p, bytes); + p = &framebufData[0]; + + // Okay, now we'll just emit this instead. + type = CommandType((int)CommandType::FRAMEBUF0 + level); + bytes += (u32)sizeof(framebuf); + } + + if (bytes > 0) { + FlushRegisters(); // Dumps are huge - let's try to find this already emitted. for (u32 prevptr : lastTextures) { @@ -559,6 +598,9 @@ static void FlushPrimState(int vcount) { // TODO: Eventually, how do we handle texturing from framebuf/zbuf? // TODO: Do we need to preload color/depth/stencil (in case from last frame)? + lastRenderTargets.insert(PSP_GetVidMemBase() | gstate.getFrameBufRawAddress()); + lastRenderTargets.insert(PSP_GetVidMemBase() | gstate.getDepthBufRawAddress()); + // We re-flush textures always in case the game changed them... kinda expensive. // TODO: Dirty textures on transfer/stall/etc. somehow? // TODO: Or maybe de-dup by validating if it has changed? @@ -782,6 +824,7 @@ void NotifyFrame() { active = true; nextFrame = false; lastTextures.clear(); + lastRenderTargets.clear(); BeginRecording(); } } @@ -977,6 +1020,32 @@ void DumpExecute::Texture(int level, u32 ptr, u32 sz) { execListQueue.push_back((addrCmd << 24) | (psp & 0x00FFFFFF)); } +void DumpExecute::Framebuf(int level, u32 ptr, u32 sz) { + struct FramebufData { + u32 addr; + int bufw; + u32 flags; + u32 pad; + }; + + FramebufData *framebuf = (FramebufData *)(pushbuf.data() + ptr); + + u32 bufwCmd = GE_CMD_TEXBUFWIDTH0 + level; + u32 addrCmd = GE_CMD_TEXADDR0 + level; + execListQueue.push_back((bufwCmd << 24) | ((framebuf->addr >> 8) & 0x00FF0000) | framebuf->bufw); + execListQueue.push_back((addrCmd << 24) | (framebuf->addr & 0x00FFFFFF)); + lastBufw_[level] = framebuf->bufw; + + // And now also copy the data into VRAM (in case it wasn't actually rendered.) + u32 headerSize = (u32)sizeof(FramebufData); + u32 pspSize = sz - headerSize; + // TODO: Potentially skip this if flags & 1 (means it was rendered to previously.) + if (Memory::IsValidRange(framebuf->addr, pspSize)) { + // Intentionally don't trigger an upload here. + Memory::MemcpyUnchecked(framebuf->addr, pushbuf.data() + ptr + headerSize, pspSize); + } +} + void DumpExecute::Display(u32 ptr, u32 sz) { struct DisplayBufData { PSPPointer topaddr; @@ -1055,6 +1124,17 @@ bool DumpExecute::Run() { Texture((int)cmd.type - (int)CommandType::TEXTURE0, cmd.ptr, cmd.sz); break; + case CommandType::FRAMEBUF0: + case CommandType::FRAMEBUF1: + case CommandType::FRAMEBUF2: + case CommandType::FRAMEBUF3: + case CommandType::FRAMEBUF4: + case CommandType::FRAMEBUF5: + case CommandType::FRAMEBUF6: + case CommandType::FRAMEBUF7: + Framebuf((int)cmd.type - (int)CommandType::FRAMEBUF0, cmd.ptr, cmd.sz); + break; + case CommandType::DISPLAY: Display(cmd.ptr, cmd.sz); break; @@ -1097,7 +1177,7 @@ bool RunMountedReplay(const std::string &filename) { pspFileSystem.ReadFile(fp, header, sizeof(header)); pspFileSystem.ReadFile(fp, (u8 *)&version, sizeof(version)); - if (memcmp(header, HEADER, sizeof(header)) != 0 || version != VERSION) { + if (memcmp(header, HEADER, sizeof(header)) != 0 || version > VERSION || version < MIN_VERSION) { ERROR_LOG(SYSTEM, "Invalid GE dump or unsupported version"); pspFileSystem.CloseFile(fp); return false; From 6383f407d18cce6870bd69660f9ef9597b5cdadc Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 17 Nov 2018 09:06:02 -0800 Subject: [PATCH 121/347] GE Debugger: Avoid overwriting in softgpu playback. --- GPU/Debugger/Record.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/GPU/Debugger/Record.cpp b/GPU/Debugger/Record.cpp index 6f42ff8f21..6075761c0a 100644 --- a/GPU/Debugger/Record.cpp +++ b/GPU/Debugger/Record.cpp @@ -1039,8 +1039,9 @@ void DumpExecute::Framebuf(int level, u32 ptr, u32 sz) { // And now also copy the data into VRAM (in case it wasn't actually rendered.) u32 headerSize = (u32)sizeof(FramebufData); u32 pspSize = sz - headerSize; - // TODO: Potentially skip this if flags & 1 (means it was rendered to previously.) - if (Memory::IsValidRange(framebuf->addr, pspSize)) { + const bool isTarget = (framebuf->flags & 1) != 0; + // Could potentially always skip if !isTarget, but playing it safe for offset texture behavior. + if (Memory::IsValidRange(framebuf->addr, pspSize) && (!isTarget || !g_Config.bSoftwareRendering)) { // Intentionally don't trigger an upload here. Memory::MemcpyUnchecked(framebuf->addr, pushbuf.data() + ptr + headerSize, pspSize); } From 2d3885fc1a63f9cf8f5f3cab71528f91e092a7f9 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 17 Nov 2018 09:21:51 -0800 Subject: [PATCH 122/347] GE Debugger: Fix display event record timing. When the display happens mid frame, this fixes it so you can see the result easily when running the dump, without manually stepping through. --- GPU/Common/FramebufferCommon.cpp | 2 ++ GPU/Debugger/Record.cpp | 41 +++++++++++++++++--------------- GPU/Debugger/Record.h | 3 ++- GPU/Software/SoftGpu.cpp | 1 + 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index 8675eec848..09b7968a55 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -39,6 +39,7 @@ #include "GPU/Common/FramebufferCommon.h" #include "GPU/Common/PostShader.h" #include "GPU/Common/TextureCacheCommon.h" +#include "GPU/Debugger/Record.h" #include "GPU/GPUInterface.h" #include "GPU/GPUState.h" @@ -169,6 +170,7 @@ void FramebufferManagerCommon::SetDisplayFramebuffer(u32 framebuf, u32 stride, G displayFramebufPtr_ = framebuf; displayStride_ = stride; displayFormat_ = format; + GPURecord::NotifyDisplay(framebuf, stride, format); } VirtualFramebuffer *FramebufferManagerCommon::GetVFBAt(u32 addr) { diff --git a/GPU/Debugger/Record.cpp b/GPU/Debugger/Record.cpp index 1fa237a600..70572a2efd 100644 --- a/GPU/Debugger/Record.cpp +++ b/GPU/Debugger/Record.cpp @@ -372,23 +372,6 @@ static std::string GenRecordingFilename() { return StringFromFormat("%s_%04d.ppdmp", prefix.c_str(), 9999); } -static void EmitDisplayBuf() { - struct DisplayBufData { - PSPPointer topaddr; - u32 linesize, pixelFormat; - }; - - DisplayBufData disp{}; - __DisplayGetFramebuf(&disp.topaddr, &disp.linesize, &disp.pixelFormat, 0); - - u32 ptr = (u32)pushbuf.size(); - u32 sz = (u32)sizeof(disp); - pushbuf.resize(pushbuf.size() + sz); - memcpy(pushbuf.data() + ptr, &disp, sz); - - commands.push_back({CommandType::DISPLAY, sz, ptr}); -} - static void BeginRecording() { u32 ptr = (u32)pushbuf.size(); u32 sz = 512 * 4; @@ -412,7 +395,6 @@ static void WriteCompressed(FILE *fp, const void *p, size_t sz) { static std::string WriteRecording() { FlushRegisters(); - EmitDisplayBuf(); const std::string filename = GenRecordingFilename(); @@ -771,6 +753,27 @@ void NotifyUpload(u32 dest, u32 sz) { NotifyMemcpy(dest, dest, sz); } +void NotifyDisplay(u32 framebuf, int stride, int fmt) { + if (!active) { + return; + } + + struct DisplayBufData { + PSPPointer topaddr; + int linesize, pixelFormat; + }; + + DisplayBufData disp{ framebuf, stride, fmt }; + + FlushRegisters(); + u32 ptr = (u32)pushbuf.size(); + u32 sz = (u32)sizeof(disp); + pushbuf.resize(pushbuf.size() + sz); + memcpy(pushbuf.data() + ptr, &disp, sz); + + commands.push_back({ CommandType::DISPLAY, sz, ptr }); +} + void NotifyFrame() { if (active && !writePending && !commands.empty()) { // Delay write until the first command of the next frame, so we get the right display buf. @@ -980,7 +983,7 @@ void DumpExecute::Texture(int level, u32 ptr, u32 sz) { void DumpExecute::Display(u32 ptr, u32 sz) { struct DisplayBufData { PSPPointer topaddr; - u32 linesize, pixelFormat; + int linesize, pixelFormat; }; DisplayBufData *disp = (DisplayBufData *)(pushbuf.data() + ptr); diff --git a/GPU/Debugger/Record.h b/GPU/Debugger/Record.h index 230b361d19..020ce2ca8c 100644 --- a/GPU/Debugger/Record.h +++ b/GPU/Debugger/Record.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017- PPSSPP Project. +// Copyright (c) 2017- PPSSPP Project. // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -33,6 +33,7 @@ void NotifyCommand(u32 pc); void NotifyMemcpy(u32 dest, u32 src, u32 sz); void NotifyMemset(u32 dest, int v, u32 sz); void NotifyUpload(u32 dest, u32 sz); +void NotifyDisplay(u32 addr, int stride, int fmt); void NotifyFrame(); bool RunMountedReplay(const std::string &filename); diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 44771c197b..f7e29dd665 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -143,6 +143,7 @@ void SoftGPU::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat for displayStride_ = stride; displayFormat_ = format; GPUDebug::NotifyDisplay(framebuf, stride, format); + GPURecord::NotifyDisplay(framebuf, stride, format); } // Copies RGBA8 data from RAM to the currently bound render target. From 66008963121fea15092c0ee0f2354ac56ae1023b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 17 Nov 2018 18:05:32 -0800 Subject: [PATCH 123/347] GPU: Fix shade mapping in soft transform. Was using invalid values when lighting was off. --- GPU/Common/SoftwareTransformCommon.cpp | 11 +++++++++-- GPU/Common/TransformCommon.cpp | 6 +++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index fc943993b4..b097a4d833 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -391,8 +391,15 @@ void SoftwareTransform( case GE_TEXMAP_ENVIRONMENT_MAP: // Shade mapping - use two light sources to generate U and V. { - Vec3f lightpos0 = Vec3f(&lighter.lpos[gstate.getUVLS0() * 3]).Normalized(); - Vec3f lightpos1 = Vec3f(&lighter.lpos[gstate.getUVLS1() * 3]).Normalized(); + auto getLPosFloat = [&](int l, int i) { + return getFloat24(gstate.lpos[l * 3 + i]); + }; + auto getLPos = [&](int l) { + return Vec3f(getLPosFloat(l, 0), getLPosFloat(l, 1), getLPosFloat(l, 2)); + }; + // Might not have lighting enabled, so don't use lighter. + Vec3f lightpos0 = getLPos(gstate.getUVLS0()).Normalized(); + Vec3f lightpos1 = getLPos(gstate.getUVLS1()).Normalized(); uv[0] = (1.0f + Dot(lightpos0, worldnormal))/2.0f; uv[1] = (1.0f + Dot(lightpos1, worldnormal))/2.0f; diff --git a/GPU/Common/TransformCommon.cpp b/GPU/Common/TransformCommon.cpp index a80b2769e5..7e74f321a7 100644 --- a/GPU/Common/TransformCommon.cpp +++ b/GPU/Common/TransformCommon.cpp @@ -107,9 +107,9 @@ void Lighter::Light(float colorOut0[4], float colorOut1[4], const float colorIn[ Vec3f lightDir(0, 0, 0); if (type == GE_LIGHTTYPE_DIRECTIONAL) - toLight = Vec3f(&lpos[l * 3]); // lightdir is for spotlights + toLight = Vec3Packedf(&lpos[l * 3]); // lightdir is for spotlights else - toLight = Vec3f(&lpos[l * 3]) - pos; + toLight = Vec3Packedf(&lpos[l * 3]) - pos; bool doSpecular = gstate.isUsingSpecularLight(l); bool poweredDiffuse = gstate.isUsingPoweredDiffuseLight(l); @@ -139,7 +139,7 @@ void Lighter::Light(float colorOut0[4], float colorOut1[4], const float colorIn[ break; case GE_LIGHTTYPE_SPOT: case GE_LIGHTTYPE_UNKNOWN: - lightDir = Vec3f(&ldir[l * 3]); + lightDir = Vec3Packedf(&ldir[l * 3]); angle = Dot(toLight.Normalized(), lightDir.Normalized()); if (angle >= lcutoff[l]) lightScale = clamp(1.0f / (latt[l * 3] + latt[l * 3 + 1] * distanceToLight + latt[l * 3 + 2] * distanceToLight*distanceToLight), 0.0f, 1.0f) * powf(angle, lconv[l]); From 986371c6338383f2e508629e759f0dfb495ef9ce Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 17 Nov 2018 18:16:54 -0800 Subject: [PATCH 124/347] SoftGPU: Normalize 0,0,0 as 0,0,1 for shade map. Takes care of #4155 for software rendering. --- GPU/Software/Lighting.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/GPU/Software/Lighting.cpp b/GPU/Software/Lighting.cpp index c322e381a9..2a1e6398aa 100644 --- a/GPU/Software/Lighting.cpp +++ b/GPU/Software/Lighting.cpp @@ -38,7 +38,8 @@ void Process(VertexData& vertex, bool hasColor) // TODO: Not sure if this really should be done even if lighting is disabled altogether if (gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP) { Vec3 L = Vec3(getFloat24(gstate.lpos[3 * light]), getFloat24(gstate.lpos[3 * light + 1]),getFloat24(gstate.lpos[3 * light + 2])); - float diffuse_factor = Dot(L.Normalized(), vertex.worldnormal); + // In other words, L.Length() == 0.0f means Dot({0, 0, 1}, worldnormal). + float diffuse_factor = L.Length() == 0.0f ? vertex.worldnormal.z : Dot(L.Normalized(), vertex.worldnormal); if (gstate.getUVLS0() == (int)light) vertex.texturecoords.s() = (diffuse_factor + 1.f) / 2.f; From 0c5c776bb9474a56ea0b7ccb670a839267e8e03f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 17 Nov 2018 18:33:07 -0800 Subject: [PATCH 125/347] GPU: Correct shade mapping with 0,0,0 light pos. May need to audit more normalize() usage, if it's consistent in other places. --- GPU/Common/SoftwareTransformCommon.cpp | 12 ++++++++++-- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 6 +++++- GPU/GLES/VertexShaderGeneratorGLES.cpp | 6 +++++- GPU/Vulkan/VertexShaderGeneratorVulkan.cpp | 8 ++++++-- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index b097a4d833..311333e791 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -397,9 +397,17 @@ void SoftwareTransform( auto getLPos = [&](int l) { return Vec3f(getLPosFloat(l, 0), getLPosFloat(l, 1), getLPosFloat(l, 2)); }; + auto calcShadingLPos = [&](int l) { + Vec3f pos = getLPos(l); + if (pos.Length() == 0.0f) { + return Vec3f(0.0f, 0.0f, 1.0f); + } else { + return pos.Normalized(); + } + }; // Might not have lighting enabled, so don't use lighter. - Vec3f lightpos0 = getLPos(gstate.getUVLS0()).Normalized(); - Vec3f lightpos1 = getLPos(gstate.getUVLS1()).Normalized(); + Vec3f lightpos0 = calcShadingLPos(gstate.getUVLS0()); + Vec3f lightpos1 = calcShadingLPos(gstate.getUVLS1()); uv[0] = (1.0f + Dot(lightpos0, worldnormal))/2.0f; uv[1] = (1.0f + Dot(lightpos1, worldnormal))/2.0f; diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 53ef880c17..9b456fe3a3 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -715,7 +715,11 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage break; case GE_TEXMAP_ENVIRONMENT_MAP: // Shade mapping - use dots from light sources. - WRITE(p, " Out.v_texcoord = float3(u_uvscaleoffset.xy * float2(1.0 + dot(normalize(u_lightpos%i), worldnormal), 1.0 + dot(normalize(u_lightpos%i), worldnormal)) * 0.5, 1.0);\n", ls0, ls1); + { + std::string lightFactor0 = StringFromFormat("(length(u_lightpos%i) == 0.0 ? worldnormal.z : dot(normalize(u_lightpos%i), worldnormal))", ls0, ls0); + std::string lightFactor1 = StringFromFormat("(length(u_lightpos%i) == 0.0 ? worldnormal.z : dot(normalize(u_lightpos%i), worldnormal))", ls1, ls1); + WRITE(p, " Out.v_texcoord = float3(u_uvscaleoffset.xy * float2(1.0 + %s, 1.0 + %s) * 0.5, 1.0);\n", lightFactor0.c_str(), lightFactor1.c_str()); + } break; default: diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index 7efc8e6341..c51da43f75 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -810,7 +810,11 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, break; case GE_TEXMAP_ENVIRONMENT_MAP: // Shade mapping - use dots from light sources. - WRITE(p, " v_texcoord = vec3(u_uvscaleoffset.xy * vec2(1.0 + dot(normalize(u_lightpos%i), worldnormal), 1.0 + dot(normalize(u_lightpos%i), worldnormal)) * 0.5, 1.0);\n", ls0, ls1); + { + std::string lightFactor0 = StringFromFormat("(length(u_lightpos%i) == 0.0 ? worldnormal.z : dot(normalize(u_lightpos%i), worldnormal))", ls0, ls0); + std::string lightFactor1 = StringFromFormat("(length(u_lightpos%i) == 0.0 ? worldnormal.z : dot(normalize(u_lightpos%i), worldnormal))", ls1, ls1); + WRITE(p, " v_texcoord = vec3(u_uvscaleoffset.xy * vec2(1.0 + %s, 1.0 + %s) * 0.5, 1.0);\n", lightFactor0.c_str(), lightFactor1.c_str()); + } break; default: diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index 6d2051828e..e64e81508d 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -602,8 +602,12 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { break; case GE_TEXMAP_ENVIRONMENT_MAP: // Shade mapping - use dots from light sources. - WRITE(p, " v_texcoord = vec3(base.uvscaleoffset.xy * vec2(1.0 + dot(normalize(light.pos[%i]), worldnormal), 1.0 + dot(normalize(light.pos[%i]), worldnormal)) * 0.5, 1.0);\n", ls0, ls1); - break; + { + std::string lightFactor0 = StringFromFormat("(length(light.pos[%i]) == 0.0 ? worldnormal.z : dot(normalize(light.pos[%i]), worldnormal))", ls0, ls0); + std::string lightFactor1 = StringFromFormat("(length(light.pos[%i]) == 0.0 ? worldnormal.z : dot(normalize(light.pos[%i]), worldnormal))", ls1, ls1); + WRITE(p, " v_texcoord = vec3(base.uvscaleoffset.xy * vec2(1.0 + %s, 1.0 + %s) * 0.5, 1.0);\n", lightFactor0.c_str(), lightFactor1.c_str()); + } + break; default: // ILLEGAL From 179514e8d76924b635a2b5f7b9cbe85dab08a872 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 17 Nov 2018 21:52:13 -0800 Subject: [PATCH 126/347] GE Debugger: Avoid writing 0 sized packets. This causes errors on allocation sometimes due to things like count=0 in a prim command. --- GPU/Debugger/Record.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/GPU/Debugger/Record.cpp b/GPU/Debugger/Record.cpp index c875787337..3adf3be9cd 100644 --- a/GPU/Debugger/Record.cpp +++ b/GPU/Debugger/Record.cpp @@ -603,10 +603,10 @@ static void FlushPrimState(int vcount) { u32 vbytes = 0; GetVertDataSizes(vcount, indices, vbytes, ibytes); - if (indices) { + if (indices && ibytes > 0) { EmitCommandWithRAM(CommandType::INDICES, indices, ibytes); } - if (verts) { + if (verts && vbytes > 0) { EmitCommandWithRAM(CommandType::VERTICES, verts, vbytes); } } @@ -631,7 +631,9 @@ static void EmitTransfer(u32 op) { u32 srcBytes = ((srcY + height - 1) * srcStride + (srcX + width)) * bpp; srcBytes = Memory::ValidSize(srcBasePtr, srcBytes); - EmitCommandWithRAM(CommandType::TRANSFERSRC, Memory::GetPointerUnchecked(srcBasePtr), srcBytes); + if (srcBytes != 0) { + EmitCommandWithRAM(CommandType::TRANSFERSRC, Memory::GetPointerUnchecked(srcBasePtr), srcBytes); + } lastRegisters.push_back(op); } @@ -641,7 +643,9 @@ static void EmitClut(u32 op) { u32 bytes = (op & 0x3F) * 32; bytes = Memory::ValidSize(addr, bytes); - EmitCommandWithRAM(CommandType::CLUT, Memory::GetPointerUnchecked(addr), bytes); + if (bytes != 0) { + EmitCommandWithRAM(CommandType::CLUT, Memory::GetPointerUnchecked(addr), bytes); + } lastRegisters.push_back(op); } @@ -763,7 +767,9 @@ void NotifyMemcpy(u32 dest, u32 src, u32 sz) { memcpy(pushbuf.data() + cmd.ptr, &dest, sizeof(dest)); sz = Memory::ValidSize(dest, sz); - EmitCommandWithRAM(CommandType::MEMCPYDATA, Memory::GetPointer(dest), sz); + if (sz != 0) { + EmitCommandWithRAM(CommandType::MEMCPYDATA, Memory::GetPointer(dest), sz); + } } } From 3cf3985c8d48edc194a7769ee3549fa7782197e1 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 17 Nov 2018 22:12:45 -0800 Subject: [PATCH 127/347] GE Debugger: Support record for more render types. This should handle both games that use display, and games that don't. --- GPU/Debugger/Record.cpp | 62 ++++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/GPU/Debugger/Record.cpp b/GPU/Debugger/Record.cpp index 3adf3be9cd..255612e3f6 100644 --- a/GPU/Debugger/Record.cpp +++ b/GPU/Debugger/Record.cpp @@ -52,7 +52,7 @@ static const int MIN_VERSION = 2; static bool active = false; static bool nextFrame = false; -static bool writePending = false; +static int flipLastAction = -1; static std::function writeCallback; enum class CommandType : u8 { @@ -389,6 +389,12 @@ static std::string GenRecordingFilename() { } static void BeginRecording() { + active = true; + nextFrame = false; + lastTextures.clear(); + lastRenderTargets.clear(); + flipLastAction = gpuStats.numFlips; + u32 ptr = (u32)pushbuf.size(); u32 sz = 512 * 4; pushbuf.resize(pushbuf.size() + sz); @@ -675,6 +681,7 @@ bool IsActivePending() { bool Activate() { if (!nextFrame) { nextFrame = true; + flipLastAction = gpuStats.numFlips; return true; } return false; @@ -691,8 +698,8 @@ static void FinishRecording() { pushbuf.clear(); NOTICE_LOG(SYSTEM, "Recording finished"); - writePending = false; active = false; + flipLastAction = gpuStats.numFlips; if (writeCallback) writeCallback(filename); @@ -703,10 +710,6 @@ void NotifyCommand(u32 pc) { if (!active) { return; } - if (writePending) { - FinishRecording(); - return; - } const u32 op = Memory::Read_U32(pc); const GECommand cmd = GECommand(op >> 24); @@ -802,6 +805,14 @@ void NotifyUpload(u32 dest, u32 sz) { } void NotifyDisplay(u32 framebuf, int stride, int fmt) { + bool writePending = false; + if (active && !commands.empty()) { + writePending = true; + } + if (nextFrame && (gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME) == 0) { + NOTICE_LOG(SYSTEM, "Recording starting on display..."); + BeginRecording(); + } if (!active) { return; } @@ -820,20 +831,39 @@ void NotifyDisplay(u32 framebuf, int stride, int fmt) { memcpy(pushbuf.data() + ptr, &disp, sz); commands.push_back({ CommandType::DISPLAY, sz, ptr }); + + if (writePending) { + NOTICE_LOG(SYSTEM, "Recording complete on display"); + FinishRecording(); + } } void NotifyFrame() { - if (active && !writePending && !commands.empty()) { - // Delay write until the first command of the next frame, so we get the right display buf. - NOTICE_LOG(SYSTEM, "Recording complete - waiting to get display buffer"); - writePending = true; + const bool noDisplayAction = flipLastAction + 4 < gpuStats.numFlips; + // We do this only to catch things that don't call NotifyDisplay. + if (active && !commands.empty() && noDisplayAction) { + NOTICE_LOG(SYSTEM, "Recording complete on frame"); + + struct DisplayBufData { + PSPPointer topaddr; + u32 linesize, pixelFormat; + }; + + DisplayBufData disp; + __DisplayGetFramebuf(&disp.topaddr, &disp.linesize, &disp.pixelFormat, 0); + + FlushRegisters(); + u32 ptr = (u32)pushbuf.size(); + u32 sz = (u32)sizeof(disp); + pushbuf.resize(pushbuf.size() + sz); + memcpy(pushbuf.data() + ptr, &disp, sz); + + commands.push_back({ CommandType::DISPLAY, sz, ptr }); + + FinishRecording(); } - if (nextFrame && (gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME) == 0) { - NOTICE_LOG(SYSTEM, "Recording starting..."); - active = true; - nextFrame = false; - lastTextures.clear(); - lastRenderTargets.clear(); + if (nextFrame && (gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME) == 0 && noDisplayAction) { + NOTICE_LOG(SYSTEM, "Recording starting on frame..."); BeginRecording(); } } From b2d60cb807bc96f3cb900982cee34885df55be89 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 18 Nov 2018 07:28:03 -0800 Subject: [PATCH 128/347] SoftGPU: Cleanup lighting code a bit. Avoid using Length() when Length2() is enough, simplify some things. --- GPU/Common/SoftwareTransformCommon.cpp | 2 +- GPU/Software/Lighting.cpp | 31 +++++++++++++------------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index 311333e791..d38784d2f5 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -399,7 +399,7 @@ void SoftwareTransform( }; auto calcShadingLPos = [&](int l) { Vec3f pos = getLPos(l); - if (pos.Length() == 0.0f) { + if (pos.Length2() == 0.0f) { return Vec3f(0.0f, 0.0f, 1.0f); } else { return pos.Normalized(); diff --git a/GPU/Software/Lighting.cpp b/GPU/Software/Lighting.cpp index 2a1e6398aa..96b0fef6cf 100644 --- a/GPU/Software/Lighting.cpp +++ b/GPU/Software/Lighting.cpp @@ -21,8 +21,11 @@ namespace Lighting { -void Process(VertexData& vertex, bool hasColor) -{ +static inline Vec3f GetLightVec(u32 lparams[12], int light) { + return Vec3(getFloat24(lparams[3 * light]), getFloat24(lparams[3 * light + 1]), getFloat24(lparams[3 * light + 2])); +} + +void Process(VertexData& vertex, bool hasColor) { const int materialupdate = gstate.materialupdate & (hasColor ? 7 : 0); Vec3 vcol0 = vertex.color0.rgb().Cast() * Vec3::AssignToAll(1.0f / 255.0f); @@ -35,11 +38,11 @@ void Process(VertexData& vertex, bool hasColor) for (unsigned int light = 0; light < 4; ++light) { // Always calculate texture coords from lighting results if environment mapping is active // TODO: Should specular lighting should affect this, too? Doesn't in GLES. - // TODO: Not sure if this really should be done even if lighting is disabled altogether + // This should be done even if lighting is disabled altogether. if (gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP) { - Vec3 L = Vec3(getFloat24(gstate.lpos[3 * light]), getFloat24(gstate.lpos[3 * light + 1]),getFloat24(gstate.lpos[3 * light + 2])); - // In other words, L.Length() == 0.0f means Dot({0, 0, 1}, worldnormal). - float diffuse_factor = L.Length() == 0.0f ? vertex.worldnormal.z : Dot(L.Normalized(), vertex.worldnormal); + Vec3 L = GetLightVec(gstate.lpos, light); + // In other words, L.Length2() == 0.0f means Dot({0, 0, 1}, worldnormal). + float diffuse_factor = L.Length2() == 0.0f ? vertex.worldnormal.z : Dot(L.Normalized(), vertex.worldnormal); if (gstate.getUVLS0() == (int)light) vertex.texturecoords.s() = (diffuse_factor + 1.f) / 2.f; @@ -58,30 +61,28 @@ void Process(VertexData& vertex, bool hasColor) // L = vector from vertex to light source // TODO: Should transfer the light positions to world/view space for these calculations? - Vec3 L = Vec3(getFloat24(gstate.lpos[3 * light]), getFloat24(gstate.lpos[3 * light + 1]),getFloat24(gstate.lpos[3 * light + 2])); + Vec3 L = GetLightVec(gstate.lpos, light); if (!gstate.isDirectionalLight(light)) { L -= vertex.worldpos; } + // TODO: Should this normalize (0, 0, 0) to (0, 0, 1)? float d = L.Normalize(); - float lka = getFloat24(gstate.latt[3 * light]); - float lkb = getFloat24(gstate.latt[3 * light + 1]); - float lkc = getFloat24(gstate.latt[3 * light + 2]); float att = 1.f; if (!gstate.isDirectionalLight(light)) { - att = 1.f / (lka + lkb * d + lkc * d * d); + att = 1.f / Dot(GetLightVec(gstate.latt, light), Vec3f(1.0f, d, d * d)); if (att > 1.f) att = 1.f; if (att < 0.f) att = 0.f; } float spot = 1.f; if (gstate.isSpotLight(light)) { - Vec3 dir = Vec3(getFloat24(gstate.ldir[3 * light]), getFloat24(gstate.ldir[3 * light + 1]),getFloat24(gstate.ldir[3 * light + 2])); - float _spot = Dot(dir.Normalized(), L); + Vec3 dir = GetLightVec(gstate.ldir, light); + float rawSpot = Dot(dir.Normalized(), L); float cutoff = getFloat24(gstate.lcutoff[light]); - if (_spot >= cutoff) { + if (rawSpot >= cutoff) { float conv = getFloat24(gstate.lconv[light]); - spot = pow(_spot, conv); + spot = pow(rawSpot, conv); } else { spot = 0.f; } From 0bf44827b710af454f351e8d0e515da35c9da3c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 19 Nov 2018 08:27:46 +0100 Subject: [PATCH 129/347] ManagedTexture: CreateTextureFromFileData should not return a ManagedTexture object if it fails. Alternatively, we should add even more checks around the code for empty ManagedTextures... --- UI/TextureUtil.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/UI/TextureUtil.cpp b/UI/TextureUtil.cpp index 3fdd3d82a1..b2a41fba52 100644 --- a/UI/TextureUtil.cpp +++ b/UI/TextureUtil.cpp @@ -200,6 +200,11 @@ std::unique_ptr CreateTextureFromFileData(Draw::DrawContext *dra if (!draw) return std::unique_ptr(); ManagedTexture *mtex = new ManagedTexture(draw); - mtex->LoadFromFileData(data, size, type, generateMips); - return std::unique_ptr(mtex); + if (mtex->LoadFromFileData(data, size, type, generateMips)) { + return std::unique_ptr(mtex); + } else { + // Best to return a null pointer if we fail! + delete mtex; + return std::unique_ptr(); + } } From 10fa20cb065aa0d5ba2206e8960c72e4c227d991 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 19 Nov 2018 06:15:55 -0800 Subject: [PATCH 130/347] SoftGPU: Fix pixel mask on rectangle clear. Oops, had inverted it. This caused it to improperly clear when masked. --- GPU/Software/Rasterizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 044f1c399f..b856ba7b8e 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -1553,7 +1553,7 @@ void ClearRectangle(const VertexData &v0, const VertexData &v1) } // The pixel write masks are respected in clear mode. - keepOldMask &= ~gstate.getColorMask(); + keepOldMask |= gstate.getColorMask(); if (keepOldMask == 0) { ScreenCoords pprime(minX, minY, 0); From a30da4b6742dff96910f63a1783e7dd7a250b2ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 20 Nov 2018 09:09:19 +0100 Subject: [PATCH 131/347] Coldbird server moved, so change the default. Should look into doing this automatically, maybe storing the coldbird server in a config file on ppsspp.org. --- Core/Config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 22b88a7604..a62dbb21f6 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -835,7 +835,7 @@ static ConfigSetting systemParamSettings[] = { ReportedConfigSetting("PSPModel", &g_Config.iPSPModel, &DefaultPSPModel, true, true), ReportedConfigSetting("PSPFirmwareVersion", &g_Config.iFirmwareVersion, PSP_DEFAULT_FIRMWARE, true, true), ConfigSetting("NickName", &g_Config.sNickName, "PPSSPP", true, true), - ConfigSetting("proAdhocServer", &g_Config.proAdhocServer, "coldbird.net", true, true), + ConfigSetting("proAdhocServer", &g_Config.proAdhocServer, "black-seraph.com", true, true), ConfigSetting("MacAddress", &g_Config.sMACAddress, "", true, true), ConfigSetting("PortOffset", &g_Config.iPortOffset, 0, true, true), ReportedConfigSetting("Language", &g_Config.iLanguage, &DefaultSystemParamLanguage, true, true), From 7adb04f773a1c98fac642842c5b19d28eed0d785 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 19 Nov 2018 08:27:46 +0100 Subject: [PATCH 132/347] ManagedTexture: CreateTextureFromFileData should not return a ManagedTexture object if it fails. Alternatively, we should add even more checks around the code for empty ManagedTextures... --- UI/TextureUtil.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/UI/TextureUtil.cpp b/UI/TextureUtil.cpp index 3fdd3d82a1..b2a41fba52 100644 --- a/UI/TextureUtil.cpp +++ b/UI/TextureUtil.cpp @@ -200,6 +200,11 @@ std::unique_ptr CreateTextureFromFileData(Draw::DrawContext *dra if (!draw) return std::unique_ptr(); ManagedTexture *mtex = new ManagedTexture(draw); - mtex->LoadFromFileData(data, size, type, generateMips); - return std::unique_ptr(mtex); + if (mtex->LoadFromFileData(data, size, type, generateMips)) { + return std::unique_ptr(mtex); + } else { + // Best to return a null pointer if we fail! + delete mtex; + return std::unique_ptr(); + } } From dd9503e4183cd7ed28b9cf26c9de78e629c5ab23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 20 Nov 2018 09:09:19 +0100 Subject: [PATCH 133/347] Coldbird server moved, so change the default. Should look into doing this automatically, maybe storing the coldbird server in a config file on ppsspp.org. --- Core/Config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 8ff95fcde5..62a5ee7977 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -834,7 +834,7 @@ static ConfigSetting systemParamSettings[] = { ReportedConfigSetting("PSPModel", &g_Config.iPSPModel, &DefaultPSPModel, true, true), ReportedConfigSetting("PSPFirmwareVersion", &g_Config.iFirmwareVersion, PSP_DEFAULT_FIRMWARE, true, true), ConfigSetting("NickName", &g_Config.sNickName, "PPSSPP", true, true), - ConfigSetting("proAdhocServer", &g_Config.proAdhocServer, "coldbird.net", true, true), + ConfigSetting("proAdhocServer", &g_Config.proAdhocServer, "black-seraph.com", true, true), ConfigSetting("MacAddress", &g_Config.sMACAddress, "", true, true), ConfigSetting("PortOffset", &g_Config.iPortOffset, 0, true, true), ReportedConfigSetting("Language", &g_Config.iLanguage, &DefaultSystemParamLanguage, true, true), From c73b13781c72ec25bb4c71dd2f21494802731691 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 17 Nov 2018 08:55:00 -0800 Subject: [PATCH 134/347] Core: Fix spurious error on Linux/Unix paths. CreateFullPath with an absolute path would try to create ''. --- Common/FileUtil.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/FileUtil.cpp b/Common/FileUtil.cpp index c6a19a2c00..e8dbc62091 100644 --- a/Common/FileUtil.cpp +++ b/Common/FileUtil.cpp @@ -336,7 +336,7 @@ bool CreateFullPath(const std::string &path) return true; } std::string subPath = fullPath.substr(0, position); - if (!File::Exists(subPath)) + if (position != 0 && !File::Exists(subPath)) File::CreateDir(subPath); // A safety check From 7af93d08cf73af4928a7bbcffa01bd229d74f12e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 21 Nov 2018 17:33:30 +0100 Subject: [PATCH 135/347] VK: Add extra safety checks around font texture creation. Motivated by some Play crashes. --- .../src/org/ppsspp/ppsspp/TextRenderer.java | 5 ++++ ext/native/gfx_es2/draw_text_android.cpp | 20 +++++++++---- ext/native/thin3d/VulkanRenderManager.cpp | 4 ++- ext/native/thin3d/thin3d_vulkan.cpp | 30 ++++++++++++------- 4 files changed, 41 insertions(+), 18 deletions(-) diff --git a/android/src/org/ppsspp/ppsspp/TextRenderer.java b/android/src/org/ppsspp/ppsspp/TextRenderer.java index 7ecdeb9a7f..6e753c8739 100644 --- a/android/src/org/ppsspp/ppsspp/TextRenderer.java +++ b/android/src/org/ppsspp/ppsspp/TextRenderer.java @@ -56,10 +56,15 @@ public class TextRenderer { total.y = (int) (p.descent() - p.ascent()) * lines.length + 2; // Returning a 0 size can create problems when the caller // uses the measurement to create a texture. + // Also, clamp to a reasonable maximum size. if (total.x < 1) total.x = 1; if (total.y < 1) total.y = 1; + if (total.x > 2048) + total.x = 2048; + if (total.y > 2048) + total.y = 2048; return total; } diff --git a/ext/native/gfx_es2/draw_text_android.cpp b/ext/native/gfx_es2/draw_text_android.cpp index 7059fab399..afb9bf6104 100644 --- a/ext/native/gfx_es2/draw_text_android.cpp +++ b/ext/native/gfx_es2/draw_text_android.cpp @@ -172,7 +172,8 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x, if (iter != cache_.end()) { entry = iter->second.get(); entry->lastUsedFrame = frameCount_; - draw_->BindTexture(0, entry->texture); + if (entry->texture) + draw_->BindTexture(0, entry->texture); } else { double size = 0.0; auto iter = fontMap_.find(fontHash_); @@ -195,8 +196,10 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x, env_->DeleteLocalRef(jstr); entry = new TextStringEntry(); - entry->bmWidth = entry->width = imageWidth; - entry->bmHeight = entry->height = imageHeight; + entry->bmWidth = imageWidth; + entry->width = imageWidth; + entry->bmHeight = imageHeight; + entry->height = imageHeight; entry->lastUsedFrame = frameCount_; TextureDesc desc{}; @@ -206,6 +209,7 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x, desc.height = entry->bmHeight; desc.depth = 1; desc.mipLevels = 1; + desc.generateMips = false; desc.tag = "TextDrawer"; uint16_t *bitmapData = new uint16_t[entry->bmWidth * entry->bmHeight]; @@ -224,13 +228,17 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x, entry->texture = draw_->CreateTexture(desc); delete[] bitmapData; cache_[key] = std::unique_ptr(entry); - draw_->BindTexture(0, entry->texture); + if (entry->texture) { + draw_->BindTexture(0, entry->texture); + } } float w = entry->bmWidth * fontScaleX_ * dpiScale_; float h = entry->bmHeight * fontScaleY_ * dpiScale_; DrawBuffer::DoAlign(align, &x, &y, &w, &h); - target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, 1.0f, 1.0f, color); - target.Flush(true); + if (entry->texture) { + target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, 1.0f, 1.0f, color); + target.Flush(true); + } } void TextDrawerAndroid::ClearCache() { diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index f18b6129bc..fb36d8a3df 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -380,7 +380,9 @@ VkCommandBuffer VulkanRenderManager::GetInitCmd() { VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT }; VkResult res = vkBeginCommandBuffer(frameData.initCmd, &begin); - _assert_(res == VK_SUCCESS); + if (res != VK_SUCCESS) { + return VK_NULL_HANDLE; + } frameData.hasInitCommands = true; } return frameData_[curFrame].initCmd; diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 37d6497b51..41c94444b3 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -301,11 +301,9 @@ struct DescriptorSetKey { class VKTexture : public Texture { public: - VKTexture(VulkanContext *vulkan, VkCommandBuffer cmd, VulkanPushBuffer *pushBuffer, const TextureDesc &desc, VulkanDeviceAllocator *alloc) - : vulkan_(vulkan), mipLevels_(desc.mipLevels), format_(desc.format) { - bool result = Create(cmd, pushBuffer, desc, alloc); - _assert_(result); - } + VKTexture(VulkanContext *vulkan, VkCommandBuffer cmd, VulkanPushBuffer *pushBuffer, const TextureDesc &desc) + : vulkan_(vulkan), mipLevels_(desc.mipLevels), format_(desc.format) {} + bool Create(VkCommandBuffer cmd, VulkanPushBuffer *pushBuffer, const TextureDesc &desc, VulkanDeviceAllocator *alloc); ~VKTexture() { Destroy(); @@ -322,8 +320,6 @@ public: } private: - bool Create(VkCommandBuffer cmd, VulkanPushBuffer *pushBuffer, const TextureDesc &desc, VulkanDeviceAllocator *alloc); - void Destroy() { if (vkTex_) { vkTex_->Destroy(); @@ -335,9 +331,9 @@ private: VulkanContext *vulkan_; VulkanTexture *vkTex_ = nullptr; - int mipLevels_; + int mipLevels_ = 0; - DataFormat format_; + DataFormat format_ = DataFormat::UNDEFINED; }; class VKFramebuffer; @@ -698,6 +694,10 @@ enum class TextureState { bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const TextureDesc &desc, VulkanDeviceAllocator *alloc) { // Zero-sized textures not allowed. _assert_(desc.width * desc.height * desc.depth > 0); // remember to set depth to 1! + if (desc.width * desc.height * desc.depth <= 0) { + ELOG("Bad texture dimensions %dx%dx%d", desc.width, desc.height, desc.depth); + return false; + } _assert_(push); format_ = desc.format; mipLevels_ = desc.mipLevels; @@ -1079,12 +1079,20 @@ InputLayout *VKContext::CreateInputLayout(const InputLayoutDesc &desc) { } Texture *VKContext::CreateTexture(const TextureDesc &desc) { - if (!push_ || !renderManager_.GetInitCmd()) { + VkCommandBuffer initCmd = renderManager_.GetInitCmd(); + if (!push_ || !initCmd) { // Too early! Fail. ELOG("Can't create textures before the first frame has started."); return nullptr; } - return new VKTexture(vulkan_, renderManager_.GetInitCmd(), push_, desc, allocator_); + VKTexture *tex = new VKTexture(vulkan_, initCmd, push_, desc); + if (tex->Create(initCmd, push_, desc, allocator_)) { + return tex; + } else { + ELOG("Failed to create texture"); + delete tex; + return nullptr; + } } static inline void CopySide(VkStencilOpState &dest, const StencilSide &src) { From f2244f789e6c64fede1cea006804875f1c7aec78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 21 Nov 2018 17:33:30 +0100 Subject: [PATCH 136/347] VK: Add extra safety checks around font texture creation. Motivated by some Play crashes. --- .../src/org/ppsspp/ppsspp/TextRenderer.java | 5 ++++ ext/native/gfx_es2/draw_text_android.cpp | 20 +++++++++---- ext/native/thin3d/VulkanRenderManager.cpp | 4 ++- ext/native/thin3d/thin3d_vulkan.cpp | 30 ++++++++++++------- 4 files changed, 41 insertions(+), 18 deletions(-) diff --git a/android/src/org/ppsspp/ppsspp/TextRenderer.java b/android/src/org/ppsspp/ppsspp/TextRenderer.java index 7ecdeb9a7f..6e753c8739 100644 --- a/android/src/org/ppsspp/ppsspp/TextRenderer.java +++ b/android/src/org/ppsspp/ppsspp/TextRenderer.java @@ -56,10 +56,15 @@ public class TextRenderer { total.y = (int) (p.descent() - p.ascent()) * lines.length + 2; // Returning a 0 size can create problems when the caller // uses the measurement to create a texture. + // Also, clamp to a reasonable maximum size. if (total.x < 1) total.x = 1; if (total.y < 1) total.y = 1; + if (total.x > 2048) + total.x = 2048; + if (total.y > 2048) + total.y = 2048; return total; } diff --git a/ext/native/gfx_es2/draw_text_android.cpp b/ext/native/gfx_es2/draw_text_android.cpp index 7059fab399..afb9bf6104 100644 --- a/ext/native/gfx_es2/draw_text_android.cpp +++ b/ext/native/gfx_es2/draw_text_android.cpp @@ -172,7 +172,8 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x, if (iter != cache_.end()) { entry = iter->second.get(); entry->lastUsedFrame = frameCount_; - draw_->BindTexture(0, entry->texture); + if (entry->texture) + draw_->BindTexture(0, entry->texture); } else { double size = 0.0; auto iter = fontMap_.find(fontHash_); @@ -195,8 +196,10 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x, env_->DeleteLocalRef(jstr); entry = new TextStringEntry(); - entry->bmWidth = entry->width = imageWidth; - entry->bmHeight = entry->height = imageHeight; + entry->bmWidth = imageWidth; + entry->width = imageWidth; + entry->bmHeight = imageHeight; + entry->height = imageHeight; entry->lastUsedFrame = frameCount_; TextureDesc desc{}; @@ -206,6 +209,7 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x, desc.height = entry->bmHeight; desc.depth = 1; desc.mipLevels = 1; + desc.generateMips = false; desc.tag = "TextDrawer"; uint16_t *bitmapData = new uint16_t[entry->bmWidth * entry->bmHeight]; @@ -224,13 +228,17 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x, entry->texture = draw_->CreateTexture(desc); delete[] bitmapData; cache_[key] = std::unique_ptr(entry); - draw_->BindTexture(0, entry->texture); + if (entry->texture) { + draw_->BindTexture(0, entry->texture); + } } float w = entry->bmWidth * fontScaleX_ * dpiScale_; float h = entry->bmHeight * fontScaleY_ * dpiScale_; DrawBuffer::DoAlign(align, &x, &y, &w, &h); - target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, 1.0f, 1.0f, color); - target.Flush(true); + if (entry->texture) { + target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, 1.0f, 1.0f, color); + target.Flush(true); + } } void TextDrawerAndroid::ClearCache() { diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index f18b6129bc..fb36d8a3df 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -380,7 +380,9 @@ VkCommandBuffer VulkanRenderManager::GetInitCmd() { VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT }; VkResult res = vkBeginCommandBuffer(frameData.initCmd, &begin); - _assert_(res == VK_SUCCESS); + if (res != VK_SUCCESS) { + return VK_NULL_HANDLE; + } frameData.hasInitCommands = true; } return frameData_[curFrame].initCmd; diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 37d6497b51..41c94444b3 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -301,11 +301,9 @@ struct DescriptorSetKey { class VKTexture : public Texture { public: - VKTexture(VulkanContext *vulkan, VkCommandBuffer cmd, VulkanPushBuffer *pushBuffer, const TextureDesc &desc, VulkanDeviceAllocator *alloc) - : vulkan_(vulkan), mipLevels_(desc.mipLevels), format_(desc.format) { - bool result = Create(cmd, pushBuffer, desc, alloc); - _assert_(result); - } + VKTexture(VulkanContext *vulkan, VkCommandBuffer cmd, VulkanPushBuffer *pushBuffer, const TextureDesc &desc) + : vulkan_(vulkan), mipLevels_(desc.mipLevels), format_(desc.format) {} + bool Create(VkCommandBuffer cmd, VulkanPushBuffer *pushBuffer, const TextureDesc &desc, VulkanDeviceAllocator *alloc); ~VKTexture() { Destroy(); @@ -322,8 +320,6 @@ public: } private: - bool Create(VkCommandBuffer cmd, VulkanPushBuffer *pushBuffer, const TextureDesc &desc, VulkanDeviceAllocator *alloc); - void Destroy() { if (vkTex_) { vkTex_->Destroy(); @@ -335,9 +331,9 @@ private: VulkanContext *vulkan_; VulkanTexture *vkTex_ = nullptr; - int mipLevels_; + int mipLevels_ = 0; - DataFormat format_; + DataFormat format_ = DataFormat::UNDEFINED; }; class VKFramebuffer; @@ -698,6 +694,10 @@ enum class TextureState { bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const TextureDesc &desc, VulkanDeviceAllocator *alloc) { // Zero-sized textures not allowed. _assert_(desc.width * desc.height * desc.depth > 0); // remember to set depth to 1! + if (desc.width * desc.height * desc.depth <= 0) { + ELOG("Bad texture dimensions %dx%dx%d", desc.width, desc.height, desc.depth); + return false; + } _assert_(push); format_ = desc.format; mipLevels_ = desc.mipLevels; @@ -1079,12 +1079,20 @@ InputLayout *VKContext::CreateInputLayout(const InputLayoutDesc &desc) { } Texture *VKContext::CreateTexture(const TextureDesc &desc) { - if (!push_ || !renderManager_.GetInitCmd()) { + VkCommandBuffer initCmd = renderManager_.GetInitCmd(); + if (!push_ || !initCmd) { // Too early! Fail. ELOG("Can't create textures before the first frame has started."); return nullptr; } - return new VKTexture(vulkan_, renderManager_.GetInitCmd(), push_, desc, allocator_); + VKTexture *tex = new VKTexture(vulkan_, initCmd, push_, desc); + if (tex->Create(initCmd, push_, desc, allocator_)) { + return tex; + } else { + ELOG("Failed to create texture"); + delete tex; + return nullptr; + } } static inline void CopySide(VkStencilOpState &dest, const StencilSide &src) { From 429a1fce012da54b60515c9cb3d53ef346e1d281 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 21 Nov 2018 18:13:48 +0100 Subject: [PATCH 137/347] Assert even in release mode if preset shaders fail to compile. This is just to help track down a Play crash. --- Qt/QtMain.h | 2 +- Windows/GPU/D3D11Context.cpp | 2 +- Windows/GPU/WindowsGLContext.cpp | 2 +- Windows/GPU/WindowsVulkanContext.cpp | 2 +- android/jni/AndroidEGLContext.cpp | 2 +- android/jni/AndroidJavaGLContext.cpp | 1 + android/jni/AndroidVulkanContext.cpp | 2 +- ios/ViewController.mm | 2 +- 8 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Qt/QtMain.h b/Qt/QtMain.h index 58fefb6cfe..70d89b88d8 100644 --- a/Qt/QtMain.h +++ b/Qt/QtMain.h @@ -54,7 +54,7 @@ public: SetGPUBackend(GPUBackend::OPENGL); renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); bool success = draw_->CreatePresets(); - assert(success); + _assert_msg_(G3D, success, "Failed to compile preset shaders"); } ~QtGLGraphicsContext() { diff --git a/Windows/GPU/D3D11Context.cpp b/Windows/GPU/D3D11Context.cpp index c5ef162b20..183a3d0529 100644 --- a/Windows/GPU/D3D11Context.cpp +++ b/Windows/GPU/D3D11Context.cpp @@ -176,7 +176,7 @@ bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) { draw_ = Draw::T3DCreateD3D11Context(device_, context_, device1_, context1_, featureLevel_, hWnd_, adapterNames); SetGPUBackend(GPUBackend::DIRECT3D11, chosenAdapterName); bool success = draw_->CreatePresets(); // If we can run D3D11, there's a compiler installed. I think. - assert(success); + _assert_msg_(G3D, success, "Failed to compile preset shaders"); int width; int height; diff --git a/Windows/GPU/WindowsGLContext.cpp b/Windows/GPU/WindowsGLContext.cpp index c6c09f5e2d..002464cf27 100644 --- a/Windows/GPU/WindowsGLContext.cpp +++ b/Windows/GPU/WindowsGLContext.cpp @@ -405,7 +405,7 @@ bool WindowsGLContext::InitFromRenderThread(std::string *error_message) { renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); SetGPUBackend(GPUBackend::OPENGL); bool success = draw_->CreatePresets(); // if we get this far, there will always be a GLSL compiler capable of compiling these. - assert(success); + _assert_msg_(G3D, success, "Failed to compile preset shaders"); renderManager_->SetSwapFunction([&]() {::SwapBuffers(hDC); }); if (wglSwapIntervalEXT) { // glew loads wglSwapIntervalEXT if available diff --git a/Windows/GPU/WindowsVulkanContext.cpp b/Windows/GPU/WindowsVulkanContext.cpp index c0c512d7bb..541d435ec9 100644 --- a/Windows/GPU/WindowsVulkanContext.cpp +++ b/Windows/GPU/WindowsVulkanContext.cpp @@ -142,7 +142,7 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m draw_ = Draw::T3DCreateVulkanContext(g_Vulkan, splitSubmit); SetGPUBackend(GPUBackend::VULKAN, g_Vulkan->GetPhysicalDeviceProperties(deviceNum).deviceName); bool success = draw_->CreatePresets(); - assert(success); // Doesn't fail, we include the compiler. + _assert_msg_(G3D, success, "Failed to compile preset shaders"); draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); diff --git a/android/jni/AndroidEGLContext.cpp b/android/jni/AndroidEGLContext.cpp index 34d21597f5..163c123fa7 100644 --- a/android/jni/AndroidEGLContext.cpp +++ b/android/jni/AndroidEGLContext.cpp @@ -52,7 +52,7 @@ bool AndroidEGLGraphicsContext::InitFromRenderThread(ANativeWindow *wnd, int des SetGPUBackend(GPUBackend::OPENGL); renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); bool success = draw_->CreatePresets(); // There will always be a GLSL compiler capable of compiling these. - assert(success); + _assert_msg_(G3D, success, "Failed to compile preset shaders"); return true; } diff --git a/android/jni/AndroidJavaGLContext.cpp b/android/jni/AndroidJavaGLContext.cpp index aca9f8fcc9..2d463e76dc 100644 --- a/android/jni/AndroidJavaGLContext.cpp +++ b/android/jni/AndroidJavaGLContext.cpp @@ -16,6 +16,7 @@ bool AndroidJavaEGLGraphicsContext::InitFromRenderThread(ANativeWindow *wnd, int draw_ = Draw::T3DCreateGLContext(); renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); bool success = draw_->CreatePresets(); + _assert_msg_(G3D, success, "Failed to compile preset shaders"); return success; } diff --git a/android/jni/AndroidVulkanContext.cpp b/android/jni/AndroidVulkanContext.cpp index 128183dcc9..0e597e0a7e 100644 --- a/android/jni/AndroidVulkanContext.cpp +++ b/android/jni/AndroidVulkanContext.cpp @@ -152,7 +152,7 @@ bool AndroidVulkanContext::InitFromRenderThread(ANativeWindow *wnd, int desiredB draw_ = Draw::T3DCreateVulkanContext(g_Vulkan, g_Config.bGfxDebugSplitSubmit); SetGPUBackend(GPUBackend::VULKAN); success = draw_->CreatePresets(); // Doesn't fail, we ship the compiler. - assert(success); + _assert_msg_(G3D, success, "Failed to compile preset shaders"); draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); diff --git a/ios/ViewController.mm b/ios/ViewController.mm index 3ca85ebcdf..61c2eee554 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -42,7 +42,7 @@ public: renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); SetGPUBackend(GPUBackend::OPENGL); bool success = draw_->CreatePresets(); - assert(success); + _assert_msg_(G3D, success, "Failed to compile preset shaders"); } ~IOSGraphicsContext() { delete draw_; From 0fd5d10ab8a07670428a9bf8b397e26086190c6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 21 Nov 2018 22:15:01 +0100 Subject: [PATCH 138/347] Attempt to fix the last very common issue of #11493 by being paranoid --- GPU/GLES/DepalettizeShaderGLES.cpp | 4 +--- GPU/GLES/DepalettizeShaderGLES.h | 4 ++-- GPU/GPU.cpp | 1 + UI/EmuScreen.cpp | 1 + ext/native/thin3d/GLQueueRunner.cpp | 4 +++- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/GPU/GLES/DepalettizeShaderGLES.cpp b/GPU/GLES/DepalettizeShaderGLES.cpp index b18ddd5876..5886df27ee 100644 --- a/GPU/GLES/DepalettizeShaderGLES.cpp +++ b/GPU/GLES/DepalettizeShaderGLES.cpp @@ -50,6 +50,7 @@ static const char *depalVShader300 = "}\n"; DepalShaderCacheGLES::DepalShaderCacheGLES(Draw::DrawContext *draw) { + _assert_(draw); render_ = (GLRenderManager *)draw->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); // Pre-build the vertex program useGL3_ = gl_extensions.GLES3 || gl_extensions.VersionGEThan(3, 3); @@ -57,9 +58,6 @@ DepalShaderCacheGLES::DepalShaderCacheGLES(Draw::DrawContext *draw) { // Use the floating point path, it just can't handle the math. useGL3_ = false; } - - vertexShaderFailed_ = false; - vertexShader_ = 0; } DepalShaderCacheGLES::~DepalShaderCacheGLES() { diff --git a/GPU/GLES/DepalettizeShaderGLES.h b/GPU/GLES/DepalettizeShaderGLES.h index e183ba22b0..c93ef87fc0 100644 --- a/GPU/GLES/DepalettizeShaderGLES.h +++ b/GPU/GLES/DepalettizeShaderGLES.h @@ -64,8 +64,8 @@ private: GLRenderManager *render_; bool useGL3_; - bool vertexShaderFailed_; - GLRShader *vertexShader_; + bool vertexShaderFailed_ = false; + GLRShader *vertexShader_ = nullptr; std::map cache_; std::map texCache_; }; diff --git a/GPU/GPU.cpp b/GPU/GPU.cpp index e7026973b4..3a4f9a921e 100644 --- a/GPU/GPU.cpp +++ b/GPU/GPU.cpp @@ -61,6 +61,7 @@ bool GPU_IsReady() { } bool GPU_Init(GraphicsContext *ctx, Draw::DrawContext *draw) { + _assert_(draw); #if PPSSPP_PLATFORM(UWP) SetGPU(new GPU_D3D11(ctx, draw)); return true; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 023419fc66..07ea5d49a9 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -231,6 +231,7 @@ void EmuScreen::bootGame(const std::string &filename) { if (g_Config.bSoftwareRendering) { coreParam.gpuCore = GPUCORE_SOFTWARE; } + // Preserve the existing graphics context. coreParam.graphicsContext = PSP_CoreParameter().graphicsContext; coreParam.thin3d = screenManager()->getDrawContext(); diff --git a/ext/native/thin3d/GLQueueRunner.cpp b/ext/native/thin3d/GLQueueRunner.cpp index 6d123518e3..31a1cca8ae 100644 --- a/ext/native/thin3d/GLQueueRunner.cpp +++ b/ext/native/thin3d/GLQueueRunner.cpp @@ -66,8 +66,10 @@ void GLQueueRunner::DestroyDeviceObjects() { glDeleteVertexArrays(1, &globalVAO_); } delete[] readbackBuffer_; + readbackBuffer_ = nullptr; readbackBufferSize_ = 0; delete[] tempBuffer_; + tempBuffer_ = nullptr; tempBufferSize_ = 0; CHECK_GL_ERROR_IF_DEBUG(); } @@ -1200,7 +1202,7 @@ void GLQueueRunner::PerformReadback(const GLRStep &pass) { if (!gl_extensions.IsGLES || gl_extensions.GLES3) { glPixelStorei(GL_PACK_ROW_LENGTH, 0); } - if (convert) { + if (convert && tempBuffer_ && readbackBuffer_) { ConvertFromRGBA8888(readbackBuffer_, tempBuffer_, pixelStride, pixelStride, rect.w, rect.h, pass.readback.dstFormat); } From dc49e839dd4a2972413a40c596ca9bace1250fbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 21 Nov 2018 22:29:21 +0100 Subject: [PATCH 139/347] VK: Workaround for validation bug (will be fixed in the next Vulkan SDK) --- Common/Vulkan/VulkanDebug.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Common/Vulkan/VulkanDebug.cpp b/Common/Vulkan/VulkanDebug.cpp index 0ee407b735..e0d945df38 100644 --- a/Common/Vulkan/VulkanDebug.cpp +++ b/Common/Vulkan/VulkanDebug.cpp @@ -79,6 +79,8 @@ VkBool32 VKAPI_CALL Vulkan_Dbg(VkDebugReportFlagsEXT msgFlags, VkDebugReportObje return false; if (msgCode == 5) return false; // Not exactly a false positive, see https://github.com/KhronosGroup/glslang/issues/1418 + if (msgCode == 0 && strstr(pMsg, "vertexPipelineStoresAndAtomics")) // https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/73 + return false; #ifdef _WIN32 std::string msg = message.str(); OutputDebugStringA(msg.c_str()); From 442b57033ff1e4aed602d954c61ed0b9b28ded3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 21 Nov 2018 22:15:01 +0100 Subject: [PATCH 140/347] Attempt to fix the last very common issue of #11493 by being paranoid --- GPU/GLES/DepalettizeShaderGLES.cpp | 4 +--- GPU/GLES/DepalettizeShaderGLES.h | 4 ++-- GPU/GPU.cpp | 1 + UI/EmuScreen.cpp | 1 + ext/native/thin3d/GLQueueRunner.cpp | 4 +++- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/GPU/GLES/DepalettizeShaderGLES.cpp b/GPU/GLES/DepalettizeShaderGLES.cpp index b18ddd5876..5886df27ee 100644 --- a/GPU/GLES/DepalettizeShaderGLES.cpp +++ b/GPU/GLES/DepalettizeShaderGLES.cpp @@ -50,6 +50,7 @@ static const char *depalVShader300 = "}\n"; DepalShaderCacheGLES::DepalShaderCacheGLES(Draw::DrawContext *draw) { + _assert_(draw); render_ = (GLRenderManager *)draw->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); // Pre-build the vertex program useGL3_ = gl_extensions.GLES3 || gl_extensions.VersionGEThan(3, 3); @@ -57,9 +58,6 @@ DepalShaderCacheGLES::DepalShaderCacheGLES(Draw::DrawContext *draw) { // Use the floating point path, it just can't handle the math. useGL3_ = false; } - - vertexShaderFailed_ = false; - vertexShader_ = 0; } DepalShaderCacheGLES::~DepalShaderCacheGLES() { diff --git a/GPU/GLES/DepalettizeShaderGLES.h b/GPU/GLES/DepalettizeShaderGLES.h index e183ba22b0..c93ef87fc0 100644 --- a/GPU/GLES/DepalettizeShaderGLES.h +++ b/GPU/GLES/DepalettizeShaderGLES.h @@ -64,8 +64,8 @@ private: GLRenderManager *render_; bool useGL3_; - bool vertexShaderFailed_; - GLRShader *vertexShader_; + bool vertexShaderFailed_ = false; + GLRShader *vertexShader_ = nullptr; std::map cache_; std::map texCache_; }; diff --git a/GPU/GPU.cpp b/GPU/GPU.cpp index e7026973b4..3a4f9a921e 100644 --- a/GPU/GPU.cpp +++ b/GPU/GPU.cpp @@ -61,6 +61,7 @@ bool GPU_IsReady() { } bool GPU_Init(GraphicsContext *ctx, Draw::DrawContext *draw) { + _assert_(draw); #if PPSSPP_PLATFORM(UWP) SetGPU(new GPU_D3D11(ctx, draw)); return true; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index fe82bf2373..91220e16b5 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -231,6 +231,7 @@ void EmuScreen::bootGame(const std::string &filename) { if (g_Config.bSoftwareRendering) { coreParam.gpuCore = GPUCORE_SOFTWARE; } + // Preserve the existing graphics context. coreParam.graphicsContext = PSP_CoreParameter().graphicsContext; coreParam.thin3d = screenManager()->getDrawContext(); diff --git a/ext/native/thin3d/GLQueueRunner.cpp b/ext/native/thin3d/GLQueueRunner.cpp index 49031eafca..fbb66b188c 100644 --- a/ext/native/thin3d/GLQueueRunner.cpp +++ b/ext/native/thin3d/GLQueueRunner.cpp @@ -66,8 +66,10 @@ void GLQueueRunner::DestroyDeviceObjects() { glDeleteVertexArrays(1, &globalVAO_); } delete[] readbackBuffer_; + readbackBuffer_ = nullptr; readbackBufferSize_ = 0; delete[] tempBuffer_; + tempBuffer_ = nullptr; tempBufferSize_ = 0; CHECK_GL_ERROR_IF_DEBUG(); } @@ -1241,7 +1243,7 @@ void GLQueueRunner::PerformReadback(const GLRStep &pass) { if (!gl_extensions.IsGLES || gl_extensions.GLES3) { glPixelStorei(GL_PACK_ROW_LENGTH, 0); } - if (convert) { + if (convert && tempBuffer_ && readbackBuffer_) { ConvertFromRGBA8888(readbackBuffer_, tempBuffer_, pixelStride, pixelStride, rect.w, rect.h, pass.readback.dstFormat); } From c944063d03cbebb4223060da5620002796975e17 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 22 Nov 2018 07:58:08 -0800 Subject: [PATCH 141/347] Reporting: Ignore link error with bad shaders. We only need the issue reported once. --- ext/native/thin3d/GLQueueRunner.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ext/native/thin3d/GLQueueRunner.cpp b/ext/native/thin3d/GLQueueRunner.cpp index 49031eafca..828aab92b8 100644 --- a/ext/native/thin3d/GLQueueRunner.cpp +++ b/ext/native/thin3d/GLQueueRunner.cpp @@ -171,8 +171,10 @@ void GLQueueRunner::RunInitSteps(const std::vector &steps, bool ski GLRProgram *program = step.create_program.program; program->program = glCreateProgram(); _assert_msg_(G3D, step.create_program.num_shaders > 0, "Can't create a program with zero shaders"); + bool anyFailed = false; for (int j = 0; j < step.create_program.num_shaders; j++) { _dbg_assert_msg_(G3D, step.create_program.shaders[j]->shader, "Can't create a program with a null shader"); + anyFailed = anyFailed || step.create_program.shaders[j]->failed; glAttachShader(program->program, step.create_program.shaders[j]->shader); } @@ -208,7 +210,8 @@ void GLQueueRunner::RunInitSteps(const std::vector &steps, bool ski std::string fsDesc = fs ? (fs->desc + (fs->failed ? " (failed)" : "")) : "(none)"; const char *vsCode = vs->code.c_str(); const char *fsCode = fs ? fs->code.c_str() : "(none)"; - Reporting::ReportMessage("Error in shader program link: info: %s\nfs: %s\n%s\nvs: %s\n%s", infoLog.c_str(), fsDesc.c_str(), fsCode, vsDesc.c_str(), vsCode); + if (!anyFailed) + Reporting::ReportMessage("Error in shader program link: info: %s\nfs: %s\n%s\nvs: %s\n%s", infoLog.c_str(), fsDesc.c_str(), fsCode, vsDesc.c_str(), vsCode); ELOG("Could not link program:\n %s", infoLog.c_str()); ERROR_LOG(G3D, "VS desc:\n%s", vsDesc.c_str()); From 9a4cd5bd9de72a17a8e380a1a31a5bccea17b604 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 22 Nov 2018 07:59:56 -0800 Subject: [PATCH 142/347] GPU: Skip specular on powered diffuse. Matches hardware tests and improves lighting for Virtua Tennis, see #4140. --- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 8 ++++---- GPU/GLES/VertexShaderGeneratorGLES.cpp | 8 ++++---- GPU/GPUState.h | 4 ++-- GPU/Vulkan/VertexShaderGeneratorVulkan.cpp | 6 +++--- GPU/ge_constants.h | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 9b456fe3a3..75338e78c2 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -159,7 +159,7 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage WRITE(p, "float3 u_lightambient%i : register(c%i);\n", i, CONST_VS_LIGHTAMBIENT + i); WRITE(p, "float3 u_lightdiffuse%i : register(c%i);\n", i, CONST_VS_LIGHTDIFFUSE + i); - if (comp != GE_LIGHTCOMP_ONLYDIFFUSE) { + if (comp == GE_LIGHTCOMP_BOTH) { WRITE(p, "float3 u_lightspecular%i : register(c%i);\n", i, CONST_VS_LIGHTSPECULAR + i); } } @@ -536,7 +536,7 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage if (doLight[i] != LIGHT_FULL) continue; diffuseIsZero = false; - if (comp != GE_LIGHTCOMP_ONLYDIFFUSE) + if (comp == GE_LIGHTCOMP_BOTH) specularIsZero = false; if (type != GE_LIGHTTYPE_DIRECTIONAL) distanceNeeded = true; @@ -579,8 +579,8 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage WRITE(p, " toLight /= distance;\n"); } - bool doSpecular = comp != GE_LIGHTCOMP_ONLYDIFFUSE; - bool poweredDiffuse = comp == GE_LIGHTCOMP_BOTHWITHPOWDIFFUSE; + bool doSpecular = comp == GE_LIGHTCOMP_BOTH; + bool poweredDiffuse = comp == GE_LIGHTCOMP_ONLYPOWDIFFUSE; WRITE(p, " ldot = max(dot(toLight, worldnormal), 0.0);\n"); if (poweredDiffuse) { diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index c51da43f75..17a6205385 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -308,7 +308,7 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, WRITE(p, "uniform lowp vec3 u_lightambient%i;\n", i); WRITE(p, "uniform lowp vec3 u_lightdiffuse%i;\n", i); - if (comp != GE_LIGHTCOMP_ONLYDIFFUSE) { + if (comp == GE_LIGHTCOMP_BOTH) { WRITE(p, "uniform lowp vec3 u_lightspecular%i;\n", i); } } @@ -630,7 +630,7 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, if (doLight[i] != LIGHT_FULL) continue; diffuseIsZero = false; - if (comp != GE_LIGHTCOMP_ONLYDIFFUSE) + if (comp == GE_LIGHTCOMP_BOTH) specularIsZero = false; if (type != GE_LIGHTTYPE_DIRECTIONAL) distanceNeeded = true; @@ -673,8 +673,8 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, WRITE(p, " toLight /= distance;\n"); } - bool doSpecular = comp != GE_LIGHTCOMP_ONLYDIFFUSE; - bool poweredDiffuse = comp == GE_LIGHTCOMP_BOTHWITHPOWDIFFUSE; + bool doSpecular = comp == GE_LIGHTCOMP_BOTH; + bool poweredDiffuse = comp == GE_LIGHTCOMP_ONLYPOWDIFFUSE; WRITE(p, " ldot = max(dot(toLight, worldnormal), 0.0);\n"); if (poweredDiffuse) { diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 25e81c6477..a3e2e4e9d4 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -326,8 +326,8 @@ struct GPUgstate { bool isLightingEnabled() const { return lightingEnable & 1; } bool isLightChanEnabled(int chan) const { return lightEnable[chan] & 1; } GELightComputation getLightComputation(int chan) const { return static_cast(ltype[chan] & 0x3); } - bool isUsingPoweredDiffuseLight(int chan) const { return getLightComputation(chan) == GE_LIGHTCOMP_BOTHWITHPOWDIFFUSE; } - bool isUsingSpecularLight(int chan) const { return getLightComputation(chan) != GE_LIGHTCOMP_ONLYDIFFUSE; } + bool isUsingPoweredDiffuseLight(int chan) const { return getLightComputation(chan) == GE_LIGHTCOMP_ONLYPOWDIFFUSE; } + bool isUsingSpecularLight(int chan) const { return getLightComputation(chan) == GE_LIGHTCOMP_BOTH; } bool isUsingSecondaryColor() const { return lmode & 1; } GELightType getLightType(int chan) const { return static_cast((ltype[chan] >> 8) & 3); } bool isDirectionalLight(int chan) const { return getLightType(chan) == GE_LIGHTTYPE_DIRECTIONAL; } diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index e64e81508d..e18b2ee71d 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -425,7 +425,7 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { if (doLight[i] != LIGHT_FULL) continue; diffuseIsZero = false; - if (comp != GE_LIGHTCOMP_ONLYDIFFUSE) + if (comp == GE_LIGHTCOMP_BOTH) specularIsZero = false; if (type != GE_LIGHTTYPE_DIRECTIONAL) distanceNeeded = true; @@ -462,8 +462,8 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { WRITE(p, " toLight /= distance;\n"); } - bool doSpecular = comp != GE_LIGHTCOMP_ONLYDIFFUSE; - bool poweredDiffuse = comp == GE_LIGHTCOMP_BOTHWITHPOWDIFFUSE; + bool doSpecular = comp == GE_LIGHTCOMP_BOTH; + bool poweredDiffuse = comp == GE_LIGHTCOMP_ONLYPOWDIFFUSE; WRITE(p, " mediump float dot%i = max(dot(toLight, worldnormal), 0.0);\n", i); if (poweredDiffuse) { diff --git a/GPU/ge_constants.h b/GPU/ge_constants.h index b765af5bcb..e9509767f0 100644 --- a/GPU/ge_constants.h +++ b/GPU/ge_constants.h @@ -395,7 +395,7 @@ enum GELightComputation { GE_LIGHTCOMP_ONLYDIFFUSE = 0, GE_LIGHTCOMP_BOTH = 1, - GE_LIGHTCOMP_BOTHWITHPOWDIFFUSE = 2, + GE_LIGHTCOMP_ONLYPOWDIFFUSE = 2, }; enum GETextureFormat From 1cec9f5ea1dd060277bc643afc957647c877d683 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 22 Nov 2018 08:08:34 -0800 Subject: [PATCH 143/347] GPU: Handle spot light with 0 exp or length. --- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 4 ++-- GPU/GLES/VertexShaderGeneratorGLES.cpp | 4 ++-- GPU/Software/Lighting.cpp | 15 +++++++++++++-- GPU/Vulkan/VertexShaderGeneratorVulkan.cpp | 4 ++-- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 75338e78c2..1bdd5c2301 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -605,9 +605,9 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage break; case GE_LIGHTTYPE_SPOT: case GE_LIGHTTYPE_UNKNOWN: - WRITE(p, " angle = dot(normalize(u_lightdir%i), toLight);\n", i); + WRITE(p, " angle = length(u_lightdir%i) == 0.0 ? 0.0 : dot(normalize(u_lightdir%i), toLight);\n", i, i); WRITE(p, " if (angle >= u_lightangle_spotCoef%i.x) {\n", i); - WRITE(p, " lightScale = clamp(1.0 / dot(u_lightatt%i, float3(1.0, distance, distance*distance)), 0.0, 1.0) * pow(angle, u_lightangle_spotCoef%i.y);\n", i, i); + WRITE(p, " lightScale = clamp(1.0 / dot(u_lightatt%i, float3(1.0, distance, distance*distance)), 0.0, 1.0) * (u_lightangle_spotCoef%i.y == 0.0 ? 1.0 : pow(angle, u_lightangle_spotCoef%i.y));\n", i, i, i); WRITE(p, " } else {\n"); WRITE(p, " lightScale = 0.0;\n"); WRITE(p, " }\n"); diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index 17a6205385..3fcf222e09 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -699,9 +699,9 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, break; case GE_LIGHTTYPE_SPOT: case GE_LIGHTTYPE_UNKNOWN: - WRITE(p, " angle = dot(normalize(u_lightdir%i), toLight);\n", i); + WRITE(p, " angle = length(u_lightdir%i) == 0.0 ? 0.0 : dot(normalize(u_lightdir%i), toLight);\n", i, i); WRITE(p, " if (angle >= u_lightangle_spotCoef%i.x) {\n", i); - WRITE(p, " lightScale = clamp(1.0 / dot(u_lightatt%i, vec3(1.0, distance, distance*distance)), 0.0, 1.0) * pow(angle, u_lightangle_spotCoef%i.y);\n", i, i); + WRITE(p, " lightScale = clamp(1.0 / dot(u_lightatt%i, vec3(1.0, distance, distance*distance)), 0.0, 1.0) * (u_lightangle_spotCoef%i.y == 0.0 ? 1.0 : pow(angle, u_lightangle_spotCoef%i.y));\n", i, i, i); WRITE(p, " } else {\n"); WRITE(p, " lightScale = 0.0;\n"); WRITE(p, " }\n"); diff --git a/GPU/Software/Lighting.cpp b/GPU/Software/Lighting.cpp index 96b0fef6cf..e4e0379235 100644 --- a/GPU/Software/Lighting.cpp +++ b/GPU/Software/Lighting.cpp @@ -25,6 +25,17 @@ static inline Vec3f GetLightVec(u32 lparams[12], int light) { return Vec3(getFloat24(lparams[3 * light]), getFloat24(lparams[3 * light + 1]), getFloat24(lparams[3 * light + 2])); } +static inline float pspLightPow(float v, float e) { + if (e == 0.0f) { + return 1.0f; + } + if (v > 0.0f) { + return pow(v, e); + } + // Negative stays negative, so let's just return the original. + return v; +} + void Process(VertexData& vertex, bool hasColor) { const int materialupdate = gstate.materialupdate & (hasColor ? 7 : 0); @@ -78,11 +89,11 @@ void Process(VertexData& vertex, bool hasColor) { float spot = 1.f; if (gstate.isSpotLight(light)) { Vec3 dir = GetLightVec(gstate.ldir, light); - float rawSpot = Dot(dir.Normalized(), L); + float rawSpot = dir.Length2() == 0.0f ? 0.0f : Dot(dir.Normalized(), L); float cutoff = getFloat24(gstate.lcutoff[light]); if (rawSpot >= cutoff) { float conv = getFloat24(gstate.lconv[light]); - spot = pow(rawSpot, conv); + spot = pspLightPow(rawSpot, conv); } else { spot = 0.f; } diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index e18b2ee71d..f65c00529d 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -488,9 +488,9 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { break; case GE_LIGHTTYPE_SPOT: case GE_LIGHTTYPE_UNKNOWN: - WRITE(p, " float angle%i = dot(normalize(light.dir[%i]), toLight);\n", i, i); + WRITE(p, " float angle%i = length(light.dir[%i]) == 0.0 ? 0.0 : dot(normalize(light.dir[%i]), toLight);\n", i, i, i); WRITE(p, " if (angle%i >= light.angle_spotCoef[%i].x) {\n", i, i); - WRITE(p, " lightScale = clamp(1.0 / dot(light.att[%i], vec3(1.0, distance, distance*distance)), 0.0, 1.0) * pow(angle%i, light.angle_spotCoef[%i].y);\n", i, i, i); + WRITE(p, " lightScale = clamp(1.0 / dot(light.att[%i], vec3(1.0, distance, distance*distance)), 0.0, 1.0) * (light.angle_spotCoef[%i].y == 0.0 ? 1.0 : pow(angle%i, light.angle_spotCoef[%i].y));\n", i, i, i, i); WRITE(p, " } else {\n"); WRITE(p, " lightScale = 0.0;\n"); WRITE(p, " }\n"); From 6e46d6c0f93103c726ef0f9004e68599492fc4d0 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 22 Nov 2018 08:10:54 -0800 Subject: [PATCH 144/347] GPU: Correct powered diffuse with exp=0. Just to ensure negative factors are handled too, as they are on hardware. --- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 2 +- GPU/GLES/VertexShaderGeneratorGLES.cpp | 2 +- GPU/Software/Lighting.cpp | 8 +------- GPU/Vulkan/VertexShaderGeneratorVulkan.cpp | 2 +- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 1bdd5c2301..332ebe0017 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -586,7 +586,7 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage if (poweredDiffuse) { // pow(0.0, 0.0) may be undefined, but the PSP seems to treat it as 1.0. // Seen in Tales of the World: Radiant Mythology (#2424.) - WRITE(p, " if (ldot == 0.0 && u_matspecular.a == 0.0) {\n"); + WRITE(p, " if (u_matspecular.a == 0.0) {\n"); WRITE(p, " ldot = 1.0;\n"); WRITE(p, " } else {\n"); WRITE(p, " ldot = pow(ldot, u_matspecular.a);\n"); diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index 3fcf222e09..daace81bc2 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -680,7 +680,7 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, if (poweredDiffuse) { // pow(0.0, 0.0) may be undefined, but the PSP seems to treat it as 1.0. // Seen in Tales of the World: Radiant Mythology (#2424.) - WRITE(p, " if (ldot == 0.0 && u_matspecular.a == 0.0) {\n"); + WRITE(p, " if (u_matspecular.a == 0.0) {\n"); WRITE(p, " ldot = 1.0;\n"); WRITE(p, " } else {\n"); WRITE(p, " ldot = pow(ldot, u_matspecular.a);\n"); diff --git a/GPU/Software/Lighting.cpp b/GPU/Software/Lighting.cpp index e4e0379235..cb45f4a5e6 100644 --- a/GPU/Software/Lighting.cpp +++ b/GPU/Software/Lighting.cpp @@ -110,13 +110,7 @@ void Process(VertexData& vertex, bool hasColor) { float diffuse_factor = Dot(L, vertex.worldnormal); if (gstate.isUsingPoweredDiffuseLight(light)) { float k = gstate.getMaterialSpecularCoef(); - // TODO: Validate Tales of the World: Radiant Mythology (#2424.) - // pow(0.0, 0.0) may be undefined, but the PSP seems to treat it as 1.0. - if (diffuse_factor <= 0.0f && k == 0.0f) { - diffuse_factor = 1.0f; - } else { - diffuse_factor = pow(diffuse_factor, k); - } + diffuse_factor = pspLightPow(diffuse_factor, k); } if (diffuse_factor > 0.f) { diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index f65c00529d..6804aec115 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -469,7 +469,7 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { if (poweredDiffuse) { // pow(0.0, 0.0) may be undefined, but the PSP seems to treat it as 1.0. // Seen in Tales of the World: Radiant Mythology (#2424.) - WRITE(p, " if (dot%i == 0.0 && light.matspecular.a == 0.0) {\n", i); + WRITE(p, " if (light.matspecular.a == 0.0) {\n"); WRITE(p, " dot%i = 1.0;\n", i); WRITE(p, " } else {\n"); WRITE(p, " dot%i = pow(dot%i, light.matspecular.a);\n", i, i); From 4816bfc1a6639aaefe311f3c8390ecbae61e154a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 22 Nov 2018 08:15:40 -0800 Subject: [PATCH 145/347] GPU: Skip specular on negative diffuse factor. This is correct per hardware tests, see #8403. Note that the PS3 emulator running PSP HD remasters does not correctly handle this, and applies specular for negative diffuse factor. --- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 12 +++++++----- GPU/GLES/VertexShaderGeneratorGLES.cpp | 12 +++++++----- GPU/Software/Lighting.cpp | 2 +- GPU/Vulkan/VertexShaderGeneratorVulkan.cpp | 12 +++++++----- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 332ebe0017..1ca697ea0e 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -582,7 +582,7 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage bool doSpecular = comp == GE_LIGHTCOMP_BOTH; bool poweredDiffuse = comp == GE_LIGHTCOMP_ONLYPOWDIFFUSE; - WRITE(p, " ldot = max(dot(toLight, worldnormal), 0.0);\n"); + WRITE(p, " ldot = dot(toLight, worldnormal);\n"); if (poweredDiffuse) { // pow(0.0, 0.0) may be undefined, but the PSP seems to treat it as 1.0. // Seen in Tales of the World: Radiant Mythology (#2424.) @@ -617,11 +617,13 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage break; } - WRITE(p, " diffuse = (u_lightdiffuse%i * %s) * ldot;\n", i, diffuseStr); + WRITE(p, " diffuse = (u_lightdiffuse%i * %s) * max(ldot, 0.0);\n", i, diffuseStr); if (doSpecular) { - WRITE(p, " ldot = dot(normalize(toLight + float3(0.0, 0.0, 1.0)), worldnormal);\n"); - WRITE(p, " if (ldot > 0.0)\n"); - WRITE(p, " lightSum1 += u_lightspecular%i * %s * (pow(ldot, u_matspecular.a) %s);\n", i, specularStr, timesLightScale); + WRITE(p, " if (ldot >= 0.0) {\n"); + WRITE(p, " ldot = dot(normalize(toLight + float3(0.0, 0.0, 1.0)), worldnormal);\n"); + WRITE(p, " if (ldot > 0.0)\n"); + WRITE(p, " lightSum1 += u_lightspecular%i * %s * (pow(ldot, u_matspecular.a) %s);\n", i, specularStr, timesLightScale); + WRITE(p, " }\n"); } WRITE(p, " lightSum0.rgb += (u_lightambient%i * %s.rgb + diffuse)%s;\n", i, ambientStr, timesLightScale); } diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index daace81bc2..63ffab8e46 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -676,7 +676,7 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, bool doSpecular = comp == GE_LIGHTCOMP_BOTH; bool poweredDiffuse = comp == GE_LIGHTCOMP_ONLYPOWDIFFUSE; - WRITE(p, " ldot = max(dot(toLight, worldnormal), 0.0);\n"); + WRITE(p, " ldot = dot(toLight, worldnormal);\n"); if (poweredDiffuse) { // pow(0.0, 0.0) may be undefined, but the PSP seems to treat it as 1.0. // Seen in Tales of the World: Radiant Mythology (#2424.) @@ -711,11 +711,13 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, break; } - WRITE(p, " diffuse = (u_lightdiffuse%i * %s) * ldot;\n", i, diffuseStr); + WRITE(p, " diffuse = (u_lightdiffuse%i * %s) * max(ldot, 0.0);\n", i, diffuseStr); if (doSpecular) { - WRITE(p, " ldot = dot(normalize(toLight + vec3(0.0, 0.0, 1.0)), worldnormal);\n"); - WRITE(p, " if (ldot > 0.0)\n"); - WRITE(p, " lightSum1 += u_lightspecular%i * %s * (pow(ldot, u_matspecular.a) %s);\n", i, specularStr, timesLightScale); + WRITE(p, " if (ldot >= 0.0) {\n"); + WRITE(p, " ldot = dot(normalize(toLight + vec3(0.0, 0.0, 1.0)), worldnormal);\n"); + WRITE(p, " if (ldot > 0.0)\n"); + WRITE(p, " lightSum1 += u_lightspecular%i * %s * (pow(ldot, u_matspecular.a) %s);\n", i, specularStr, timesLightScale); + WRITE(p, " }\n"); } WRITE(p, " lightSum0.rgb += (u_lightambient%i * %s.rgb + diffuse)%s;\n", i, ambientStr, timesLightScale); } diff --git a/GPU/Software/Lighting.cpp b/GPU/Software/Lighting.cpp index cb45f4a5e6..c9f58e7f82 100644 --- a/GPU/Software/Lighting.cpp +++ b/GPU/Software/Lighting.cpp @@ -117,7 +117,7 @@ void Process(VertexData& vertex, bool hasColor) { final_color += ldc * mdc * diffuse_factor * att * spot; } - if (gstate.isUsingSpecularLight(light)) { + if (gstate.isUsingSpecularLight(light) && diffuse_factor >= 0.0f) { Vec3 H = L + Vec3(0.f, 0.f, 1.f); Vec3 lsc = Vec3::FromRGB(gstate.getSpecularColor(light)); diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index 6804aec115..891d2ea723 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -465,7 +465,7 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { bool doSpecular = comp == GE_LIGHTCOMP_BOTH; bool poweredDiffuse = comp == GE_LIGHTCOMP_ONLYPOWDIFFUSE; - WRITE(p, " mediump float dot%i = max(dot(toLight, worldnormal), 0.0);\n", i); + WRITE(p, " mediump float dot%i = dot(toLight, worldnormal);\n", i); if (poweredDiffuse) { // pow(0.0, 0.0) may be undefined, but the PSP seems to treat it as 1.0. // Seen in Tales of the World: Radiant Mythology (#2424.) @@ -500,11 +500,13 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { break; } - WRITE(p, " diffuse = (light.diffuse[%i] * %s) * dot%i;\n", i, diffuseStr, i); + WRITE(p, " diffuse = (light.diffuse[%i] * %s) * max(dot%i, 0.0);\n", i, diffuseStr, i); if (doSpecular) { - WRITE(p, " dot%i = dot(normalize(toLight + vec3(0.0, 0.0, 1.0)), worldnormal);\n", i); - WRITE(p, " if (dot%i > 0.0)\n", i); - WRITE(p, " lightSum1 += light.specular[%i] * %s * (pow(dot%i, light.matspecular.a) %s);\n", i, specularStr, i, timesLightScale); + WRITE(p, " if (dot%i >= 0.0) {\n", i); + WRITE(p, " dot%i = dot(normalize(toLight + vec3(0.0, 0.0, 1.0)), worldnormal);\n", i); + WRITE(p, " if (dot%i > 0.0)\n", i); + WRITE(p, " lightSum1 += light.specular[%i] * %s * (pow(dot%i, light.matspecular.a) %s);\n", i, specularStr, i, timesLightScale); + WRITE(p, " }\n"); } WRITE(p, " lightSum0.rgb += (light.ambient[%i] * %s.rgb + diffuse)%s;\n", i, ambientStr, timesLightScale); } From 1c19bce514473f536facf72844cc3b6dd3d2b75c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 22 Nov 2018 08:31:32 -0800 Subject: [PATCH 146/347] GPU: Correct specular exponent zero. --- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 9 +++++++-- GPU/GLES/VertexShaderGeneratorGLES.cpp | 9 +++++++-- GPU/Software/Lighting.cpp | 2 +- GPU/Vulkan/VertexShaderGeneratorVulkan.cpp | 9 +++++++-- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 1ca697ea0e..406816031e 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -589,7 +589,7 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage WRITE(p, " if (u_matspecular.a == 0.0) {\n"); WRITE(p, " ldot = 1.0;\n"); WRITE(p, " } else {\n"); - WRITE(p, " ldot = pow(ldot, u_matspecular.a);\n"); + WRITE(p, " ldot = pow(max(ldot, 0.0), u_matspecular.a);\n"); WRITE(p, " }\n"); } @@ -621,8 +621,13 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage if (doSpecular) { WRITE(p, " if (ldot >= 0.0) {\n"); WRITE(p, " ldot = dot(normalize(toLight + float3(0.0, 0.0, 1.0)), worldnormal);\n"); + WRITE(p, " if (u_matspecular.a == 0.0) {\n"); + WRITE(p, " ldot = 1.0;\n"); + WRITE(p, " } else {\n"); + WRITE(p, " ldot = pow(max(ldot, 0.0), u_matspecular.a);\n"); + WRITE(p, " }\n"); WRITE(p, " if (ldot > 0.0)\n"); - WRITE(p, " lightSum1 += u_lightspecular%i * %s * (pow(ldot, u_matspecular.a) %s);\n", i, specularStr, timesLightScale); + WRITE(p, " lightSum1 += u_lightspecular%i * %s * ldot %s;\n", i, specularStr, timesLightScale); WRITE(p, " }\n"); } WRITE(p, " lightSum0.rgb += (u_lightambient%i * %s.rgb + diffuse)%s;\n", i, ambientStr, timesLightScale); diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index 63ffab8e46..f8193617e0 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -683,7 +683,7 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, WRITE(p, " if (u_matspecular.a == 0.0) {\n"); WRITE(p, " ldot = 1.0;\n"); WRITE(p, " } else {\n"); - WRITE(p, " ldot = pow(ldot, u_matspecular.a);\n"); + WRITE(p, " ldot = pow(max(ldot, 0.0), u_matspecular.a);\n"); WRITE(p, " }\n"); } @@ -715,8 +715,13 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, if (doSpecular) { WRITE(p, " if (ldot >= 0.0) {\n"); WRITE(p, " ldot = dot(normalize(toLight + vec3(0.0, 0.0, 1.0)), worldnormal);\n"); + WRITE(p, " if (u_matspecular.a == 0.0) {\n"); + WRITE(p, " ldot = 1.0;\n"); + WRITE(p, " } else {\n"); + WRITE(p, " ldot = pow(max(ldot, 0.0), u_matspecular.a);\n"); + WRITE(p, " }\n"); WRITE(p, " if (ldot > 0.0)\n"); - WRITE(p, " lightSum1 += u_lightspecular%i * %s * (pow(ldot, u_matspecular.a) %s);\n", i, specularStr, timesLightScale); + WRITE(p, " lightSum1 += u_lightspecular%i * %s * ldot %s;\n", i, specularStr, timesLightScale); WRITE(p, " }\n"); } WRITE(p, " lightSum0.rgb += (u_lightambient%i * %s.rgb + diffuse)%s;\n", i, ambientStr, timesLightScale); diff --git a/GPU/Software/Lighting.cpp b/GPU/Software/Lighting.cpp index c9f58e7f82..5246d9124d 100644 --- a/GPU/Software/Lighting.cpp +++ b/GPU/Software/Lighting.cpp @@ -125,7 +125,7 @@ void Process(VertexData& vertex, bool hasColor) { float specular_factor = Dot(H.Normalized(), vertex.worldnormal); float k = gstate.getMaterialSpecularCoef(); - specular_factor = pow(specular_factor, k); + specular_factor = pspLightPow(specular_factor, k); if (specular_factor > 0.f) { specular_color += lsc * msc * specular_factor * att * spot; diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index 891d2ea723..c6aa3644bd 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -472,7 +472,7 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { WRITE(p, " if (light.matspecular.a == 0.0) {\n"); WRITE(p, " dot%i = 1.0;\n", i); WRITE(p, " } else {\n"); - WRITE(p, " dot%i = pow(dot%i, light.matspecular.a);\n", i, i); + WRITE(p, " dot%i = pow(max(dot%i, 0.0), light.matspecular.a);\n", i, i); WRITE(p, " }\n"); } @@ -504,8 +504,13 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { if (doSpecular) { WRITE(p, " if (dot%i >= 0.0) {\n", i); WRITE(p, " dot%i = dot(normalize(toLight + vec3(0.0, 0.0, 1.0)), worldnormal);\n", i); + WRITE(p, " if (light.matspecular.a == 0.0) {\n"); + WRITE(p, " dot%i = 1.0;\n", i); + WRITE(p, " } else {\n"); + WRITE(p, " dot%i = pow(max(dot%i, 0.0), light.matspecular.a);\n", i, i); + WRITE(p, " }\n"); WRITE(p, " if (dot%i > 0.0)\n", i); - WRITE(p, " lightSum1 += light.specular[%i] * %s * (pow(dot%i, light.matspecular.a) %s);\n", i, specularStr, i, timesLightScale); + WRITE(p, " lightSum1 += light.specular[%i] * %s * dot%i %s;\n", i, specularStr, i, timesLightScale); WRITE(p, " }\n"); } WRITE(p, " lightSum0.rgb += (light.ambient[%i] * %s.rgb + diffuse)%s;\n", i, ambientStr, timesLightScale); From 87085d18f0850d8ffc2e738bcc2d5b9e6368c004 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 22 Nov 2018 09:26:12 -0800 Subject: [PATCH 147/347] GLES: Fix render-to-self detection. Was broken by the recent fb_address changes, so match Vulkan and D3D11 for consistency. --- GPU/Directx9/FramebufferDX9.cpp | 2 +- GPU/GLES/FramebufferManagerGLES.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/Directx9/FramebufferDX9.cpp b/GPU/Directx9/FramebufferDX9.cpp index 75a3beeb3a..9bcbec3427 100644 --- a/GPU/Directx9/FramebufferDX9.cpp +++ b/GPU/Directx9/FramebufferDX9.cpp @@ -454,7 +454,7 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { if (GPUStepping::IsStepping() || g_Config.bDisableSlowFramebufEffects) { skipCopy = true; } - if (!skipCopy && currentRenderVfb_ && framebuffer->fb_address == gstate.getFrameBufRawAddress()) { + if (!skipCopy && framebuffer == currentRenderVfb_) { // TODO: Maybe merge with bvfbs_? Not sure if those could be packing, and they're created at a different size. Draw::Framebuffer *renderCopy = GetTempFBO(TempFBO::COPY, framebuffer->renderWidth, framebuffer->renderHeight, (Draw::FBColorDepth)framebuffer->colorDepth); if (renderCopy) { diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 6ddf06b3bd..780735da13 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -513,7 +513,7 @@ void FramebufferManagerGLES::BindFramebufferAsColorTexture(int stage, VirtualFra if (GPUStepping::IsStepping() || g_Config.bDisableSlowFramebufEffects) { skipCopy = true; } - if (!skipCopy && currentRenderVfb_ && framebuffer->fb_address == gstate.getFrameBufRawAddress()) { + if (!skipCopy && framebuffer == currentRenderVfb_) { // TODO: Maybe merge with bvfbs_? Not sure if those could be packing, and they're created at a different size. Draw::Framebuffer *renderCopy = GetTempFBO(TempFBO::COPY, framebuffer->renderWidth, framebuffer->renderHeight, (Draw::FBColorDepth)framebuffer->colorDepth); if (renderCopy) { From 3d20ddecc55bec759287d54126d11b9fb600a53d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 22 Nov 2018 23:53:58 +0100 Subject: [PATCH 148/347] VK: Fix sometimes-missing images in GameScreen. Can't load textures from update(). (should probably make that possible though.. later). --- UI/GameInfoCache.cpp | 4 ++-- UI/GameScreen.cpp | 4 ++-- UI/GameScreen.h | 2 +- UI/TextureUtil.cpp | 3 ++- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index f727aa1363..c1f263c71f 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -742,7 +742,7 @@ void GameInfoCache::WaitUntilDone(std::shared_ptr &info) { } -// Runs on the main thread. +// Runs on the main thread. Only call from render() and similar, not update()! std::shared_ptr GameInfoCache::GetInfo(Draw::DrawContext *draw, const std::string &gamePath, int wantFlags) { std::shared_ptr info; @@ -800,7 +800,7 @@ void GameInfoCache::SetupTexture(std::shared_ptr &info, Draw::DrawCont if (tex.texture) { tex.timeLoaded = time_now_d(); } else { - ERROR_LOG(G3D, "Failed creating texture"); + ERROR_LOG(G3D, "Failed creating texture (%s)", info->GetTitle().c_str()); } } if ((info->wantFlags & GAMEINFO_WANTBGDATA) == 0) { diff --git a/UI/GameScreen.cpp b/UI/GameScreen.cpp index d10584463e..250977b329 100644 --- a/UI/GameScreen.cpp +++ b/UI/GameScreen.cpp @@ -189,8 +189,8 @@ UI::EventReturn GameScreen::OnDeleteConfig(UI::EventParams &e) return UI::EVENT_DONE; } -void GameScreen::update() { - UIScreen::update(); +void GameScreen::render() { + UIScreen::render(); I18NCategory *ga = GetI18NCategory("Game"); diff --git a/UI/GameScreen.h b/UI/GameScreen.h index 77b0c8727b..bc35ab64ea 100644 --- a/UI/GameScreen.h +++ b/UI/GameScreen.h @@ -33,7 +33,7 @@ public: GameScreen(const std::string &gamePath); ~GameScreen(); - void update() override; + void render() override; std::string tag() const override { return "game"; } diff --git a/UI/TextureUtil.cpp b/UI/TextureUtil.cpp index b2a41fba52..fed1fb1f74 100644 --- a/UI/TextureUtil.cpp +++ b/UI/TextureUtil.cpp @@ -110,6 +110,7 @@ bool ManagedTexture::LoadFromFileData(const uint8_t *data, size_t dataSize, Imag num_levels = 1; } + // Free the old texture, if any. if (texture_) { delete texture_; texture_ = nullptr; @@ -134,7 +135,7 @@ bool ManagedTexture::LoadFromFileData(const uint8_t *data, size_t dataSize, Imag if (image[i]) free(image[i]); } - return texture_ != nullptr; + return texture_; } bool ManagedTexture::LoadFromFile(const std::string &filename, ImageFileType type, bool generateMips) { From d6b8d9bfe51f6efb2b9a1252ca2d7139b57a32ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 22 Nov 2018 23:53:58 +0100 Subject: [PATCH 149/347] VK: Fix sometimes-missing images in GameScreen. Can't load textures from update(). (should probably make that possible though.. later). --- UI/GameInfoCache.cpp | 4 ++-- UI/GameScreen.cpp | 4 ++-- UI/GameScreen.h | 2 +- UI/TextureUtil.cpp | 3 ++- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index f727aa1363..c1f263c71f 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -742,7 +742,7 @@ void GameInfoCache::WaitUntilDone(std::shared_ptr &info) { } -// Runs on the main thread. +// Runs on the main thread. Only call from render() and similar, not update()! std::shared_ptr GameInfoCache::GetInfo(Draw::DrawContext *draw, const std::string &gamePath, int wantFlags) { std::shared_ptr info; @@ -800,7 +800,7 @@ void GameInfoCache::SetupTexture(std::shared_ptr &info, Draw::DrawCont if (tex.texture) { tex.timeLoaded = time_now_d(); } else { - ERROR_LOG(G3D, "Failed creating texture"); + ERROR_LOG(G3D, "Failed creating texture (%s)", info->GetTitle().c_str()); } } if ((info->wantFlags & GAMEINFO_WANTBGDATA) == 0) { diff --git a/UI/GameScreen.cpp b/UI/GameScreen.cpp index d10584463e..250977b329 100644 --- a/UI/GameScreen.cpp +++ b/UI/GameScreen.cpp @@ -189,8 +189,8 @@ UI::EventReturn GameScreen::OnDeleteConfig(UI::EventParams &e) return UI::EVENT_DONE; } -void GameScreen::update() { - UIScreen::update(); +void GameScreen::render() { + UIScreen::render(); I18NCategory *ga = GetI18NCategory("Game"); diff --git a/UI/GameScreen.h b/UI/GameScreen.h index 77b0c8727b..bc35ab64ea 100644 --- a/UI/GameScreen.h +++ b/UI/GameScreen.h @@ -33,7 +33,7 @@ public: GameScreen(const std::string &gamePath); ~GameScreen(); - void update() override; + void render() override; std::string tag() const override { return "game"; } diff --git a/UI/TextureUtil.cpp b/UI/TextureUtil.cpp index b2a41fba52..fed1fb1f74 100644 --- a/UI/TextureUtil.cpp +++ b/UI/TextureUtil.cpp @@ -110,6 +110,7 @@ bool ManagedTexture::LoadFromFileData(const uint8_t *data, size_t dataSize, Imag num_levels = 1; } + // Free the old texture, if any. if (texture_) { delete texture_; texture_ = nullptr; @@ -134,7 +135,7 @@ bool ManagedTexture::LoadFromFileData(const uint8_t *data, size_t dataSize, Imag if (image[i]) free(image[i]); } - return texture_ != nullptr; + return texture_; } bool ManagedTexture::LoadFromFile(const std::string &filename, ImageFileType type, bool generateMips) { From 11a8857a7e29d63e08bd64faba9556a75dd4369a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 22 Nov 2018 17:48:55 -0800 Subject: [PATCH 150/347] SoftGPU: Correct clipping for flat shading. It needs to use the provoking color, regardless of culling or clipping. Fixes Blade Dancer lighting (see #4140.) --- GPU/Software/Clipper.cpp | 34 +++++++++++++++++++++++----------- GPU/Software/Clipper.h | 2 +- GPU/Software/TransformUnit.cpp | 30 ++++++++++++++++-------------- 3 files changed, 40 insertions(+), 26 deletions(-) diff --git a/GPU/Software/Clipper.cpp b/GPU/Software/Clipper.cpp index 1ab91015eb..eb181ce613 100644 --- a/GPU/Software/Clipper.cpp +++ b/GPU/Software/Clipper.cpp @@ -176,10 +176,10 @@ void ProcessRect(const VertexData& v0, const VertexData& v1) } // Four triangles to do backfaces as well. Two of them will get backface culled. - ProcessTriangle(*topleft, *topright, *bottomright); - ProcessTriangle(*bottomright, *topright, *topleft); - ProcessTriangle(*bottomright, *bottomleft, *topleft); - ProcessTriangle(*topleft, *bottomleft, *bottomright); + ProcessTriangle(*topleft, *topright, *bottomright, buf[3]); + ProcessTriangle(*bottomright, *topright, *topleft, buf[3]); + ProcessTriangle(*bottomright, *bottomleft, *topleft, buf[3]); + ProcessTriangle(*topleft, *bottomleft, *bottomright, buf[3]); } else { // through mode handling VertexData buf[4]; @@ -271,10 +271,17 @@ void ProcessLine(VertexData& v0, VertexData& v1) Rasterizer::DrawLine(data[0], data[1]); } -void ProcessTriangle(VertexData& v0, VertexData& v1, VertexData& v2) -{ +void ProcessTriangle(VertexData& v0, VertexData& v1, VertexData& v2, const VertexData &provoking) { if (gstate.isModeThrough()) { - Rasterizer::DrawTriangle(v0, v1, v2); + // In case of cull reordering, make sure the right color is on the final vertex. + if (gstate.getShadeMode() == GE_SHADE_FLAT) { + VertexData corrected2 = v2; + corrected2.color0 = provoking.color0; + corrected2.color1 = provoking.color1; + Rasterizer::DrawTriangle(v0, v1, corrected2); + } else { + Rasterizer::DrawTriangle(v0, v1, v2); + } return; } @@ -339,14 +346,19 @@ void ProcessTriangle(VertexData& v0, VertexData& v1, VertexData& v2) return; } - for (int i = 0; i+3 <= numIndices; i+=3) - { - if(indices[i] != SKIP_FLAG) - { + for (int i = 0; i + 3 <= numIndices; i += 3) { + if (indices[i] != SKIP_FLAG) { VertexData data[3] = { *Vertices[indices[i]], *Vertices[indices[i+1]], *Vertices[indices[i+2]] }; data[0].screenpos = TransformUnit::ClipToScreen(data[0].clippos); data[1].screenpos = TransformUnit::ClipToScreen(data[1].clippos); data[2].screenpos = TransformUnit::ClipToScreen(data[2].clippos); + + if (gstate.getShadeMode() == GE_SHADE_FLAT) { + // So that the order of clipping doesn't matter... + data[2].color0 = provoking.color0; + data[2].color1 = provoking.color1; + } + Rasterizer::DrawTriangle(data[0], data[1], data[2]); } } diff --git a/GPU/Software/Clipper.h b/GPU/Software/Clipper.h index e0926e6248..d00262001a 100644 --- a/GPU/Software/Clipper.h +++ b/GPU/Software/Clipper.h @@ -23,7 +23,7 @@ namespace Clipper { void ProcessPoint(VertexData& v0); void ProcessLine(VertexData& v0, VertexData& v1); -void ProcessTriangle(VertexData& v0, VertexData& v1, VertexData& v2); +void ProcessTriangle(VertexData& v0, VertexData& v1, VertexData& v2, const VertexData &provoking); void ProcessRect(const VertexData& v0, const VertexData& v1); } diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index e72e9a85cb..f8081ec8d7 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -342,12 +342,12 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy case GE_PRIM_TRIANGLES: { if (!gstate.isCullEnabled() || gstate.isModeClear()) { - Clipper::ProcessTriangle(data[0], data[1], data[2]); - Clipper::ProcessTriangle(data[2], data[1], data[0]); + Clipper::ProcessTriangle(data[0], data[1], data[2], data[2]); + Clipper::ProcessTriangle(data[2], data[1], data[0], data[2]); } else if (!gstate.getCullMode()) { - Clipper::ProcessTriangle(data[2], data[1], data[0]); + Clipper::ProcessTriangle(data[2], data[1], data[0], data[2]); } else { - Clipper::ProcessTriangle(data[0], data[1], data[2]); + Clipper::ProcessTriangle(data[0], data[1], data[2], data[2]); } break; } @@ -413,7 +413,8 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy vreader.Goto(vtx); } - data[(data_index++) % 3] = ReadVertex(vreader); + int provoking_index = (data_index++) % 3; + data[provoking_index] = ReadVertex(vreader); if (outside_range_flag) { // Drop all primitives containing the current vertex skip_count = 2; @@ -427,14 +428,14 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy } if (!gstate.isCullEnabled() || gstate.isModeClear()) { - Clipper::ProcessTriangle(data[0], data[1], data[2]); - Clipper::ProcessTriangle(data[2], data[1], data[0]); + Clipper::ProcessTriangle(data[0], data[1], data[2], data[provoking_index]); + Clipper::ProcessTriangle(data[2], data[1], data[0], data[provoking_index]); } else if ((!gstate.getCullMode()) ^ ((data_index - 1) % 2)) { // We need to reverse the vertex order for each second primitive, // but we additionally need to do that for every primitive if CCW cullmode is used. - Clipper::ProcessTriangle(data[2], data[1], data[0]); + Clipper::ProcessTriangle(data[2], data[1], data[0], data[provoking_index]); } else { - Clipper::ProcessTriangle(data[0], data[1], data[2]); + Clipper::ProcessTriangle(data[0], data[1], data[2], data[provoking_index]); } } break; @@ -466,7 +467,8 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy vreader.Goto(vtx); } - data[2 - ((data_index++) % 2)] = ReadVertex(vreader); + int provoking_index = 2 - ((data_index++) % 2); + data[provoking_index] = ReadVertex(vreader); if (outside_range_flag) { // Drop all primitives containing the current vertex skip_count = 2; @@ -480,14 +482,14 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy } if (!gstate.isCullEnabled() || gstate.isModeClear()) { - Clipper::ProcessTriangle(data[0], data[1], data[2]); - Clipper::ProcessTriangle(data[2], data[1], data[0]); + Clipper::ProcessTriangle(data[0], data[1], data[2], data[provoking_index]); + Clipper::ProcessTriangle(data[2], data[1], data[0], data[provoking_index]); } else if ((!gstate.getCullMode()) ^ ((data_index - 1) % 2)) { // We need to reverse the vertex order for each second primitive, // but we additionally need to do that for every primitive if CCW cullmode is used. - Clipper::ProcessTriangle(data[2], data[1], data[0]); + Clipper::ProcessTriangle(data[2], data[1], data[0], data[provoking_index]); } else { - Clipper::ProcessTriangle(data[0], data[1], data[2]); + Clipper::ProcessTriangle(data[0], data[1], data[2], data[provoking_index]); } } break; From cd6783fa0dddb9de857cf09284816e39aa772895 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 22 Nov 2018 17:52:14 -0800 Subject: [PATCH 151/347] GPU: Use provoking normal for lighting with flat. This might interact strangely with skinning of texture matrix mapping, but they're not likely to be used together. --- GPU/Common/SoftwareTransformCommon.cpp | 49 +++++++++++++------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index d38784d2f5..66909cb2d0 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -191,9 +191,9 @@ void SoftwareTransform( fog_slope = std::signbit(fog_slope) ? -65535.0f : 65535.0f; } - int colorIndOffset = 0; + int provokeIndOffset = 0; if (params->provokeFlatFirst) { - colorIndOffset = ColorIndexOffset(prim, gstate.getShadeMode(), gstate.isModeClear()); + provokeIndOffset = ColorIndexOffset(prim, gstate.getShadeMode(), gstate.isModeClear()); } VertexReader reader(decoded, decVtxFormat, vertType); @@ -206,8 +206,8 @@ void SoftwareTransform( reader.ReadPos(vert.pos); if (reader.hasColor0()) { - if (colorIndOffset != 0 && index + colorIndOffset < maxIndex) { - reader.Goto(index + colorIndOffset); + if (provokeIndOffset != 0 && index + provokeIndOffset < maxIndex) { + reader.Goto(index + provokeIndOffset); reader.ReadColor0_8888(vert.color0); reader.Goto(index); } else { @@ -247,10 +247,24 @@ void SoftwareTransform( Vec3f worldnormal(0, 0, 1); reader.ReadPos(pos); + float ruv[2] = { 0.0f, 0.0f }; + if (reader.hasUV()) + reader.ReadUV(ruv); + + // Read all the provoking vertex values here. + Vec4f unlitColor; + if (provokeIndOffset != 0 && index + provokeIndOffset < maxIndex) + reader.Goto(index + provokeIndOffset); + if (reader.hasColor0()) + reader.ReadColor0(unlitColor.AsArray()); + else + unlitColor = Vec4f::FromRGBA(gstate.getMaterialAmbientRGBA()); + if (reader.hasNormal()) + reader.ReadNrm(normal.AsArray()); + if (!skinningEnabled) { Vec3ByMatrix43(out, pos, gstate.worldMatrix); if (reader.hasNormal()) { - reader.ReadNrm(normal.AsArray()); if (gstate.areNormalsReversed()) { normal = -normal; } @@ -259,9 +273,9 @@ void SoftwareTransform( } } else { float weights[8]; + // TODO: For flat, are weights from the provoking used for color/normal? + reader.Goto(index); reader.ReadWeights(weights); - if (reader.hasNormal()) - reader.ReadNrm(normal.AsArray()); // Skinning Vec3f psum(0, 0, 0); @@ -291,20 +305,7 @@ void SoftwareTransform( } } - // Perform lighting here if enabled. don't need to check through, it's checked above. - Vec4f unlitColor = Vec4f(1, 1, 1, 1); - if (reader.hasColor0()) { - if (colorIndOffset != 0 && index + colorIndOffset < maxIndex) { - reader.Goto(index + colorIndOffset); - reader.ReadColor0(&unlitColor.x); - reader.Goto(index); - } else { - reader.ReadColor0(&unlitColor.x); - } - } else { - unlitColor = Vec4f::FromRGBA(gstate.getMaterialAmbientRGBA()); - } - + // Perform lighting here if enabled. if (gstate.isLightingEnabled()) { float litColor0[4]; float litColor1[4]; @@ -338,10 +339,6 @@ void SoftwareTransform( } } - float ruv[2] = {0.0f, 0.0f}; - if (reader.hasUV()) - reader.ReadUV(ruv); - // Perform texture coordinate generation after the transform and lighting - one style of UV depends on lights. switch (gstate.getUVGenMode()) { case GE_TEXMAP_TEXTURE_COORDS: // UV mapping @@ -354,6 +351,8 @@ void SoftwareTransform( case GE_TEXMAP_TEXTURE_MATRIX: { + // TODO: What's the correct behavior with flat shading? Provoked normal or real normal? + // Projection mapping Vec3f source; switch (gstate.getUVProjMode()) { From 529efded1c4049afc3a9e08891699127d796cb96 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 22 Nov 2018 17:53:36 -0800 Subject: [PATCH 152/347] GE Debugger: Fix display of raw normals. --- GPU/Software/TransformUnit.cpp | 2 +- Windows/GEDebugger/TabVertices.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index f8081ec8d7..4d51a9f3d1 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -510,7 +510,7 @@ bool TransformUnit::GetCurrentSimpleVertices(int count, std::vector 0 && (gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { const u8 *inds = Memory::GetPointer(gstate_c.indexAddr); const u16 *inds16 = (const u16 *)inds; const u32 *inds32 = (const u32 *)inds; diff --git a/Windows/GEDebugger/TabVertices.cpp b/Windows/GEDebugger/TabVertices.cpp index f1f7e2f164..bd65e87999 100644 --- a/Windows/GEDebugger/TabVertices.cpp +++ b/Windows/GEDebugger/TabVertices.cpp @@ -187,6 +187,7 @@ void CtrlVertexList::FormatVertColRaw(wchar_t *dest, int row, int col) { const u8 *pos = vert + decoder->posoff; const u8 *tc = vert + decoder->tcoff; const u8 *color = vert + decoder->coloff; + const u8 *norm = vert + decoder->nrmoff; switch (col) { case VERTEXLIST_COL_X: @@ -208,6 +209,10 @@ void CtrlVertexList::FormatVertColRaw(wchar_t *dest, int row, int col) { FormatVertColRawColor(dest, color, decoder->col); break; + case VERTEXLIST_COL_NX: FormatVertColRawType(dest, norm, decoder->nrm, 0); break; + case VERTEXLIST_COL_NY: FormatVertColRawType(dest, norm, decoder->nrm, 1); break; + case VERTEXLIST_COL_NZ: FormatVertColRawType(dest, norm, decoder->nrm, 2); break; + default: wcscpy(dest, L"Invalid"); break; From fedc72eff582af4d31984df010bab1e954075c87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 23 Nov 2018 09:51:16 +0100 Subject: [PATCH 153/347] Revert "Android: Fix Vulkan immersive startup." This reverts commit 5a5483ca9360fdc773da67413b19f9129394b5a8. --- UI/NativeApp.cpp | 5 +---- android/src/org/ppsspp/ppsspp/NativeActivity.java | 5 ----- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index c31745337b..2dd8ca97f5 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -133,7 +133,6 @@ static UI::Theme ui_theme; ScreenManager *screenManager; std::string config_filename; -bool g_graphicsIniting; bool g_graphicsInited; // Really need to clean this mess of globals up... but instead I add more :P @@ -754,7 +753,6 @@ static void UIThemeInit() { void RenderOverlays(UIContext *dc, void *userdata); bool NativeInitGraphics(GraphicsContext *graphicsContext) { - g_graphicsIniting = true; ILOG("NativeInitGraphics"); _assert_msg_(G3D, graphicsContext, "No graphics context!"); @@ -831,7 +829,6 @@ bool NativeInitGraphics(GraphicsContext *graphicsContext) { gpu->DeviceRestore(); g_graphicsInited = true; - g_graphicsIniting = false; ILOG("NativeInitGraphics completed"); return true; } @@ -1253,7 +1250,7 @@ void NativeMessageReceived(const char *message, const char *value) { void NativeResized() { // NativeResized can come from any thread so we just set a flag, then process it later. - if (g_graphicsInited || g_graphicsIniting) { + if (g_graphicsInited) { resized = true; } else { ILOG("NativeResized ignored, not initialized"); diff --git a/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java index 319147e01d..da7278c71d 100644 --- a/android/src/org/ppsspp/ppsspp/NativeActivity.java +++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java @@ -569,11 +569,6 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C // Note that desiredSize might be 0,0 here - but that's fine when calling setFixedSize! It means auto. Log.d(TAG, "Setting fixed size " + desiredSize.x + " x " + desiredSize.y); holder.setFixedSize(desiredSize.x, desiredSize.y); - - // This may change it - but, since we're visible now, we can actually set this. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - updateSystemUiVisibility(); - } } @Override From 2a65f224e643915236bd3ca4139037a2c84711b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 23 Nov 2018 13:29:42 +0100 Subject: [PATCH 154/347] 1.7.3 --- android/AndroidManifest.xml | 4 ++-- assets/lang | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 18e454d348..9eae7a2977 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -2,8 +2,8 @@ + android:versionCode="17030000" + android:versionName="1.7.3.0"> diff --git a/assets/lang b/assets/lang index f60be494a4..a6c1c24e8d 160000 --- a/assets/lang +++ b/assets/lang @@ -1 +1 @@ -Subproject commit f60be494a43a49fd7ff61603e132c1e24c160d88 +Subproject commit a6c1c24e8dfe35afb56210fc46110dbf6fb6f593 From a59019a43a2bc876fd0faa591dd3f14d67baa6da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 23 Nov 2018 16:05:31 +0100 Subject: [PATCH 155/347] Update readme for 1.7.3 --- README.md | 11 +++++++++++ android/AndroidManifest.xml | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7905cdbf52..0bdbdd95e9 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,17 @@ For build instructions and other development tutorials, see [the wiki](https://g For game compatibility, see [community compatibility feedback](https://report.ppsspp.org/games). + +What's new in 1.7.3 +------------------- +* Attempted fixes for a couple of common crashes +* Reverted immersive mode change temporarily to see if it helps misaligned buttons +* Change default adhoc server address + +What's new in 1.7.2 +------------------- +* Update text of "Buy PPSSPP Gold" button + What's new in 1.7.1 ------------------- * Minor crashfixes, lang updates diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 9eae7a2977..a1c5bf225b 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -2,8 +2,8 @@ + android:versionCode="17030001" + android:versionName="1.7.3.1"> From 04b4dedfcacca4edef2d71d53eb2eb94568382e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 23 Nov 2018 16:16:58 +0100 Subject: [PATCH 156/347] Have to increment the build number due to a mistake, so make it 1.7.4 --- README.md | 2 +- android/AndroidManifest.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0bdbdd95e9..e67efd66a2 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ For build instructions and other development tutorials, see [the wiki](https://g For game compatibility, see [community compatibility feedback](https://report.ppsspp.org/games). -What's new in 1.7.3 +What's new in 1.7.3/1.7.4 ------------------- * Attempted fixes for a couple of common crashes * Reverted immersive mode change temporarily to see if it helps misaligned buttons diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index a1c5bf225b..e118cf6ebc 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -2,8 +2,8 @@ + android:versionCode="17040000" + android:versionName="1.7.4.0"> From e664e1c1dd0270f4b401262cdb00f8cc3d86ae75 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 23 Nov 2018 06:10:14 -0800 Subject: [PATCH 157/347] SoftGPU: Oops, properly apply pixel mask in 16-bit. --- GPU/Software/Rasterizer.cpp | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index b856ba7b8e..051bef282b 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -1512,39 +1512,35 @@ void ClearRectangle(const VertexData &v0, const VertexData &v1) } } - const u32 new_color = v1.color0.ToRGBA(); - u16 new_color16; - // Note: this stays 0xFFFFFFFF if keeping color and alpha, even for 16-bit. u32 keepOldMask = 0xFFFFFFFF; + if (gstate.isClearModeColorMask()) + keepOldMask &= 0xFF000000; + if (gstate.isClearModeAlphaMask()) + keepOldMask &= 0x00FFFFFF; + + // The pixel write masks are respected in clear mode. + keepOldMask |= gstate.getColorMask(); + + const u32 new_color = v1.color0.ToRGBA(); + u16 new_color16; switch (gstate.FrameBufFormat()) { case GE_FORMAT_565: new_color16 = RGBA8888ToRGB565(new_color); - if (gstate.isClearModeColorMask()) - keepOldMask = 0; + keepOldMask = keepOldMask == 0 ? 0 : (0xFFFF0000 | RGBA8888ToRGB565(keepOldMask)); break; case GE_FORMAT_5551: new_color16 = RGBA8888ToRGBA5551(new_color); - if (gstate.isClearModeColorMask()) - keepOldMask &= 0x00008000; - if (gstate.isClearModeAlphaMask()) - keepOldMask &= 0x00007FFF; + keepOldMask = keepOldMask == 0 ? 0 : (0xFFFF0000 | RGBA8888ToRGBA5551(keepOldMask)); break; case GE_FORMAT_4444: new_color16 = RGBA8888ToRGBA4444(new_color); - if (gstate.isClearModeColorMask()) - keepOldMask &= 0x0000F000; - if (gstate.isClearModeAlphaMask()) - keepOldMask &= 0x00000FFF; + keepOldMask = keepOldMask == 0 ? 0 : (0xFFFF0000 | RGBA8888ToRGBA4444(keepOldMask)); break; case GE_FORMAT_8888: - if (gstate.isClearModeColorMask()) - keepOldMask &= 0xFF000000; - if (gstate.isClearModeAlphaMask()) - keepOldMask &= 0x00FFFFFF; break; case GE_FORMAT_INVALID: @@ -1552,9 +1548,6 @@ void ClearRectangle(const VertexData &v0, const VertexData &v1) break; } - // The pixel write masks are respected in clear mode. - keepOldMask |= gstate.getColorMask(); - if (keepOldMask == 0) { ScreenCoords pprime(minX, minY, 0); const int stride = gstate.FrameBufStride(); From 88f9eda4befab8c84143302f96afc287d8b1ae9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 24 Nov 2018 17:14:15 +0100 Subject: [PATCH 158/347] GL: Realized we need another sanity check in the readback code Added similar checks to Vulkan, just because. --- ext/native/thin3d/GLQueueRunner.cpp | 4 ++++ ext/native/thin3d/VulkanQueueRunner.cpp | 17 +++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/ext/native/thin3d/GLQueueRunner.cpp b/ext/native/thin3d/GLQueueRunner.cpp index 31a1cca8ae..480e77ec31 100644 --- a/ext/native/thin3d/GLQueueRunner.cpp +++ b/ext/native/thin3d/GLQueueRunner.cpp @@ -1262,6 +1262,10 @@ void GLQueueRunner::CopyReadbackBuffer(int width, int height, Draw::DataFormat s // don't usually provide very optimized conversion implementations, though some do. // Just need to be careful about dithering, which may break Danganronpa. int bpp = (int)Draw::DataFormatSizeInBytes(destFormat); + if (!readbackBuffer_ || bpp <= 0 || !pixels) { + // Something went wrong during the read and no readback buffer was allocated, probably. + return; + } for (int y = 0; y < height; y++) { memcpy(pixels + y * pixelStride * bpp, readbackBuffer_ + y * width * bpp, width * bpp); } diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp index 2e122de544..7d5d409bc4 100644 --- a/ext/native/thin3d/VulkanQueueRunner.cpp +++ b/ext/native/thin3d/VulkanQueueRunner.cpp @@ -50,14 +50,20 @@ void VulkanQueueRunner::ResizeReadbackBuffer(VkDeviceSize requiredSize) { VkMemoryRequirements reqs{}; vkGetBufferMemoryRequirements(device, readbackBuffer_, &reqs); - VkMemoryAllocateInfo alloc{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; - alloc.allocationSize = reqs.size; + VkMemoryAllocateInfo allocInfo{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + allocInfo.allocationSize = reqs.size; VkFlags typeReqs = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - bool success = vulkan_->MemoryTypeFromProperties(reqs.memoryTypeBits, typeReqs, &alloc.memoryTypeIndex); + bool success = vulkan_->MemoryTypeFromProperties(reqs.memoryTypeBits, typeReqs, &allocInfo.memoryTypeIndex); _assert_(success); - vkAllocateMemory(device, &alloc, nullptr, &readbackMemory_); + VkResult res = vkAllocateMemory(device, &allocInfo, nullptr, &readbackMemory_); + if (res != VK_SUCCESS) { + readbackMemory_ = VK_NULL_HANDLE; + vkDestroyBuffer(device, readbackBuffer_, nullptr); + readbackBuffer_ = VK_NULL_HANDLE; + return; + } uint32_t offset = 0; vkBindBufferMemory(device, readbackBuffer_, readbackMemory_, offset); } @@ -1278,6 +1284,9 @@ void VulkanQueueRunner::PerformReadbackImage(const VKRStep &step, VkCommandBuffe } void VulkanQueueRunner::CopyReadbackBuffer(int width, int height, Draw::DataFormat srcFormat, Draw::DataFormat destFormat, int pixelStride, uint8_t *pixels) { + if (!readbackMemory_) + return; // Something has gone really wrong. + // Read back to the requested address in ram from buffer. void *mappedData; const size_t srcPixelSize = DataFormatSizeInBytes(srcFormat); From d1910de166cf27cbeb2f2aaa82fe043582a4c7a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 24 Nov 2018 17:14:15 +0100 Subject: [PATCH 159/347] GL: Realized we need another sanity check in the readback code Added similar checks to Vulkan, just because. --- ext/native/thin3d/GLQueueRunner.cpp | 4 ++++ ext/native/thin3d/VulkanQueueRunner.cpp | 17 +++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/ext/native/thin3d/GLQueueRunner.cpp b/ext/native/thin3d/GLQueueRunner.cpp index 8a73a42139..02bfc979b1 100644 --- a/ext/native/thin3d/GLQueueRunner.cpp +++ b/ext/native/thin3d/GLQueueRunner.cpp @@ -1306,6 +1306,10 @@ void GLQueueRunner::CopyReadbackBuffer(int width, int height, Draw::DataFormat s // don't usually provide very optimized conversion implementations, though some do. // Just need to be careful about dithering, which may break Danganronpa. int bpp = (int)Draw::DataFormatSizeInBytes(destFormat); + if (!readbackBuffer_ || bpp <= 0 || !pixels) { + // Something went wrong during the read and no readback buffer was allocated, probably. + return; + } for (int y = 0; y < height; y++) { memcpy(pixels + y * pixelStride * bpp, readbackBuffer_ + y * width * bpp, width * bpp); } diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp index 07cb01dca1..631d088d26 100644 --- a/ext/native/thin3d/VulkanQueueRunner.cpp +++ b/ext/native/thin3d/VulkanQueueRunner.cpp @@ -50,14 +50,20 @@ void VulkanQueueRunner::ResizeReadbackBuffer(VkDeviceSize requiredSize) { VkMemoryRequirements reqs{}; vkGetBufferMemoryRequirements(device, readbackBuffer_, &reqs); - VkMemoryAllocateInfo alloc{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; - alloc.allocationSize = reqs.size; + VkMemoryAllocateInfo allocInfo{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + allocInfo.allocationSize = reqs.size; VkFlags typeReqs = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - bool success = vulkan_->MemoryTypeFromProperties(reqs.memoryTypeBits, typeReqs, &alloc.memoryTypeIndex); + bool success = vulkan_->MemoryTypeFromProperties(reqs.memoryTypeBits, typeReqs, &allocInfo.memoryTypeIndex); _assert_(success); - vkAllocateMemory(device, &alloc, nullptr, &readbackMemory_); + VkResult res = vkAllocateMemory(device, &allocInfo, nullptr, &readbackMemory_); + if (res != VK_SUCCESS) { + readbackMemory_ = VK_NULL_HANDLE; + vkDestroyBuffer(device, readbackBuffer_, nullptr); + readbackBuffer_ = VK_NULL_HANDLE; + return; + } uint32_t offset = 0; vkBindBufferMemory(device, readbackBuffer_, readbackMemory_, offset); } @@ -1279,6 +1285,9 @@ void VulkanQueueRunner::PerformReadbackImage(const VKRStep &step, VkCommandBuffe } void VulkanQueueRunner::CopyReadbackBuffer(int width, int height, Draw::DataFormat srcFormat, Draw::DataFormat destFormat, int pixelStride, uint8_t *pixels) { + if (!readbackMemory_) + return; // Something has gone really wrong. + // Read back to the requested address in ram from buffer. void *mappedData; const size_t srcPixelSize = DataFormatSizeInBytes(srcFormat); From d9510f88246522696122e2b4cd500dc070e958b1 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 24 Nov 2018 10:19:10 -0800 Subject: [PATCH 160/347] D3D11: Allow shader blend to self. It was forcing from black before. See #9616. --- GPU/Common/FramebufferCommon.h | 2 ++ GPU/D3D11/FramebufferManagerD3D11.cpp | 2 +- GPU/D3D11/TextureCacheD3D11.cpp | 4 ++-- GPU/Directx9/TextureCacheDX9.cpp | 2 +- GPU/GLES/TextureCacheGLES.cpp | 2 +- GPU/Vulkan/FramebufferVulkan.cpp | 2 +- 6 files changed, 8 insertions(+), 6 deletions(-) diff --git a/GPU/Common/FramebufferCommon.h b/GPU/Common/FramebufferCommon.h index e2ee170f0e..235d319924 100644 --- a/GPU/Common/FramebufferCommon.h +++ b/GPU/Common/FramebufferCommon.h @@ -146,6 +146,8 @@ enum BindFramebufferColorFlags { BINDFBCOLOR_MAY_COPY = 1, BINDFBCOLOR_MAY_COPY_WITH_UV = 3, BINDFBCOLOR_APPLY_TEX_OFFSET = 4, + // Used when rendering to a temporary surface (e.g. not the current render target.) + BINDFBCOLOR_FORCE_SELF = 8, }; enum DrawTextureFlags { diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index 01bfd06fb6..69b07bb36e 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -553,7 +553,7 @@ void FramebufferManagerD3D11::BindFramebufferAsColorTexture(int stage, VirtualFr } else { draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0); } - } else if (framebuffer != currentRenderVfb_) { + } else if (framebuffer != currentRenderVfb_ || (flags & BINDFBCOLOR_FORCE_SELF) != 0) { draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0); } else { ERROR_LOG_REPORT_ONCE(d3d11SelfTexture, G3D, "Attempting to texture from target (src=%08x / target=%08x / flags=%d)", framebuffer->fb_address, currentRenderVfb_->fb_address, flags); diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index a85e5750f0..56143782e2 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -398,11 +398,11 @@ void TextureCacheD3D11::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFra shaderApply.ApplyBounds(gstate_c.vertBounds, gstate_c.curTextureXOffset, gstate_c.curTextureYOffset, xoff, yoff); shaderApply.Use(depalShaderCache_->GetDepalettizeVertexShader(), depalShaderCache_->GetInputLayout()); + draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }); context_->PSSetShaderResources(3, 1, &clutTexture); context_->PSSetSamplers(3, 1, &stockD3D11.samplerPoint2DWrap); - framebufferManagerD3D11_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_SKIP_COPY); + framebufferManagerD3D11_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_SKIP_COPY | BINDFBCOLOR_FORCE_SELF); context_->PSSetSamplers(0, 1, &stockD3D11.samplerPoint2DWrap); - draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }); shaderApply.Shade(); framebufferManagerD3D11_->RebindFramebuffer(); diff --git a/GPU/Directx9/TextureCacheDX9.cpp b/GPU/Directx9/TextureCacheDX9.cpp index 6d4338117e..7e1660e892 100644 --- a/GPU/Directx9/TextureCacheDX9.cpp +++ b/GPU/Directx9/TextureCacheDX9.cpp @@ -442,7 +442,7 @@ void TextureCacheDX9::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFrame device_->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_POINT); device_->SetSamplerState(1, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - framebufferManagerDX9_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_SKIP_COPY); + framebufferManagerDX9_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_SKIP_COPY | BINDFBCOLOR_FORCE_SELF); device_->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); device_->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); device_->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); diff --git a/GPU/GLES/TextureCacheGLES.cpp b/GPU/GLES/TextureCacheGLES.cpp index 6536e8d916..395651f24b 100644 --- a/GPU/GLES/TextureCacheGLES.cpp +++ b/GPU/GLES/TextureCacheGLES.cpp @@ -484,7 +484,7 @@ void TextureCacheGLES::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFram shaderApply.ApplyBounds(gstate_c.vertBounds, gstate_c.curTextureXOffset, gstate_c.curTextureYOffset); shaderApply.Use(render_, drawEngine_, shadeInputLayout_); - framebufferManagerGL_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_SKIP_COPY); + framebufferManagerGL_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_SKIP_COPY | BINDFBCOLOR_FORCE_SELF); render_->BindTexture(TEX_SLOT_CLUT, clutTexture); render_->SetTextureSampler(TEX_SLOT_CLUT, GL_REPEAT, GL_CLAMP_TO_EDGE, GL_NEAREST, GL_NEAREST, 0.0f); diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp index 91dd924a15..4ec89a66e1 100644 --- a/GPU/Vulkan/FramebufferVulkan.cpp +++ b/GPU/Vulkan/FramebufferVulkan.cpp @@ -425,7 +425,7 @@ VkImageView FramebufferManagerVulkan::BindFramebufferAsColorTexture(int stage, V draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0); } return (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW); - } else if (framebuffer != currentRenderVfb_) { + } else if (framebuffer != currentRenderVfb_ || (flags & BINDFBCOLOR_FORCE_SELF) != 0) { draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0); return (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW); } else { From fd97d82c71a8fa06f2596122d529879a45e800a8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 24 Nov 2018 10:47:49 -0800 Subject: [PATCH 161/347] D3D9: Correct shader bounds apply. Also, use triangle strip like D3D11. --- GPU/Directx9/TextureCacheDX9.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/GPU/Directx9/TextureCacheDX9.cpp b/GPU/Directx9/TextureCacheDX9.cpp index 7e1660e892..321b980f44 100644 --- a/GPU/Directx9/TextureCacheDX9.cpp +++ b/GPU/Directx9/TextureCacheDX9.cpp @@ -320,14 +320,14 @@ public: static const Pos pos[4] = { {-1, 1, 0}, { 1, 1, 0}, - { 1, -1, 0}, {-1, -1, 0}, + { 1, -1, 0}, }; static const UV uv[4] = { {0, 0}, {1, 0}, - {1, 1}, {0, 1}, + {1, 1}, }; for (int i = 0; i < 4; ++i) { @@ -354,25 +354,25 @@ public: const float left = u1 * invHalfWidth - 1.0f + xoff; const float right = u2 * invHalfWidth - 1.0f + xoff; - const float top = v1 * invHalfHeight - 1.0f + yoff; - const float bottom = v2 * invHalfHeight - 1.0f + yoff; + const float top = (bufferH_ - v1) * invHalfHeight - 1.0f + yoff; + const float bottom = (bufferH_ - v2) * invHalfHeight - 1.0f + yoff; float z = 0.0f; - // Points are: BL, BR, TR, TL. - verts_[0].pos = Pos(left, bottom, z); - verts_[1].pos = Pos(right, bottom, z); - verts_[2].pos = Pos(right, top, z); - verts_[3].pos = Pos(left, top, z); + verts_[0].pos = Pos(left, top, z); + verts_[1].pos = Pos(right, top, z); + verts_[2].pos = Pos(left, bottom, z); + verts_[3].pos = Pos(right, bottom, z); // And also the UVs, same order. const float uvleft = u1 * invWidth; const float uvright = u2 * invWidth; const float uvtop = v1 * invHeight; const float uvbottom = v2 * invHeight; - verts_[0].uv = UV(uvleft, uvbottom); - verts_[1].uv = UV(uvright, uvbottom); - verts_[2].uv = UV(uvright, uvtop); - verts_[3].uv = UV(uvleft, uvtop); + + verts_[0].uv = UV(uvleft, uvtop); + verts_[1].uv = UV(uvright, uvtop); + verts_[2].uv = UV(uvleft, uvbottom); + verts_[3].uv = UV(uvright, uvbottom); // We need to reapply the texture next time since we cropped UV. gstate_c.Dirty(DIRTY_TEXTURE_PARAMS); @@ -396,7 +396,7 @@ public: D3DVIEWPORT9 vp{ 0, 0, (DWORD)renderW_, (DWORD)renderH_, 0.0f, 1.0f }; device_->SetViewport(&vp); - HRESULT hr = device_->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, verts_, (3 + 2) * sizeof(float)); + HRESULT hr = device_->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, verts_, (3 + 2) * sizeof(float)); if (FAILED(hr)) { ERROR_LOG_REPORT(G3D, "Depal render failed: %08x", hr); } From c2e72636015870c3836c3c95e426df61a21e6eba Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 24 Nov 2018 10:51:47 -0800 Subject: [PATCH 162/347] D3D11: Correct shader bounds apply. --- GPU/D3D11/TextureCacheD3D11.cpp | 35 +++++++++++++++++---------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index 56143782e2..d943b91d79 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -277,7 +277,7 @@ public: }; TextureShaderApplierD3D11(ID3D11DeviceContext *context, ID3D11PixelShader *pshader, ID3D11Buffer *dynamicBuffer, float bufferW, float bufferH, int renderW, int renderH, float xoff, float yoff) - : context_(context), pshader_(pshader), bufferW_(bufferW), bufferH_(bufferH), renderW_(renderW), renderH_(renderH) { + : context_(context), pshader_(pshader), vbuffer_(dynamicBuffer), bufferW_(bufferW), bufferH_(bufferH), renderW_(renderW), renderH_(renderH) { static const Pos pos[4] = { { -1, 1, 0 }, { 1, 1, 0 }, @@ -297,11 +297,6 @@ public: verts_[i].pos.y += yoff; verts_[i].uv = uv[i]; } - D3D11_MAPPED_SUBRESOURCE map; - context->Map(dynamicBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, &verts_[0], 4 * 5 * sizeof(float)); - context->Unmap(dynamicBuffer, 0); - vbuffer_ = dynamicBuffer; } void ApplyBounds(const KnownVertexBounds &bounds, u32 uoff, u32 voff, float xoff, float yoff) { @@ -320,28 +315,34 @@ public: const float left = u1 * invHalfWidth - 1.0f + xoff; const float right = u2 * invHalfWidth - 1.0f + xoff; - const float top = v1 * invHalfHeight - 1.0f + yoff; - const float bottom = v2 * invHalfHeight - 1.0f + yoff; + const float top = (bufferH_ - v1) * invHalfHeight - 1.0f + yoff; + const float bottom = (bufferH_ - v2) * invHalfHeight - 1.0f + yoff; + float z = 0.0f; - // Points are: BL, BR, TL, TR. - verts_[0].pos = Pos(left, bottom, z); - verts_[1].pos = Pos(right, bottom, z); - verts_[2].pos = Pos(left, top, z); - verts_[3].pos = Pos(right, top, z); + verts_[0].pos = Pos(left, top, z); + verts_[1].pos = Pos(right, top, z); + verts_[2].pos = Pos(left, bottom, z); + verts_[3].pos = Pos(right, bottom, z); // And also the UVs, same order. const float uvleft = u1 * invWidth; const float uvright = u2 * invWidth; const float uvtop = v1 * invHeight; const float uvbottom = v2 * invHeight; - verts_[0].uv = UV(uvleft, uvbottom); - verts_[1].uv = UV(uvright, uvbottom); - verts_[2].uv = UV(uvleft, uvtop); - verts_[3].uv = UV(uvright, uvtop); + + verts_[0].uv = UV(uvleft, uvtop); + verts_[1].uv = UV(uvright, uvtop); + verts_[2].uv = UV(uvleft, uvbottom); + verts_[3].uv = UV(uvright, uvbottom); // We need to reapply the texture next time since we cropped UV. gstate_c.Dirty(DIRTY_TEXTURE_PARAMS); } + + D3D11_MAPPED_SUBRESOURCE map; + context_->Map(vbuffer_, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, &verts_[0], 4 * 5 * sizeof(float)); + context_->Unmap(vbuffer_, 0); } void Use(ID3D11VertexShader *vshader, ID3D11InputLayout *decl) { From c5c1c46f389b5e80512dee4b3087c299539ed18a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 25 Nov 2018 11:33:02 +0100 Subject: [PATCH 163/347] Attempt to fix glsl depal error reported in #11588 (ATI/AMD) --- GPU/Common/DepalettizeShaderCommon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Common/DepalettizeShaderCommon.cpp b/GPU/Common/DepalettizeShaderCommon.cpp index e691f25459..3da0c04766 100644 --- a/GPU/Common/DepalettizeShaderCommon.cpp +++ b/GPU/Common/DepalettizeShaderCommon.cpp @@ -252,7 +252,7 @@ void GenerateDepalShaderFloat(char *buffer, GEBufferFormat pixelFormat, ShaderLa WRITE(p, "#version 100\n"); WRITE(p, "precision mediump float;\n"); } else { - WRITE(p, "#version 110\n"); + WRITE(p, "#version %d\n", gl_extensions.GLSLVersion()); } WRITE(p, "varying vec2 v_texcoord0;\n"); WRITE(p, "uniform sampler2D tex;\n"); From b8b4763ef26d341d72ae12af743b483406e95814 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 25 Nov 2018 08:20:23 -0800 Subject: [PATCH 164/347] SaveState: Retry failed state screenshots. See #10815 - happens when the device is resized before the save state. --- Core/SaveState.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index 687ab0983c..94595f432c 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -240,6 +240,7 @@ namespace SaveState static bool needsProcess = false; static std::vector pending; static std::mutex mutex; + static int screenshotFailures = 0; static bool hasLoadedState = false; static const int STALE_STATE_USES = 2; // 4 hours of total gameplay since the virtual PSP started the game. @@ -249,6 +250,7 @@ namespace SaveState // TODO: Should this be configurable? static const int REWIND_NUM_STATES = 20; + static const int SCREENSHOT_FAILURE_RETRIES = 15; static StateRingbuffer rewindStates(REWIND_NUM_STATES); // TODO: Any reason for this to be configurable? const static float rewindMaxWallFrequency = 1.0f; @@ -852,6 +854,12 @@ namespace SaveState callbackResult = tempResult ? Status::SUCCESS : Status::FAILURE; if (!tempResult) { ERROR_LOG(SAVESTATE, "Failed to take a screenshot for the savestate! %s", op.filename.c_str()); + if (screenshotFailures++ < SCREENSHOT_FAILURE_RETRIES) { + // Requeue for next frame. + SaveScreenshot(op.filename, op.callback, op.cbUserData); + } + } else { + screenshotFailures = 0; } break; } From 38461ed821c9c615bb3c058932a0fc86ceec60e6 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 25 Nov 2018 08:21:31 -0800 Subject: [PATCH 165/347] UI: Allow sorting saves by date too. --- UI/SavedataScreen.cpp | 26 ++++++++++++++++++++++++++ UI/SavedataScreen.h | 2 ++ 2 files changed, 28 insertions(+) diff --git a/UI/SavedataScreen.cpp b/UI/SavedataScreen.cpp index f8e49d8a2d..a017aa540d 100644 --- a/UI/SavedataScreen.cpp +++ b/UI/SavedataScreen.cpp @@ -323,6 +323,8 @@ void SavedataBrowser::SetSortOption(SavedataSortOption opt) { gl->SetCompare(&ByFilename, &SortDone); } else if (sortOption_ == SavedataSortOption::SIZE) { gl->SetCompare(&BySize, &SortDone); + } else if (sortOption_ == SavedataSortOption::DATE) { + gl->SetCompare(&ByDate, &SortDone); } } } @@ -345,6 +347,29 @@ bool SavedataBrowser::BySize(const UI::View *v1, const UI::View *v2) { return g1info->gameSize > g2info->gameSize; } +bool SavedataBrowser::ByDate(const UI::View *v1, const UI::View *v2) { + const SavedataButton *b1 = static_cast(v1); + const SavedataButton *b2 = static_cast(v2); + + auto getDateSeconds = [&](const SavedataButton *b) { + std::shared_ptr ginfo = g_gameInfoCache->GetInfo(nullptr, b->GamePath(), 0); + tm datetm; + bool success; + if (ginfo && ginfo->fileType == IdentifiedFileType::PSP_SAVEDATA_DIRECTORY) { + success = File::GetModifTime(b->GamePath() + "/PARAM.SFO", datetm); + } else { + success = File::GetModifTime(b->GamePath(), datetm); + } + + if (success) { + return mktime(&datetm); + } + return (time_t)0; + }; + + return getDateSeconds(b1) > getDateSeconds(b2); +} + bool SavedataBrowser::SortDone() { PrioritizedWorkQueue *wq = g_gameInfoCache->WorkQueue(); return wq->Done(); @@ -454,6 +479,7 @@ void SavedataScreen::CreateViews() { ChoiceStrip *sortStrip = new ChoiceStrip(ORIENT_HORIZONTAL, new AnchorLayoutParams(NONE, 0, 0, NONE)); sortStrip->AddChoice(sa->T("Filename")); sortStrip->AddChoice(sa->T("Size")); + sortStrip->AddChoice(sa->T("Date")); sortStrip->SetSelection((int)sortOption_); sortStrip->OnChoice.Handle(this, &SavedataScreen::OnSortClick); diff --git a/UI/SavedataScreen.h b/UI/SavedataScreen.h index 0ab3e6ed56..49da370483 100644 --- a/UI/SavedataScreen.h +++ b/UI/SavedataScreen.h @@ -29,6 +29,7 @@ enum class SavedataSortOption { FILENAME, SIZE, + DATE, }; class SavedataBrowser : public UI::LinearLayout { @@ -42,6 +43,7 @@ public: private: static bool ByFilename(const UI::View *, const UI::View *); static bool BySize(const UI::View *, const UI::View *); + static bool ByDate(const UI::View *, const UI::View *); static bool SortDone(); void Refresh(); From 1f898e3b702dfa5588ce28f5128e2b4a307cf46f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 25 Nov 2018 16:56:39 -0800 Subject: [PATCH 166/347] GPU: Correctly flush on cull mode change. Fixes #11593 and fixes #11591. --- GPU/GPUCommon.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index c6eec3c599..dc53f28cdd 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1706,9 +1706,12 @@ bail: currentList->pc += cmdCount * 4; // flush back cull mode if (cullMode != gstate.getCullMode()) { + // We rewrote everything to the old cull mode, so flush first. + drawEngineCommon_->DispatchFlush(); + + // Now update things for next time. gstate.cmdmem[GE_CMD_CULL] ^= 1; gstate_c.Dirty(DIRTY_RASTER_STATE); - drawEngineCommon_->DispatchFlush(); } } From 3c5455f85b99db4f00c0fac40b8b615a890c824e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 25 Nov 2018 19:19:11 -0800 Subject: [PATCH 167/347] SoftGPU: Calculate texcoords in transform. No need to do it in rasterization, and should be faster to do it on the verts, anyway. This fixes the software issue of #11595, presumably because of the w handling. --- GPU/Software/Rasterizer.cpp | 68 +--------------------------------- GPU/Software/TransformUnit.cpp | 34 ++++++++++++++++- 2 files changed, 35 insertions(+), 67 deletions(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 051bef282b..f210325a96 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -199,6 +199,7 @@ static inline void GetTextureCoordinates(const VertexData& v0, const VertexData& case GE_TEXMAP_TEXTURE_COORDS: case GE_TEXMAP_UNKNOWN: case GE_TEXMAP_ENVIRONMENT_MAP: + case GE_TEXMAP_TEXTURE_MATRIX: { // TODO: What happens if vertex has no texture coordinates? // Note that for environment mapping, texture coordinates have been calculated during lighting @@ -212,39 +213,6 @@ static inline void GetTextureCoordinates(const VertexData& v0, const VertexData& t = (v0.texturecoords.t() * wq0 + v1.texturecoords.t() * wq1) * q_recip; } break; - case GE_TEXMAP_TEXTURE_MATRIX: - { - // projection mapping, TODO: Move this code to TransformUnit! - Vec3 source; - switch (gstate.getUVProjMode()) { - case GE_PROJMAP_POSITION: - source = (v0.modelpos * p + v1.modelpos * (1.0f - p)); - break; - - case GE_PROJMAP_UV: - source = Vec3f((v0.texturecoords * p + v1.texturecoords * (1.0f - p)), 0.0f); - break; - - case GE_PROJMAP_NORMALIZED_NORMAL: - source = (v0.normal.Normalized() * p + v1.normal.Normalized() * (1.0f - p)); - break; - - case GE_PROJMAP_NORMAL: - source = (v0.normal * p + v1.normal * (1.0f - p)); - break; - - default: - ERROR_LOG_REPORT(G3D, "Software: Unsupported UV projection mode %x", gstate.getUVProjMode()); - break; - } - - Mat3x3 tgen(gstate.tgenMatrix); - Vec3 stq = tgen * source + Vec3(gstate.tgenMatrix[9], gstate.tgenMatrix[10], gstate.tgenMatrix[11]); - float z_recip = 1.0f / stq.z; - s = stq.x * z_recip; - t = stq.y * z_recip; - } - break; default: ERROR_LOG_REPORT(G3D, "Software: Unsupported texture mapping mode %x!", gstate.getUVGenMode()); s = 0.0f; @@ -259,6 +227,7 @@ static inline void GetTextureCoordinates(const VertexData& v0, const VertexData& case GE_TEXMAP_TEXTURE_COORDS: case GE_TEXMAP_UNKNOWN: case GE_TEXMAP_ENVIRONMENT_MAP: + case GE_TEXMAP_TEXTURE_MATRIX: { // TODO: What happens if vertex has no texture coordinates? // Note that for environment mapping, texture coordinates have been calculated during lighting @@ -274,39 +243,6 @@ static inline void GetTextureCoordinates(const VertexData& v0, const VertexData& t = Interpolate(v0.texturecoords.t(), v1.texturecoords.t(), v2.texturecoords.t(), wq0, wq1, wq2, q_recip); } break; - case GE_TEXMAP_TEXTURE_MATRIX: - for (int i = 0; i < 4; ++i) { - // projection mapping, TODO: Move this code to TransformUnit! - Vec3 source; - switch (gstate.getUVProjMode()) { - case GE_PROJMAP_POSITION: - source = (v0.modelpos * w0[i] + v1.modelpos * w1[i] + v2.modelpos * w2[i]) * wsum_recip[i]; - break; - - case GE_PROJMAP_UV: - source = Vec3f((v0.texturecoords * w0[i] + v1.texturecoords * w1[i] + v2.texturecoords * w2[i]) * wsum_recip[i], 0.0f); - break; - - case GE_PROJMAP_NORMALIZED_NORMAL: - source = (v0.normal.Normalized() * w0[i] + v1.normal.Normalized() * w1[i] + v2.normal.Normalized() * w2[i]) * wsum_recip[i]; - break; - - case GE_PROJMAP_NORMAL: - source = (v0.normal * w0[i] + v1.normal * w1[i] + v2.normal * w2[i]) * wsum_recip[i]; - break; - - default: - ERROR_LOG_REPORT(G3D, "Software: Unsupported UV projection mode %x", gstate.getUVProjMode()); - break; - } - - Mat3x3 tgen(gstate.tgenMatrix); - Vec3 stq = tgen * source + Vec3(gstate.tgenMatrix[9], gstate.tgenMatrix[10], gstate.tgenMatrix[11]); - float z_recip = 1.0f / stq.z; - s[i] = stq.x * z_recip; - t[i] = stq.y * z_recip; - } - break; default: ERROR_LOG_REPORT(G3D, "Software: Unsupported texture mapping mode %x!", gstate.getUVGenMode()); s = Vec4::AssignToAll(0.0f); diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 4d51a9f3d1..c7799eaf3e 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -234,12 +234,44 @@ VertexData TransformUnit::ReadVertex(VertexReader& vreader) if (vreader.hasNormal()) { vertex.worldnormal = TransformUnit::ModelToWorldNormal(vertex.normal); - // TODO: Isn't there a flag that controls whether to normalize the normal? vertex.worldnormal /= vertex.worldnormal.Length(); } else { vertex.worldnormal = Vec3(0.0f, 0.0f, 1.0f); } + // Time to generate some texture coords. Lighting will handle shade mapping. + if (gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX) { + Vec3f source; + switch (gstate.getUVProjMode()) { + case GE_PROJMAP_POSITION: + source = vertex.modelpos; + break; + + case GE_PROJMAP_UV: + source = Vec3f(vertex.texturecoords, 0.0f); + break; + + case GE_PROJMAP_NORMALIZED_NORMAL: + source = vertex.normal.Normalized(); + break; + + case GE_PROJMAP_NORMAL: + source = vertex.normal; + break; + + default: + source = Vec3f::AssignToAll(0.0f); + ERROR_LOG_REPORT(G3D, "Software: Unsupported UV projection mode %x", gstate.getUVProjMode()); + break; + } + + // TODO: What about uv scale and offset? + Mat3x3 tgen(gstate.tgenMatrix); + Vec3 stq = tgen * source + Vec3(gstate.tgenMatrix[9], gstate.tgenMatrix[10], gstate.tgenMatrix[11]); + float z_recip = 1.0f / stq.z; + vertex.texturecoords = Vec2f(stq.x * z_recip, stq.y * z_recip); + } + Lighting::Process(vertex, vreader.hasColor0()); } else { vertex.screenpos.x = (int)(pos[0] * 16) + gstate.getOffsetX16(); From ee34a73e80b1577891e0f90937cbe58d07608491 Mon Sep 17 00:00:00 2001 From: sum2012 Date: Mon, 26 Nov 2018 21:34:00 +0800 Subject: [PATCH 168/347] yugioh save fix tool --- Core/Config.cpp | 1 + Core/Config.h | 1 + Core/HLE/sceUtility.cpp | 11 +++++++++-- UI/GameSettingsScreen.cpp | 2 ++ 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index a62dbb21f6..197ce3ed5a 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -838,6 +838,7 @@ static ConfigSetting systemParamSettings[] = { ConfigSetting("proAdhocServer", &g_Config.proAdhocServer, "black-seraph.com", true, true), ConfigSetting("MacAddress", &g_Config.sMACAddress, "", true, true), ConfigSetting("PortOffset", &g_Config.iPortOffset, 0, true, true), + ConfigSetting("SavedataCorrectionForyugioh", &g_Config.bSavedataCorrectionForyugioh, false, true, true), ReportedConfigSetting("Language", &g_Config.iLanguage, &DefaultSystemParamLanguage, true, true), ConfigSetting("TimeFormat", &g_Config.iTimeFormat, PSP_SYSTEMPARAM_TIME_FORMAT_24HR, true, true), ConfigSetting("DateFormat", &g_Config.iDateFormat, PSP_SYSTEMPARAM_DATE_FORMAT_YYYYMMDD, true, true), diff --git a/Core/Config.h b/Core/Config.h index 311516d769..44f74a2ec2 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -90,6 +90,7 @@ public: bool bCheckForNewVersion; bool bForceLagSync; bool bFuncReplacements; + bool bSavedataCorrectionForyugioh; bool bHideSlowWarnings; bool bHideStateWarnings; bool bPreloadFunctions; diff --git a/Core/HLE/sceUtility.cpp b/Core/HLE/sceUtility.cpp index 6b5b89d75f..0519c139d2 100644 --- a/Core/HLE/sceUtility.cpp +++ b/Core/HLE/sceUtility.cpp @@ -185,8 +185,15 @@ static int sceUtilitySavedataInitStart(u32 paramAddr) { if (currentDialogActive && currentDialogType != UTILITY_DIALOG_SAVEDATA) { - WARN_LOG(SCEUTILITY, "sceUtilitySavedataInitStart(%08x): wrong dialog type", paramAddr); - return SCE_ERROR_UTILITY_WRONG_TYPE; + if (g_Config.bSavedataCorrectionForyugioh) + { + WARN_LOG(SCEUTILITY, "Savedata Correction"); + g_Config.bSavedataCorrectionForyugioh = false; + } + else { + WARN_LOG(SCEUTILITY, "sceUtilitySavedataInitStart(%08x): wrong dialog type", paramAddr); + return SCE_ERROR_UTILITY_WRONG_TYPE; + } } oldStatus = 100; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index c3b98df7a1..016bc107cd 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -671,6 +671,8 @@ void GameSettingsScreen::CreateViews() { tools->Add(new ItemHeader(ms->T("Tools"))); // These were moved here so use the wrong translation objects, to avoid having to change all inis... This isn't a sustainable situation :P tools->Add(new Choice(sa->T("Savedata Manager")))->OnClick.Handle(this, &GameSettingsScreen::OnSavedataManager); + // issue #7914 + tools->Add(new CheckBox(&g_Config.bSavedataCorrectionForyugioh, sa->T("Savedata correction for yugioh"))); tools->Add(new Choice(dev->T("System Information")))->OnClick.Handle(this, &GameSettingsScreen::OnSysInfo); tools->Add(new Choice(sy->T("Developer Tools")))->OnClick.Handle(this, &GameSettingsScreen::OnDeveloperTools); tools->Add(new Choice(ri->T("Remote disc streaming")))->OnClick.Handle(this, &GameSettingsScreen::OnRemoteISO); From 0ab6c59fbe44145e516afeac94ca40174fc16554 Mon Sep 17 00:00:00 2001 From: mrfixit2001 <38842252+mrfixit2001@users.noreply.github.com> Date: Mon, 26 Nov 2018 14:59:14 -0500 Subject: [PATCH 169/347] Avoid possible compile error: conflicting defs In some cases, depending on the build flags, these two lines can be actively compiled at the same time, resulting in a conflicting definitions error: https://github.com/hrydgard/ppsspp/blob/master/GPU/Common/DrawEngineCommon.h#L41 https://github.com/hrydgard/ppsspp/blob/master/GPU/Common/TextureDecoder.h#L88 I believe all that's necessary here is to add these "or" clauses to avoid it and safeguard against the error. --- GPU/Common/TextureDecoder.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/Common/TextureDecoder.h b/GPU/Common/TextureDecoder.h index 30054168bd..b151a40d03 100644 --- a/GPU/Common/TextureDecoder.h +++ b/GPU/Common/TextureDecoder.h @@ -49,7 +49,7 @@ void DoUnswizzleTex16Basic(const u8 *texptr, u32 *ydestp, int bxc, int byc, u32 #define DoReliableHash32 XXH32 #define DoReliableHash64 XXH64 -#ifdef _M_X64 +#ifdef _M_X64 || defined(ARM64) #define DoReliableHash XXH64 typedef u64 ReliableHashType; #else @@ -58,7 +58,7 @@ typedef u32 ReliableHashType; #endif // For ARM64, NEON is mandatory, so we also statically link. -#elif PPSSPP_ARCH(ARM64) +#elif PPSSPP_ARCH(ARM64) || defined(ARM64) #define DoQuickTexHash QuickTexHashNEON #define StableQuickTexHash QuickTexHashNEON #define DoUnswizzleTex16 DoUnswizzleTex16NEON From 53e6fbadf4f3210547aaffad1f57dc1a8bb44bcf Mon Sep 17 00:00:00 2001 From: mrfixit2001 <38842252+mrfixit2001@users.noreply.github.com> Date: Mon, 26 Nov 2018 16:02:25 -0500 Subject: [PATCH 170/347] fix ifdef vs if defined --- GPU/Common/TextureDecoder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Common/TextureDecoder.h b/GPU/Common/TextureDecoder.h index b151a40d03..35ffa8400f 100644 --- a/GPU/Common/TextureDecoder.h +++ b/GPU/Common/TextureDecoder.h @@ -49,7 +49,7 @@ void DoUnswizzleTex16Basic(const u8 *texptr, u32 *ydestp, int bxc, int byc, u32 #define DoReliableHash32 XXH32 #define DoReliableHash64 XXH64 -#ifdef _M_X64 || defined(ARM64) +#if defined(_M_X64) || defined(ARM64) #define DoReliableHash XXH64 typedef u64 ReliableHashType; #else From b82b42fab091a247d78941b36e02eed1963e08a3 Mon Sep 17 00:00:00 2001 From: sum2012 Date: Tue, 27 Nov 2018 22:45:51 +0800 Subject: [PATCH 171/347] Use compat setting instead --- Core/Compatibility.cpp | 1 + Core/Compatibility.h | 1 + Core/Config.cpp | 1 - Core/Config.h | 1 - Core/HLE/sceUtility.cpp | 6 +++--- UI/GameSettingsScreen.cpp | 2 -- assets/compat.ini | 38 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 43 insertions(+), 7 deletions(-) diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp index 692993973c..855218db6b 100644 --- a/Core/Compatibility.cpp +++ b/Core/Compatibility.cpp @@ -60,6 +60,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "MGS2AcidHack", &flags_.MGS2AcidHack); CheckSetting(iniFile, gameID, "SonicRivalsHack", &flags_.SonicRivalsHack); CheckSetting(iniFile, gameID, "BlockTransferAllowCreateFB", &flags_.BlockTransferAllowCreateFB); + CheckSetting(iniFile, gameID, "YugiohSaveFix", &flags_.YugiohSaveFix); } void Compatibility::CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag) { diff --git a/Core/Compatibility.h b/Core/Compatibility.h index 97373b9418..0d74f828f6 100644 --- a/Core/Compatibility.h +++ b/Core/Compatibility.h @@ -60,6 +60,7 @@ struct CompatFlags { bool MGS2AcidHack; bool SonicRivalsHack; bool BlockTransferAllowCreateFB; + bool YugiohSaveFix; }; class IniFile; diff --git a/Core/Config.cpp b/Core/Config.cpp index 197ce3ed5a..a62dbb21f6 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -838,7 +838,6 @@ static ConfigSetting systemParamSettings[] = { ConfigSetting("proAdhocServer", &g_Config.proAdhocServer, "black-seraph.com", true, true), ConfigSetting("MacAddress", &g_Config.sMACAddress, "", true, true), ConfigSetting("PortOffset", &g_Config.iPortOffset, 0, true, true), - ConfigSetting("SavedataCorrectionForyugioh", &g_Config.bSavedataCorrectionForyugioh, false, true, true), ReportedConfigSetting("Language", &g_Config.iLanguage, &DefaultSystemParamLanguage, true, true), ConfigSetting("TimeFormat", &g_Config.iTimeFormat, PSP_SYSTEMPARAM_TIME_FORMAT_24HR, true, true), ConfigSetting("DateFormat", &g_Config.iDateFormat, PSP_SYSTEMPARAM_DATE_FORMAT_YYYYMMDD, true, true), diff --git a/Core/Config.h b/Core/Config.h index 44f74a2ec2..311516d769 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -90,7 +90,6 @@ public: bool bCheckForNewVersion; bool bForceLagSync; bool bFuncReplacements; - bool bSavedataCorrectionForyugioh; bool bHideSlowWarnings; bool bHideStateWarnings; bool bPreloadFunctions; diff --git a/Core/HLE/sceUtility.cpp b/Core/HLE/sceUtility.cpp index 0519c139d2..1a9c994701 100644 --- a/Core/HLE/sceUtility.cpp +++ b/Core/HLE/sceUtility.cpp @@ -26,6 +26,7 @@ #include "Core/MIPS/MIPS.h" #include "Core/Reporting.h" #include "Core/Config.h" +#include "Core/System.h" #include "Core/HLE/sceKernel.h" #include "Core/HLE/sceKernelMemory.h" @@ -185,10 +186,9 @@ static int sceUtilitySavedataInitStart(u32 paramAddr) { if (currentDialogActive && currentDialogType != UTILITY_DIALOG_SAVEDATA) { - if (g_Config.bSavedataCorrectionForyugioh) + if (PSP_CoreParameter().compat.flags().YugiohSaveFix) { - WARN_LOG(SCEUTILITY, "Savedata Correction"); - g_Config.bSavedataCorrectionForyugioh = false; + WARN_LOG(SCEUTILITY, "Yugioh Savedata Correction"); } else { WARN_LOG(SCEUTILITY, "sceUtilitySavedataInitStart(%08x): wrong dialog type", paramAddr); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 016bc107cd..c3b98df7a1 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -671,8 +671,6 @@ void GameSettingsScreen::CreateViews() { tools->Add(new ItemHeader(ms->T("Tools"))); // These were moved here so use the wrong translation objects, to avoid having to change all inis... This isn't a sustainable situation :P tools->Add(new Choice(sa->T("Savedata Manager")))->OnClick.Handle(this, &GameSettingsScreen::OnSavedataManager); - // issue #7914 - tools->Add(new CheckBox(&g_Config.bSavedataCorrectionForyugioh, sa->T("Savedata correction for yugioh"))); tools->Add(new Choice(dev->T("System Information")))->OnClick.Handle(this, &GameSettingsScreen::OnSysInfo); tools->Add(new Choice(sy->T("Developer Tools")))->OnClick.Handle(this, &GameSettingsScreen::OnDeveloperTools); tools->Add(new Choice(ri->T("Remote disc streaming")))->OnClick.Handle(this, &GameSettingsScreen::OnRemoteISO); diff --git a/assets/compat.ini b/assets/compat.ini index 895db36663..d64361c8eb 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -346,3 +346,41 @@ NPJH50686 = true # Digimon Adventures (JP, and English patches...) ULJS00078 = true # MotoGP ULUS10153 = true # MotoGP UCES00373 = true # MotoGP + +[YugiohSaveFix] +# The cause of Yu-gi-oh series 's bad save (cannot save) are load "save status" and use cwcheat, +# but the real cause still unknown. #7914 + +# Yu-Gi-Oh! Duel Monsters GX: Tag Force +ULJM05151 = true +ULES00600 = true +ULUS10136 = true + +# Yu-Gi-Oh! Duel Monsters GX: Tag Force 2 +ULUS10302 = true +ULJM05260 = true +ULES00925 = true +ULES00926 = true + +# Yu-Gi-Oh! Duel Monsters GX: Tag Force 3 +ULES01183 = true +ULJM05373 = true + +# Yu-Gi-Oh! 5D's Tag Force 4 +ULUS10481 = true +ULJM05479 = true +ULES01362 = true + +# Yu-Gi-Oh! 5D's Tag Force 5 +ULUS10555 = true +ULJM05734 = true + +# Yu-Gi-Oh! 5D's Tag Force 6 +ULJM-05940 = true +NPJH-50794 = true + +# Yu-Gi-Oh! 5D's Tag Force +ULJM05940 = true + +# Yu-Gi-Oh! ARC-V Tag Force Special +NPJH00142 = true From 46063961a84903c2c4c6198329727a1a3cfe70da Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 28 Nov 2018 21:46:55 -0800 Subject: [PATCH 172/347] Windows: Translate all items by id, not position. Fixes #11571. --- Windows/MainWindowMenu.cpp | 114 +++++++++++++------------------------ Windows/ppsspp.rc | 67 +++++++++++----------- Windows/resource.h | 21 ++++++- 3 files changed, 94 insertions(+), 108 deletions(-) diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index aff87ebd21..8cad334007 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -45,7 +45,7 @@ namespace MainWindow { static W32Util::AsyncBrowseDialog *browseImageDialog; static bool browsePauseAfter; - static std::map initialMenuKeys; + static std::unordered_map initialMenuKeys; static std::vector availableShaders; static std::string menuLanguageID = ""; static bool menuShaderInfoLoaded = false; @@ -79,44 +79,23 @@ namespace MainWindow { EnableMenuItem(menu, ID_OPTIONS_LANGUAGE, state == UISTATE_INGAME ? MF_GRAYED : MF_ENABLED); } - // These are used as an offset - // to determine which menu item to change. - // Make sure to count(from 0) the separators too, when dealing with submenus!! - enum MenuItemPosition { - // Main menus - MENU_FILE = 0, - MENU_EMULATION = 1, - MENU_DEBUG = 2, - MENU_OPTIONS = 3, - MENU_HELP = 4, + static HMENU GetSubmenuById(HMENU menu, int menuID) { + MENUITEMINFO menuInfo{ sizeof(MENUITEMINFO), MIIM_SUBMENU }; + if (GetMenuItemInfo(menu, menuID, MF_BYCOMMAND, &menuInfo) != FALSE) { + return menuInfo.hSubMenu; + } + return nullptr; + } - // File submenus - SUBMENU_FILE_SAVESTATE_SLOT = 6, - SUBMENU_FILE_RECORD = 11, - - // Emulation submenus - SUBMENU_DISPLAY_ROTATION = 4, - - // Game Settings submenus - SUBMENU_DISPLAY_LAYOUT = 7, - SUBMENU_CUSTOM_SHADERS = 10, - SUBMENU_RENDERING_RESOLUTION = 11, - SUBMENU_WINDOW_SIZE = 12, - SUBMENU_RENDERING_BACKEND = 13, - SUBMENU_RENDERING_MODE = 14, - SUBMENU_FRAME_SKIPPING = 15, - SUBMENU_TEXTURE_FILTERING = 16, - SUBMENU_BUFFER_FILTER = 17, - SUBMENU_TEXTURE_SCALING = 18, - }; + static void EmptySubMenu(HMENU menu) { + int c = GetMenuItemCount(menu); + for (int i = 0; i < c; ++i) { + RemoveMenu(menu, i, MF_BYPOSITION); + } + } static std::string GetMenuItemText(HMENU menu, int menuID) { - MENUITEMINFO menuInfo; - memset(&menuInfo, 0, sizeof(menuInfo)); - menuInfo.cbSize = sizeof(MENUITEMINFO); - menuInfo.fMask = MIIM_STRING; - menuInfo.dwTypeData = 0; - + MENUITEMINFO menuInfo{ sizeof(menuInfo), MIIM_STRING }; std::string retVal; if (GetMenuItemInfo(menu, menuID, MF_BYCOMMAND, &menuInfo) != FALSE) { wchar_t *buffer = new wchar_t[++menuInfo.cch]; @@ -148,10 +127,10 @@ namespace MainWindow { const std::wstring aboutPPSSPP = ConvertUTF8ToWString(des->T("About PPSSPP...")); // Simply remove the old help menu and create a new one. - RemoveMenu(menu, MENU_HELP, MF_BYPOSITION); + RemoveMenu(menu, ID_HELP_MENU, MF_BYCOMMAND); HMENU helpMenu = CreatePopupMenu(); - InsertMenu(menu, MENU_HELP, MF_POPUP | MF_STRING | MF_BYPOSITION, (UINT_PTR)helpMenu, help.c_str()); + InsertMenu(menu, ID_HELP_MENU, MF_POPUP | MF_STRING | MF_BYCOMMAND, (UINT_PTR)helpMenu, help.c_str()); AppendMenu(helpMenu, MF_STRING | MF_BYCOMMAND, ID_HELP_OPENWEBSITE, visitMainWebsite.c_str()); AppendMenu(helpMenu, MF_STRING | MF_BYCOMMAND, ID_HELP_OPENFORUM, visitForum.c_str()); @@ -187,20 +166,12 @@ namespace MainWindow { return false; } - I18NCategory *des = GetI18NCategory("DesktopUI"); I18NCategory *ps = GetI18NCategory("PostShaders"); - const std::wstring key = ConvertUTF8ToWString(des->T("Postprocessing Shader")); - HMENU optionsMenu = GetSubMenu(menu, MENU_OPTIONS); - - HMENU shaderMenu = CreatePopupMenu(); - - RemoveMenu(optionsMenu, SUBMENU_CUSTOM_SHADERS, MF_BYPOSITION); - InsertMenu(optionsMenu, SUBMENU_CUSTOM_SHADERS, MF_POPUP | MF_STRING | MF_BYPOSITION, (UINT_PTR)shaderMenu, key.c_str()); + HMENU shaderMenu = GetSubmenuById(menu, ID_OPTIONS_SHADER_MENU); + EmptySubMenu(shaderMenu); int item = ID_SHADERS_BASE + 1; - int checkedStatus = -1; - const char *translatedShaderName = nullptr; availableShaders.clear(); @@ -209,7 +180,7 @@ namespace MainWindow { AppendMenu(shaderMenu, MF_STRING | MF_BYPOSITION | MF_GRAYED, item++, ConvertUTF8ToWString(translatedShaderName).c_str()); } else { for (auto i = info.begin(); i != info.end(); ++i) { - checkedStatus = MF_UNCHECKED; + int checkedStatus = MF_UNCHECKED; availableShaders.push_back(i->section); if (g_Config.sPostShaderName == i->section) { checkedStatus = MF_CHECKED; @@ -243,34 +214,28 @@ namespace MainWindow { _TranslateMenuItem(menu, menuID, key, true, accelerator); } - void TranslateMenu(HMENU menu, const char *key, const MenuItemPosition mainMenuPosition, const std::wstring& accelerator = L"") { - _TranslateMenuItem(menu, mainMenuPosition, key, false, accelerator); - } - - void TranslateSubMenu(HMENU menu, const char *key, const MenuItemPosition mainMenuItem, const MenuItemPosition subMenuItem, const std::wstring& accelerator = L"") { - _TranslateMenuItem(GetSubMenu(menu, mainMenuItem), subMenuItem, key, false, accelerator); + void TranslateMenu(HMENU menu, const char *key, const int itemID, const std::wstring& accelerator = L"") { + _TranslateMenuItem(menu, itemID, key, true, accelerator); } void DoTranslateMenus(HWND hWnd, HMENU menu) { - // Menu headers and submenu headers don't have resource IDs, - // So we have to hardcode strings here, unfortunately. - TranslateMenu(menu, "File", MENU_FILE); - TranslateMenu(menu, "Emulation", MENU_EMULATION); - TranslateMenu(menu, "Debugging", MENU_DEBUG); - TranslateMenu(menu, "Game Settings", MENU_OPTIONS); - TranslateMenu(menu, "Help", MENU_HELP); + TranslateMenu(menu, "File", ID_FILE_MENU); + TranslateMenu(menu, "Emulation", ID_EMULATION_MENU); + TranslateMenu(menu, "Debugging", ID_DEBUG_MENU); + TranslateMenu(menu, "Game Settings", ID_OPTIONS_MENU); + TranslateMenu(menu, "Help", ID_HELP_MENU); // File menu TranslateMenuItem(menu, ID_FILE_LOAD); TranslateMenuItem(menu, ID_FILE_LOAD_DIR); TranslateMenuItem(menu, ID_FILE_LOAD_MEMSTICK); TranslateMenuItem(menu, ID_FILE_MEMSTICK); - TranslateSubMenu(menu, "Savestate Slot", MENU_FILE, SUBMENU_FILE_SAVESTATE_SLOT, L"\tF3"); + TranslateMenuItem(menu, ID_FILE_SAVESTATE_SLOT_MENU, L"\tF3"); TranslateMenuItem(menu, ID_FILE_QUICKLOADSTATE, L"\tF4"); TranslateMenuItem(menu, ID_FILE_QUICKSAVESTATE, L"\tF2"); TranslateMenuItem(menu, ID_FILE_LOADSTATEFILE); TranslateMenuItem(menu, ID_FILE_SAVESTATEFILE); - TranslateSubMenu(menu, "Record", MENU_FILE, SUBMENU_FILE_RECORD); + TranslateMenuItem(menu, ID_FILE_RECORD_MENU); TranslateMenuItem(menu, ID_FILE_EXIT, L"\tAlt+F4"); // Emulation menu @@ -278,7 +243,7 @@ namespace MainWindow { TranslateMenuItem(menu, ID_EMULATION_STOP, L"\tCtrl+W"); TranslateMenuItem(menu, ID_EMULATION_RESET, L"\tCtrl+B"); TranslateMenuItem(menu, ID_EMULATION_SWITCH_UMD, L"\tCtrl+U", "Switch UMD"); - TranslateSubMenu(menu, "Display Rotation", MENU_EMULATION, SUBMENU_DISPLAY_ROTATION); + TranslateMenuItem(menu, ID_EMULATION_ROTATION_MENU); TranslateMenuItem(menu, ID_EMULATION_ROTATION_H); TranslateMenuItem(menu, ID_EMULATION_ROTATION_V); TranslateMenuItem(menu, ID_EMULATION_ROTATION_H_R); @@ -319,36 +284,37 @@ namespace MainWindow { // Skip display multipliers x1-x10 TranslateMenuItem(menu, ID_OPTIONS_FULLSCREEN, L"\tAlt+Return, F11"); TranslateMenuItem(menu, ID_OPTIONS_VSYNC); - TranslateSubMenu(menu, "Postprocessing Shader", MENU_OPTIONS, SUBMENU_CUSTOM_SHADERS); - TranslateSubMenu(menu, "Rendering Resolution", MENU_OPTIONS, SUBMENU_RENDERING_RESOLUTION, L"\tCtrl+1"); + TranslateMenuItem(menu, ID_OPTIONS_SHADER_MENU); + TranslateMenuItem(menu, ID_OPTIONS_SCREEN_MENU, L"\tCtrl+1"); TranslateMenuItem(menu, ID_OPTIONS_SCREENAUTO); // Skip rendering resolution 2x-5x.. - TranslateSubMenu(menu, "Window Size", MENU_OPTIONS, SUBMENU_WINDOW_SIZE); + TranslateMenuItem(menu, ID_OPTIONS_WINDOW_MENU); // Skip window size 1x-4x.. - TranslateSubMenu(menu, "Backend", MENU_OPTIONS, SUBMENU_RENDERING_BACKEND); + TranslateMenuItem(menu, ID_OPTIONS_BACKEND_MENU); TranslateMenuItem(menu, ID_OPTIONS_DIRECT3D11); TranslateMenuItem(menu, ID_OPTIONS_DIRECT3D9); TranslateMenuItem(menu, ID_OPTIONS_OPENGL); TranslateMenuItem(menu, ID_OPTIONS_VULKAN); - TranslateSubMenu(menu, "Rendering Mode", MENU_OPTIONS, SUBMENU_RENDERING_MODE); + TranslateMenuItem(menu, ID_OPTIONS_RENDERMODE_MENU); TranslateMenuItem(menu, ID_OPTIONS_NONBUFFEREDRENDERING); TranslateMenuItem(menu, ID_OPTIONS_BUFFEREDRENDERING); - TranslateSubMenu(menu, "Frame Skipping", MENU_OPTIONS, SUBMENU_FRAME_SKIPPING, L"\tF7"); + TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIP_MENU, L"\tF7"); TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIP_AUTO); TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIP_0); + TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIPTYPE_MENU); TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIPTYPE_COUNT); TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIPTYPE_PRCNT); // Skip frameskipping 1-8.. - TranslateSubMenu(menu, "Texture Filtering", MENU_OPTIONS, SUBMENU_TEXTURE_FILTERING); + TranslateMenuItem(menu, ID_OPTIONS_TEXTUREFILTERING_MENU); TranslateMenuItem(menu, ID_OPTIONS_TEXTUREFILTERING_AUTO); TranslateMenuItem(menu, ID_OPTIONS_NEARESTFILTERING); TranslateMenuItem(menu, ID_OPTIONS_LINEARFILTERING); TranslateMenuItem(menu, ID_OPTIONS_LINEARFILTERING_CG); - TranslateSubMenu(menu, "Screen Scaling Filter", MENU_OPTIONS, SUBMENU_BUFFER_FILTER); + TranslateMenuItem(menu, ID_OPTIONS_SCREENFILTER_MENU); TranslateMenuItem(menu, ID_OPTIONS_BUFLINEARFILTER); TranslateMenuItem(menu, ID_OPTIONS_BUFNEARESTFILTER); - TranslateSubMenu(menu, "Texture Scaling", MENU_OPTIONS, SUBMENU_TEXTURE_SCALING); + TranslateMenuItem(menu, ID_OPTIONS_TEXTURESCALING_MENU); TranslateMenuItem(menu, ID_TEXTURESCALING_OFF); // Skip texture scaling 2x-5x... TranslateMenuItem(menu, ID_TEXTURESCALING_XBRZ); diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index f4cc79c8f1..e554b90a06 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -448,18 +448,18 @@ IDI_STOPDISABLE ICON "stop1.ico" // Menu // -IDR_MENU1 MENU +IDR_MENU1 MENUEX BEGIN - POPUP "File" + POPUP "File", ID_FILE_MENU BEGIN MENUITEM "Load", ID_FILE_LOAD MENUITEM "Open Directory...", ID_FILE_LOAD_DIR MENUITEM "Open from MS:/PSP/GAME...", ID_FILE_LOAD_MEMSTICK - MENUITEM SEPARATOR + MENUITEM "", 0, MFT_SEPARATOR MENUITEM "Open Memory Stick", ID_FILE_MEMSTICK - MENUITEM SEPARATOR + MENUITEM "", 0, MFT_SEPARATOR - POPUP "Savestate Slot" + POPUP "Savestate Slot", ID_FILE_SAVESTATE_SLOT_MENU BEGIN MENUITEM "&1", ID_FILE_SAVESTATE_SLOT_1 MENUITEM "&2", ID_FILE_SAVESTATE_SLOT_2 @@ -472,24 +472,24 @@ BEGIN MENUITEM "Load State File...", ID_FILE_LOADSTATEFILE MENUITEM "Save State File...", ID_FILE_SAVESTATEFILE - POPUP "Record" + POPUP "Record", ID_FILE_RECORD_MENU BEGIN MENUITEM "Record Display", ID_FILE_DUMPFRAMES MENUITEM "Use Lossless Video Codec (FFV1)", ID_FILE_USEFFV1 - MENUITEM SEPARATOR + MENUITEM "", 0, MFT_SEPARATOR MENUITEM "Record Audio", ID_FILE_DUMPAUDIO END - MENUITEM SEPARATOR + MENUITEM "", 0, MFT_SEPARATOR MENUITEM "Exit", ID_FILE_EXIT END - POPUP "Emulation" + POPUP "Emulation", ID_EMULATION_MENU BEGIN MENUITEM "Pause", ID_EMULATION_PAUSE MENUITEM "Stop", ID_EMULATION_STOP MENUITEM "Reset", ID_EMULATION_RESET MENUITEM "Switch UMD", ID_EMULATION_SWITCH_UMD - POPUP "Display Rotation" + POPUP "Display Rotation", ID_EMULATION_ROTATION_MENU BEGIN MENUITEM "Landscape", ID_EMULATION_ROTATION_H MENUITEM "Portrait", ID_EMULATION_ROTATION_V @@ -498,22 +498,22 @@ BEGIN END END - POPUP "Debug" + POPUP "Debug", ID_DEBUG_MENU BEGIN MENUITEM "Run", ID_TOGGLE_BREAK MENUITEM "Break on Load", ID_DEBUG_BREAKONLOAD MENUITEM "Ignore Illegal Reads/Writes", ID_DEBUG_IGNOREILLEGALREADS - MENUITEM SEPARATOR + MENUITEM "", 0, MFT_SEPARATOR MENUITEM "Load Map File...", ID_DEBUG_LOADMAPFILE MENUITEM "Save Map File...", ID_DEBUG_SAVEMAPFILE MENUITEM "Load .sym File...", ID_DEBUG_LOADSYMFILE MENUITEM "Save .sym File...", ID_DEBUG_SAVESYMFILE MENUITEM "Reset Symbol Table", ID_DEBUG_RESETSYMBOLTABLE - MENUITEM SEPARATOR + MENUITEM "", 0, MFT_SEPARATOR MENUITEM "Take Screenshot", ID_DEBUG_TAKESCREENSHOT MENUITEM "Dump Next Frame to Log", ID_DEBUG_DUMPNEXTFRAME MENUITEM "Show Debug Statistics", ID_DEBUG_SHOWDEBUGSTATISTICS - MENUITEM SEPARATOR + MENUITEM "", 0, MFT_SEPARATOR MENUITEM "Disassembly", ID_DEBUG_DISASSEMBLY MENUITEM "GE Debugger...", ID_DEBUG_GEDEBUGGER MENUITEM "Extract File...", ID_DEBUG_EXTRACTFILE @@ -521,7 +521,7 @@ BEGIN MENUITEM "Memory View...", ID_DEBUG_MEMORYVIEW END - POPUP "Options" + POPUP "Options", ID_OPTIONS_MENU BEGIN MENUITEM "Keep PPSSPP On Top", ID_OPTIONS_TOPMOST MENUITEM "Pause When Not Focused", ID_OPTIONS_PAUSE_FOCUS @@ -530,11 +530,14 @@ BEGIN MENUITEM "Control Mapping...", ID_OPTIONS_CONTROLS MENUITEM "Display Layout Editor", ID_OPTIONS_DISPLAY_LAYOUT MENUITEM "More Settings...", ID_OPTIONS_MORE_SETTINGS - MENUITEM SEPARATOR + MENUITEM "", 0, MFT_SEPARATOR MENUITEM "Fullscreen", ID_OPTIONS_FULLSCREEN MENUITEM "VSync", ID_OPTIONS_VSYNC - MENUITEM "Postprocessing Shader", ID_OPTIONS_FXAA - POPUP "Rendering Resolution" + POPUP "Postprocessing Shader", ID_OPTIONS_SHADER_MENU + BEGIN + MENUITEM "", 0, MFT_SEPARATOR + END + POPUP "Rendering Resolution", ID_OPTIONS_SCREEN_MENU BEGIN MENUITEM "Auto", ID_OPTIONS_SCREENAUTO MENUITEM "&1x", ID_OPTIONS_SCREEN1X @@ -548,7 +551,7 @@ BEGIN MENUITEM "&9x", ID_OPTIONS_SCREEN9X MENUITEM "&10x", ID_OPTIONS_SCREEN10X END - POPUP "Window Size" + POPUP "Window Size", ID_OPTIONS_WINDOW_MENU BEGIN MENUITEM "&1x", ID_OPTIONS_WINDOW1X MENUITEM "&2x", ID_OPTIONS_WINDOW2X @@ -562,7 +565,7 @@ BEGIN MENUITEM "&10x", ID_OPTIONS_WINDOW10X END - POPUP "Backend" + POPUP "Backend", ID_OPTIONS_BACKEND_MENU BEGIN MENUITEM "Direct3D9", ID_OPTIONS_DIRECT3D9 MENUITEM "Direct3D11", ID_OPTIONS_DIRECT3D11 @@ -570,15 +573,15 @@ BEGIN MENUITEM "Vulkan", ID_OPTIONS_VULKAN END - POPUP "Rendering Mode" + POPUP "Rendering Mode", ID_OPTIONS_RENDERMODE_MENU BEGIN MENUITEM "Non-Buffered Rendering", ID_OPTIONS_NONBUFFEREDRENDERING MENUITEM "Buffered Rendering", ID_OPTIONS_BUFFEREDRENDERING END - POPUP "Frame Skipping" + POPUP "Frame Skipping", ID_OPTIONS_FRAMESKIP_MENU BEGIN MENUITEM "Auto", ID_OPTIONS_FRAMESKIP_AUTO - MENUITEM SEPARATOR + MENUITEM "", 0, MFT_SEPARATOR MENUITEM "Off", ID_OPTIONS_FRAMESKIP_0 MENUITEM "&1", ID_OPTIONS_FRAMESKIP_1 MENUITEM "&2", ID_OPTIONS_FRAMESKIP_2 @@ -589,25 +592,25 @@ BEGIN MENUITEM "&7", ID_OPTIONS_FRAMESKIP_7 MENUITEM "&8", ID_OPTIONS_FRAMESKIP_8 END - POPUP "Frame Skipping Type" + POPUP "Frame Skipping Type", ID_OPTIONS_FRAMESKIPTYPE_MENU BEGIN MENUITEM "Skip Number of Frames", ID_OPTIONS_FRAMESKIPTYPE_COUNT MENUITEM "Skip Percent of FPS", ID_OPTIONS_FRAMESKIPTYPE_PRCNT END - POPUP "Texture Filtering" + POPUP "Texture Filtering", ID_OPTIONS_TEXTUREFILTERING_MENU BEGIN MENUITEM "Auto", ID_OPTIONS_TEXTUREFILTERING_AUTO MENUITEM "Nearest", ID_OPTIONS_NEARESTFILTERING MENUITEM "Linear", ID_OPTIONS_LINEARFILTERING MENUITEM "Linear on FMV", ID_OPTIONS_LINEARFILTERING_CG END - POPUP "Screen Scaling Filter" + POPUP "Screen Scaling Filter", ID_OPTIONS_SCREENFILTER_MENU BEGIN MENUITEM "Linear", ID_OPTIONS_BUFLINEARFILTER MENUITEM "Nearest", ID_OPTIONS_BUFNEARESTFILTER END - POPUP "Texture Scaling" + POPUP "Texture Scaling", ID_OPTIONS_TEXTURESCALING_MENU BEGIN MENUITEM "Off", ID_TEXTURESCALING_OFF MENUITEM "Auto", ID_TEXTURESCALING_AUTO @@ -615,20 +618,20 @@ BEGIN MENUITEM "&3x", ID_TEXTURESCALING_3X MENUITEM "&4x", ID_TEXTURESCALING_4X MENUITEM "&5x", ID_TEXTURESCALING_5X - MENUITEM SEPARATOR + MENUITEM "", 0, MFT_SEPARATOR MENUITEM "xBRZ", ID_TEXTURESCALING_XBRZ MENUITEM "Hybrid", ID_TEXTURESCALING_HYBRID MENUITEM "Bicubic", ID_TEXTURESCALING_BICUBIC MENUITEM "Hybrid + Bicubic", ID_TEXTURESCALING_HYBRID_BICUBIC - MENUITEM SEPARATOR + MENUITEM "", 0, MFT_SEPARATOR MENUITEM "Deposterize", ID_TEXTURESCALING_DEPOSTERIZE END MENUITEM "Hardware Transform", ID_OPTIONS_HARDWARETRANSFORM MENUITEM "Vertex Cache", ID_OPTIONS_VERTEXCACHE MENUITEM "Show FPS Counter", ID_OPTIONS_SHOWFPS - MENUITEM SEPARATOR - MENUITEM "Enable Sound", ID_EMULATION_SOUND, CHECKED - MENUITEM SEPARATOR + MENUITEM "", 0, MFT_SEPARATOR + MENUITEM "Enable Sound", ID_EMULATION_SOUND + MENUITEM "", 0, MFT_SEPARATOR MENUITEM "Enable Cheats", ID_EMULATION_CHEATS END END diff --git a/Windows/resource.h b/Windows/resource.h index d6394a20bb..7ae3fc5b45 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -288,7 +288,7 @@ #define IDC_GEDBG_LISTS_ALLLISTS 40123 #define IDC_GEDBG_LISTS_STACK 40124 #define IDC_GEDBG_LISTS_SELECTEDLIST 40125 -#define ID_OPTIONS_FXAA 40126 +#define ID_OPTIONS_SHADER_MENU 40126 #define IDC_DEBUG_BOTTOMTABS 40127 #define ID_DEBUG_HIDEBOTTOMTABS 40128 #define ID_DEBUG_TOGGLEBOTTOMTABTITLES 40129 @@ -345,6 +345,23 @@ #define IDC_GEDBG_STEPCURVE 40179 #define ID_OPTIONS_FRAMESKIPTYPE_COUNT 40180 #define ID_OPTIONS_FRAMESKIPTYPE_PRCNT 40181 +#define ID_FILE_MENU 40182 +#define ID_EMULATION_MENU 40183 +#define ID_DEBUG_MENU 40184 +#define ID_OPTIONS_MENU 40185 +#define ID_HELP_MENU 40186 +#define ID_FILE_SAVESTATE_SLOT_MENU 40187 +#define ID_FILE_RECORD_MENU 40188 +#define ID_EMULATION_ROTATION_MENU 40189 +#define ID_OPTIONS_SCREEN_MENU 40190 +#define ID_OPTIONS_WINDOW_MENU 40191 +#define ID_OPTIONS_BACKEND_MENU 40192 +#define ID_OPTIONS_RENDERMODE_MENU 40193 +#define ID_OPTIONS_FRAMESKIP_MENU 40194 +#define ID_OPTIONS_FRAMESKIPTYPE_MENU 40195 +#define ID_OPTIONS_TEXTUREFILTERING_MENU 40196 +#define ID_OPTIONS_SCREENFILTER_MENU 40197 +#define ID_OPTIONS_TEXTURESCALING_MENU 40198 // Dummy option to let the buffered rendering hotkey cycle through all the options. #define ID_OPTIONS_BUFFEREDRENDERINGDUMMY 40500 @@ -357,7 +374,7 @@ #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 256 -#define _APS_NEXT_COMMAND_VALUE 40178 +#define _APS_NEXT_COMMAND_VALUE 40199 #define _APS_NEXT_CONTROL_VALUE 1200 #define _APS_NEXT_SYMED_VALUE 101 #endif From db7cdce27cc8050b435213bac1fad4de838a8514 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 28 Nov 2018 21:58:54 -0800 Subject: [PATCH 173/347] Windows: Define menu item text in menu only. Except Run/Stop which changes, let's not use this parameter. --- Windows/MainWindowMenu.cpp | 44 ++++++++++++++------------------------ Windows/ppsspp.rc | 9 ++++++-- 2 files changed, 23 insertions(+), 30 deletions(-) diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index 8cad334007..ce9baab828 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -118,7 +118,6 @@ namespace MainWindow { void CreateHelpMenu(HMENU menu) { I18NCategory *des = GetI18NCategory("DesktopUI"); - const std::wstring help = ConvertUTF8ToWString(des->T("Help")); const std::wstring visitMainWebsite = ConvertUTF8ToWString(des->T("www.ppsspp.org")); const std::wstring visitForum = ConvertUTF8ToWString(des->T("PPSSPP Forums")); const std::wstring buyGold = ConvertUTF8ToWString(des->T("Buy Gold")); @@ -126,11 +125,8 @@ namespace MainWindow { const std::wstring discord = ConvertUTF8ToWString(des->T("Discord")); const std::wstring aboutPPSSPP = ConvertUTF8ToWString(des->T("About PPSSPP...")); - // Simply remove the old help menu and create a new one. - RemoveMenu(menu, ID_HELP_MENU, MF_BYCOMMAND); - - HMENU helpMenu = CreatePopupMenu(); - InsertMenu(menu, ID_HELP_MENU, MF_POPUP | MF_STRING | MF_BYCOMMAND, (UINT_PTR)helpMenu, help.c_str()); + HMENU helpMenu = GetSubmenuById(menu, ID_HELP_MENU); + EmptySubMenu(helpMenu); AppendMenu(helpMenu, MF_STRING | MF_BYCOMMAND, ID_HELP_OPENWEBSITE, visitMainWebsite.c_str()); AppendMenu(helpMenu, MF_STRING | MF_BYCOMMAND, ID_HELP_OPENFORUM, visitForum.c_str()); @@ -196,34 +192,26 @@ namespace MainWindow { return true; } - static void _TranslateMenuItem(const HMENU hMenu, const int menuIDOrPosition, const char *key, bool byCommand = false, const std::wstring& accelerator = L"") { + static void TranslateMenuItem(const HMENU hMenu, const int menuID, const std::wstring& accelerator = L"", const char *key = nullptr) { I18NCategory *des = GetI18NCategory("DesktopUI"); - std::wstring translated = ConvertUTF8ToWString(des->T(key)); + std::wstring translated; + if (key == nullptr || !strcmp(key, "")) { + translated = ConvertUTF8ToWString(des->T(GetMenuItemInitialText(hMenu, menuID))); + } else { + translated = ConvertUTF8ToWString(des->T(key)); + } translated.append(accelerator); - u32 flags = MF_STRING | (byCommand ? MF_BYCOMMAND : MF_BYPOSITION); - - ModifyMenu(hMenu, menuIDOrPosition, flags, menuIDOrPosition, translated.c_str()); - } - - void TranslateMenuItem(HMENU menu, int menuID, const std::wstring& accelerator = L"", const char *key = "") { - if (key == nullptr || !strcmp(key, "")) - _TranslateMenuItem(menu, menuID, GetMenuItemInitialText(menu, menuID).c_str(), true, accelerator); - else - _TranslateMenuItem(menu, menuID, key, true, accelerator); - } - - void TranslateMenu(HMENU menu, const char *key, const int itemID, const std::wstring& accelerator = L"") { - _TranslateMenuItem(menu, itemID, key, true, accelerator); + ModifyMenu(hMenu, menuID, MF_STRING | MF_BYCOMMAND, menuID, translated.c_str()); } void DoTranslateMenus(HWND hWnd, HMENU menu) { - TranslateMenu(menu, "File", ID_FILE_MENU); - TranslateMenu(menu, "Emulation", ID_EMULATION_MENU); - TranslateMenu(menu, "Debugging", ID_DEBUG_MENU); - TranslateMenu(menu, "Game Settings", ID_OPTIONS_MENU); - TranslateMenu(menu, "Help", ID_HELP_MENU); + TranslateMenuItem(menu, ID_FILE_MENU); + TranslateMenuItem(menu, ID_EMULATION_MENU); + TranslateMenuItem(menu, ID_DEBUG_MENU); + TranslateMenuItem(menu, ID_OPTIONS_MENU); + TranslateMenuItem(menu, ID_HELP_MENU); // File menu TranslateMenuItem(menu, ID_FILE_LOAD); @@ -242,7 +230,7 @@ namespace MainWindow { TranslateMenuItem(menu, ID_EMULATION_PAUSE); TranslateMenuItem(menu, ID_EMULATION_STOP, L"\tCtrl+W"); TranslateMenuItem(menu, ID_EMULATION_RESET, L"\tCtrl+B"); - TranslateMenuItem(menu, ID_EMULATION_SWITCH_UMD, L"\tCtrl+U", "Switch UMD"); + TranslateMenuItem(menu, ID_EMULATION_SWITCH_UMD, L"\tCtrl+U"); TranslateMenuItem(menu, ID_EMULATION_ROTATION_MENU); TranslateMenuItem(menu, ID_EMULATION_ROTATION_H); TranslateMenuItem(menu, ID_EMULATION_ROTATION_V); diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index e554b90a06..4d3ae58dcf 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -498,7 +498,7 @@ BEGIN END END - POPUP "Debug", ID_DEBUG_MENU + POPUP "Debugging", ID_DEBUG_MENU BEGIN MENUITEM "Run", ID_TOGGLE_BREAK MENUITEM "Break on Load", ID_DEBUG_BREAKONLOAD @@ -521,7 +521,7 @@ BEGIN MENUITEM "Memory View...", ID_DEBUG_MEMORYVIEW END - POPUP "Options", ID_OPTIONS_MENU + POPUP "Game Settings", ID_OPTIONS_MENU BEGIN MENUITEM "Keep PPSSPP On Top", ID_OPTIONS_TOPMOST MENUITEM "Pause When Not Focused", ID_OPTIONS_PAUSE_FOCUS @@ -634,6 +634,11 @@ BEGIN MENUITEM "", 0, MFT_SEPARATOR MENUITEM "Enable Cheats", ID_EMULATION_CHEATS END + + POPUP "Help", ID_HELP_MENU + BEGIN + MENUITEM "", 0, MFT_SEPARATOR + END END IDR_POPUPMENUS MENU From 1517d66d4ed966613e6456dc8716a4aa7d489ee1 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 29 Nov 2018 19:03:38 -0800 Subject: [PATCH 174/347] GPU: Properly flip cull on simple triangle lists. Fixes #11601. --- GPU/Common/IndexGenerator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Common/IndexGenerator.cpp b/GPU/Common/IndexGenerator.cpp index 9c1b13d42d..06bef591df 100644 --- a/GPU/Common/IndexGenerator.cpp +++ b/GPU/Common/IndexGenerator.cpp @@ -218,7 +218,7 @@ void IndexGenerator::TranslateList(int numInds, const ITypeLE *inds, int indexOf indexOffset = index_ - indexOffset; // We only bother doing this minor optimization in triangle list, since it's by far the most // common operation that can benefit. - if (sizeof(ITypeLE) == sizeof(inds_[0]) && indexOffset == 0) { + if (sizeof(ITypeLE) == sizeof(inds_[0]) && indexOffset == 0 && clockwise) { memcpy(inds_, inds, numInds * sizeof(ITypeLE)); inds_ += numInds; count_ += numInds; From d3db5653442cd391016b56140840dc1279da5c89 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 29 Nov 2018 19:28:10 -0800 Subject: [PATCH 175/347] GPU: Maintain a bit more state in inner-prim loop. Trying to make dumps properly trigger this optimization, but they still sometimes get flattened and don't. --- GPU/GPUCommon.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index dc53f28cdd..2030f23f01 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1627,8 +1627,13 @@ void GPUCommon::Execute_Prim(u32 op, u32 diff) { break; } case GE_CMD_VADDR: + gstate.cmdmem[data >> 24] = data; gstate_c.vertexAddr = gstate_c.getRelativeAddress(data & 0x00FFFFFF); break; + case GE_CMD_IADDR: + gstate.cmdmem[data >> 24] = data; + gstate_c.indexAddr = gstate_c.getRelativeAddress(data & 0x00FFFFFF); + break; case GE_CMD_OFFSETADDR: gstate.cmdmem[GE_CMD_OFFSETADDR] = data; gstate_c.offsetAddr = data << 8; @@ -1646,8 +1651,10 @@ void GPUCommon::Execute_Prim(u32 op, u32 diff) { // flip face by indices for triangles cullMode = data & 1; break; + case GE_CMD_TEXFLUSH: case GE_CMD_NOP: case GE_CMD_NOP_FF: + gstate.cmdmem[data >> 24] = data; break; case GE_CMD_BONEMATRIXNUMBER: gstate.cmdmem[GE_CMD_BONEMATRIXNUMBER] = data; @@ -1690,6 +1697,12 @@ void GPUCommon::Execute_Prim(u32 op, u32 diff) { break; } + case GE_CMD_TEXBUFWIDTH0: + case GE_CMD_TEXADDR0: + if (data != gstate.cmdmem[data >> 24]) + goto bail; + break; + default: // All other commands might need a flush or something, stop this inner loop. goto bail; From 636a7a260111fcea2d0467163f234c3c006e6b88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 30 Nov 2018 10:57:56 +0100 Subject: [PATCH 176/347] Update lang --- assets/lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/lang b/assets/lang index 3f5e33f843..a6c1c24e8d 160000 --- a/assets/lang +++ b/assets/lang @@ -1 +1 @@ -Subproject commit 3f5e33f84319ab4d8b8e19612d46db431907706f +Subproject commit a6c1c24e8dfe35afb56210fc46110dbf6fb6f593 From 7b815af3318e104d6338c91171cbf4133fde5a7b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 30 Nov 2018 07:22:28 -0800 Subject: [PATCH 177/347] GPU: Force use of indexes on cull mode flip. Since we flip in the index, it can't be pure in this case. --- GPU/Common/IndexGenerator.cpp | 10 +++++++++- GPU/Common/ShaderId.h | 1 - GPU/GPUCommon.cpp | 5 +++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/GPU/Common/IndexGenerator.cpp b/GPU/Common/IndexGenerator.cpp index 06bef591df..d339fb4790 100644 --- a/GPU/Common/IndexGenerator.cpp +++ b/GPU/Common/IndexGenerator.cpp @@ -77,6 +77,10 @@ void IndexGenerator::AddList(int numVerts, bool clockwise) { count_ += numVerts; prim_ = GE_PRIM_TRIANGLES; seenPrims_ |= 1 << GE_PRIM_TRIANGLES; + if (!clockwise) { + // Make sure we don't treat this as pure. + seenPrims_ |= 1 << GE_PRIM_TRIANGLE_STRIP; + } } void IndexGenerator::AddStrip(int numVerts, bool clockwise) { @@ -96,7 +100,7 @@ void IndexGenerator::AddStrip(int numVerts, bool clockwise) { if (numTris > 0) count_ += numTris * 3; // This is so we can detect one single strip by just looking at seenPrims_. - if (!seenPrims_) { + if (!seenPrims_ && clockwise) { seenPrims_ = 1 << GE_PRIM_TRIANGLE_STRIP; prim_ = GE_PRIM_TRIANGLE_STRIP; pureCount_ = numVerts; @@ -123,6 +127,10 @@ void IndexGenerator::AddFan(int numVerts, bool clockwise) { count_ += numTris * 3; prim_ = GE_PRIM_TRIANGLES; seenPrims_ |= 1 << GE_PRIM_TRIANGLE_FAN; + if (!clockwise) { + // Make sure we don't treat this as pure. + seenPrims_ |= 1 << GE_PRIM_TRIANGLE_STRIP; + } } //Lines diff --git a/GPU/Common/ShaderId.h b/GPU/Common/ShaderId.h index 573da9c3f3..df0efb36d5 100644 --- a/GPU/Common/ShaderId.h +++ b/GPU/Common/ShaderId.h @@ -176,7 +176,6 @@ struct FShaderID : ShaderID { }; -bool CanUseHardwareTransform(int prim); void ComputeVertexShaderID(ShaderID *id, uint32_t vertexType, bool useHWTransform); // Generates a compact string that describes the shader. Useful in a list to get an overview // of the current flora of shaders. diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 2030f23f01..3b55b566db 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1537,7 +1537,7 @@ void GPUCommon::Execute_Prim(u32 op, u32 diff) { } void *verts = Memory::GetPointerUnchecked(gstate_c.vertexAddr); - void *inds = 0; + void *inds = nullptr; u32 vertexType = gstate.vertType; if ((vertexType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { u32 indexAddr = gstate_c.indexAddr; @@ -1602,9 +1602,10 @@ void GPUCommon::Execute_Prim(u32 op, u32 diff) { } GEPrimitiveType newPrim = static_cast((data >> 16) & 7); + SetDrawType(DRAW_PRIM, newPrim); // TODO: more efficient updating of verts/inds verts = Memory::GetPointerUnchecked(gstate_c.vertexAddr); - inds = 0; + inds = nullptr; if ((vertexType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { inds = Memory::GetPointerUnchecked(gstate_c.indexAddr); } From 6d8b78f523961e58d40131d3ea6ce2c63c8c00c5 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 30 Nov 2018 17:45:54 -0800 Subject: [PATCH 178/347] Headless: Allow startup using NULL core. Or maybe we should have a dummy Draw context... --- GPU/GPU.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GPU.cpp b/GPU/GPU.cpp index 3a4f9a921e..2fe380d3c1 100644 --- a/GPU/GPU.cpp +++ b/GPU/GPU.cpp @@ -61,7 +61,7 @@ bool GPU_IsReady() { } bool GPU_Init(GraphicsContext *ctx, Draw::DrawContext *draw) { - _assert_(draw); + _assert_(draw || PSP_CoreParameter().gpuCore == GPUCORE_NULL); #if PPSSPP_PLATFORM(UWP) SetGPU(new GPU_D3D11(ctx, draw)); return true; From d573bf9cc91061a9394992e1697807f18e5899d7 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 30 Nov 2018 17:46:47 -0800 Subject: [PATCH 179/347] Headless: Fix compare for 16-bit output. Most tests have been 32-bit output, so haven't run into this. Enables tests with softgpu to generate 16-bit output. --- headless/Compare.cpp | 44 +++++++++++++++++++++++++++++-------------- headless/StubHost.cpp | 2 +- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/headless/Compare.cpp b/headless/Compare.cpp index 556bd32873..ba35b93c90 100644 --- a/headless/Compare.cpp +++ b/headless/Compare.cpp @@ -301,28 +301,44 @@ std::vector TranslateDebugBufferToCompare(const GPUDebugBuffer *buffer, u32 std::vector data; data.resize(stride * h, 0); - const u32 *pixels = (const u32 *)buffer->GetData(); + const u32 *pixels32 = (const u32 *)buffer->GetData(); + const u16 *pixels16 = (const u16 *)buffer->GetData(); int outStride = buffer->GetStride(); - if (!buffer->GetFlipped()) - { + if (!buffer->GetFlipped()) { // Bitmaps are flipped, so we have to compare backwards in this case. - pixels += outStride * (buffer->GetHeight() - 1); + int toLastRow = outStride * (buffer->GetHeight() - 1); + pixels32 += toLastRow; + pixels16 += toLastRow; outStride = -outStride; } u32 errors = 0; - for (u32 y = 0; y < safeH; ++y) - { - if (buffer->GetFormat() == GPU_DBG_FORMAT_8888) - ConvertBGRA8888ToRGBA8888(&data[y * stride], pixels, safeW); - else if (buffer->GetFormat() == GPU_DBG_FORMAT_8888_BGRA) - memcpy(&data[y * stride], pixels, safeW * sizeof(u32)); - else - { + for (u32 y = 0; y < safeH; ++y) { + switch (buffer->GetFormat()) { + case GPU_DBG_FORMAT_8888: + ConvertBGRA8888ToRGBA8888(&data[y * stride], pixels32, safeW); + break; + case GPU_DBG_FORMAT_8888_BGRA: + memcpy(&data[y * stride], pixels32, safeW * sizeof(u32)); + break; + + case GPU_DBG_FORMAT_565: + ConvertRGB565ToBGRA8888(&data[y * stride], pixels16, safeW); + break; + case GPU_DBG_FORMAT_5551: + ConvertRGBA5551ToBGRA8888(&data[y * stride], pixels16, safeW); + break; + case GPU_DBG_FORMAT_4444: + ConvertRGBA4444ToBGRA8888(&data[y * stride], pixels16, safeW); + break; + + default: data.resize(0); return data; } - pixels += outStride; + + pixels32 += outStride; + pixels16 += outStride; } return data; @@ -365,4 +381,4 @@ double CompareScreenshot(const std::vector &pixels, u32 stride, u32 w, u32 free(reference); return (double) errors / (double) (w * h); -} \ No newline at end of file +} diff --git a/headless/StubHost.cpp b/headless/StubHost.cpp index dc3520013e..6569cc3b1a 100644 --- a/headless/StubHost.cpp +++ b/headless/StubHost.cpp @@ -55,7 +55,7 @@ void HeadlessHost::SendDebugScreenshot(const u8 *pixbuf, u32 w, u32 h) std::string error; double errors = CompareScreenshot(pixels, FRAME_STRIDE, FRAME_WIDTH, FRAME_HEIGHT, comparisonScreenshot_, error); if (errors < 0) - SendOrCollectDebugOutput(error); + SendOrCollectDebugOutput(error + "\n"); if (errors > 0) { From b95c76f3bb50cd6ff9a23d34be8a4cf05cb10cd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 1 Dec 2018 12:30:31 +0100 Subject: [PATCH 180/347] Update lang again --- assets/lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/lang b/assets/lang index a6c1c24e8d..67c189ca63 160000 --- a/assets/lang +++ b/assets/lang @@ -1 +1 @@ -Subproject commit a6c1c24e8dfe35afb56210fc46110dbf6fb6f593 +Subproject commit 67c189ca63c68cba9e0146c98c89b2a8e9a10975 From 4d5c8fcff4e5dbbc6a99ee42f8eaa66af0a915ff Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 1 Dec 2018 06:26:35 -0800 Subject: [PATCH 181/347] GE Debugger: Track a counter of prims. --- GPU/Debugger/Debugger.cpp | 22 ++++++++++++++++++++++ GPU/Debugger/Debugger.h | 3 +++ GPU/Debugger/Stepping.cpp | 1 + Windows/GEDebugger/GEDebugger.cpp | 5 +++++ Windows/ppsspp.rc | 17 +++++++++-------- Windows/resource.h | 3 ++- 6 files changed, 42 insertions(+), 9 deletions(-) diff --git a/GPU/Debugger/Debugger.cpp b/GPU/Debugger/Debugger.cpp index 088836c2ff..27083674b0 100644 --- a/GPU/Debugger/Debugger.cpp +++ b/GPU/Debugger/Debugger.cpp @@ -26,6 +26,10 @@ static bool active = false; static bool inited = false; static BreakNext breakNext = BreakNext::NONE; +static int primsLastFrame = 0; +static int primsThisFrame = 0; +static int thisFlipNum = 0; + static void Init() { if (!inited) { GPUBreakpoints::Init(); @@ -68,6 +72,16 @@ void NotifyCommand(u32 pc) { if (!active) return; u32 op = Memory::ReadUnchecked_U32(pc); + u32 cmd = op >> 24; + if (thisFlipNum != gpuStats.numFlips) { + primsLastFrame = primsThisFrame; + primsThisFrame = 0; + thisFlipNum = gpuStats.numFlips; + } + if (cmd == GE_CMD_PRIM || cmd == GE_CMD_BEZIER || cmd == GE_CMD_SPLINE) { + primsThisFrame++; + } + if (breakNext == BreakNext::OP || GPUBreakpoints::IsBreakpoint(pc, op)) { GPUBreakpoints::ClearTempBreakpoints(); @@ -100,4 +114,12 @@ void NotifyTextureAttachment(u32 texaddr) { return; } +int PrimsThisFrame() { + return primsThisFrame; +} + +int PrimsLastFrame() { + return primsLastFrame; +} + } diff --git a/GPU/Debugger/Debugger.h b/GPU/Debugger/Debugger.h index 2a45f93ba0..193b4630ec 100644 --- a/GPU/Debugger/Debugger.h +++ b/GPU/Debugger/Debugger.h @@ -43,4 +43,7 @@ void NotifyDraw(); void NotifyDisplay(u32 framebuf, u32 stride, int format); void NotifyTextureAttachment(u32 texaddr); +int PrimsThisFrame(); +int PrimsLastFrame(); + } diff --git a/GPU/Debugger/Stepping.cpp b/GPU/Debugger/Stepping.cpp index b277496556..bf5ddb4834 100644 --- a/GPU/Debugger/Stepping.cpp +++ b/GPU/Debugger/Stepping.cpp @@ -38,6 +38,7 @@ enum PauseAction { }; static bool isStepping; +// Number of times we've entered stepping, to detect a resume asynchronously. static int stepCounter = 0; static std::mutex pauseLock; diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index e36fe84a52..5d4f978357 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -291,6 +291,10 @@ void CGEDebugger::UpdatePreviews() { displayList->setDisplayList(list); } + wchar_t primCounter[1024]{}; + swprintf(primCounter, ARRAY_SIZE(primCounter), L"%d/%d", PrimsThisFrame(), PrimsLastFrame()); + SetDlgItemText(m_hDlg, IDC_GEDBG_PRIMCOUNTER, primCounter); + flags->Update(); lighting->Update(); textureState->Update(); @@ -778,6 +782,7 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { secondWindow->Clear(); SetDlgItemText(m_hDlg, IDC_GEDBG_FRAMEBUFADDR, L""); SetDlgItemText(m_hDlg, IDC_GEDBG_TEXADDR, L""); + SetDlgItemText(m_hDlg, IDC_GEDBG_PRIMCOUNTER, L""); SetBreakNext(BreakNext::NONE); break; diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index 4d3ae58dcf..3aa2993ec6 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -210,14 +210,15 @@ EXSTYLE WS_EX_ACCEPTFILES | WS_EX_TOOLWINDOW CAPTION "GE" FONT 8, "MS Shell Dlg", 0, 0, 0x1 BEGIN - PUSHBUTTON "Step &Frame",IDC_GEDBG_STEPFRAME,10,2,48,14 - PUSHBUTTON "Step &Tex",IDC_GEDBG_STEPTEX,62,2,48,14 - PUSHBUTTON "Step &Draw",IDC_GEDBG_STEPDRAW,114,2,48,14 - PUSHBUTTON "Step &Prim",IDC_GEDBG_STEPPRIM,166,2,48,14 - PUSHBUTTON "Step &Curve",IDC_GEDBG_STEPCURVE,218,2,48,14 - PUSHBUTTON "Step &Into",IDC_GEDBG_STEP,270,2,48,14 - PUSHBUTTON "&Resume",IDC_GEDBG_RESUME,322,2,48,14 - PUSHBUTTON "Rec&ord",IDC_GEDBG_RECORD,440,2,48,14 + PUSHBUTTON "Step &Frame",IDC_GEDBG_STEPFRAME,10,2,44,14 + PUSHBUTTON "Step &Tex",IDC_GEDBG_STEPTEX,55,2,44,14 + PUSHBUTTON "Step &Draw",IDC_GEDBG_STEPDRAW,100,2,44,14 + PUSHBUTTON "Step &Prim",IDC_GEDBG_STEPPRIM,145,2,44,14 + PUSHBUTTON "Step &Curve",IDC_GEDBG_STEPCURVE,190,2,44,14 + PUSHBUTTON "Step &Into",IDC_GEDBG_STEP,235,2,44,14 + EDITTEXT IDC_GEDBG_PRIMCOUNTER,340,4,44,12,ES_READONLY | NOT WS_BORDER + PUSHBUTTON "&Resume",IDC_GEDBG_RESUME,396,2,44,14 + PUSHBUTTON "Rec&ord",IDC_GEDBG_RECORD,444,2,44,14 CONTROL "",IDC_GEDBG_TEX,"SimpleGLWindow",WS_CHILD | WS_VISIBLE,10,20,128,128 CONTROL "",IDC_GEDBG_FRAME,"SimpleGLWindow",WS_CHILD | WS_VISIBLE,148,20,256,136 CONTROL "",IDC_GEDBG_MAINTAB,"SysTabControl32",TCS_TABS | TCS_FOCUSNEVER,10,216,480,180 diff --git a/Windows/resource.h b/Windows/resource.h index 7ae3fc5b45..1d56567dcd 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -165,6 +165,7 @@ #define IDC_GEDBG_SHOWCLUT 1198 #define IDC_BREAKPOINT_LOG_FORMAT 1199 #define IDC_SHOWOFFSETS 1200 +#define IDC_GEDBG_PRIMCOUNTER 1201 #define ID_SHADERS_BASE 5000 @@ -375,7 +376,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 256 #define _APS_NEXT_COMMAND_VALUE 40199 -#define _APS_NEXT_CONTROL_VALUE 1200 +#define _APS_NEXT_CONTROL_VALUE 1202 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif From e029168be2fc0a92975f99a8e6381446e11adebc Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 1 Dec 2018 06:40:27 -0800 Subject: [PATCH 182/347] GE Debugger: Allow jumping to a specific prim. This will make the most sense when frames are relatively stable, and works great for GE dumps. --- GPU/Debugger/Debugger.cpp | 21 +++++++++++++++++++-- GPU/Debugger/Debugger.h | 2 ++ Windows/GEDebugger/GEDebugger.cpp | 14 ++++++++++++++ Windows/ppsspp.rc | 3 ++- Windows/resource.h | 3 ++- 5 files changed, 39 insertions(+), 4 deletions(-) diff --git a/GPU/Debugger/Debugger.cpp b/GPU/Debugger/Debugger.cpp index 27083674b0..9591cec8c1 100644 --- a/GPU/Debugger/Debugger.cpp +++ b/GPU/Debugger/Debugger.cpp @@ -25,6 +25,7 @@ namespace GPUDebug { static bool active = false; static bool inited = false; static BreakNext breakNext = BreakNext::NONE; +static int breakAtCount = -1; static int primsLastFrame = 0; static int primsThisFrame = 0; @@ -44,6 +45,7 @@ void SetActive(bool flag) { active = flag; if (!active) { breakNext = BreakNext::NONE; + breakAtCount = -1; GPUStepping::ResumeFromStepping(); } } @@ -55,9 +57,10 @@ bool IsActive() { void SetBreakNext(BreakNext next) { SetActive(true); breakNext = next; + breakAtCount = -1; if (next == BreakNext::TEX) { GPUBreakpoints::AddTextureChangeTempBreakpoint(); - } else if (next == BreakNext::PRIM) { + } else if (next == BreakNext::PRIM || next == BreakNext::COUNT) { GPUBreakpoints::AddCmdBreakpoint(GE_CMD_PRIM, true); GPUBreakpoints::AddCmdBreakpoint(GE_CMD_BEZIER, true); GPUBreakpoints::AddCmdBreakpoint(GE_CMD_SPLINE, true); @@ -68,6 +71,20 @@ void SetBreakNext(BreakNext next) { GPUStepping::ResumeFromStepping(); } +void SetBreakCount(int c) { + breakAtCount = c; +} + +static bool IsBreakpoint(u32 pc, u32 op) { + if (breakNext == BreakNext::OP) { + return true; + } else if (breakNext == BreakNext::COUNT) { + return primsThisFrame == breakAtCount; + } else { + return GPUBreakpoints::IsBreakpoint(pc, op); + } +} + void NotifyCommand(u32 pc) { if (!active) return; @@ -82,7 +99,7 @@ void NotifyCommand(u32 pc) { primsThisFrame++; } - if (breakNext == BreakNext::OP || GPUBreakpoints::IsBreakpoint(pc, op)) { + if (IsBreakpoint(pc, op)) { GPUBreakpoints::ClearTempBreakpoints(); auto info = gpuDebug->DissassembleOp(pc); diff --git a/GPU/Debugger/Debugger.h b/GPU/Debugger/Debugger.h index 193b4630ec..b459f5a859 100644 --- a/GPU/Debugger/Debugger.h +++ b/GPU/Debugger/Debugger.h @@ -30,12 +30,14 @@ enum class BreakNext { FRAME, PRIM, CURVE, + COUNT, }; void SetActive(bool flag); bool IsActive(); void SetBreakNext(BreakNext next); +void SetBreakCount(int c); // While debugging is active, these may block. void NotifyCommand(u32 pc); diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index 5d4f978357..8ff0223ecd 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -20,6 +20,7 @@ #include #include +#include "base/stringutil.h" #include "Common/ColorConv.h" #include "Core/Config.h" #include "Core/Screenshot.h" @@ -724,6 +725,19 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { SetBreakNext(BreakNext::CURVE); break; + case IDC_GEDBG_STEPCOUNT: + { + std::string value; + int count; + if (InputBox_GetString(GetModuleHandle(NULL), m_hDlg, L"Prim count", "", value)) { + if (TryParse(value, &count)) { + SetBreakNext(BreakNext::COUNT); + SetBreakCount(count); + } + } + } + break; + case IDC_GEDBG_BREAKTEX: { GPUDebug::SetActive(true); diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index 3aa2993ec6..195f92eb05 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -216,7 +216,8 @@ BEGIN PUSHBUTTON "Step &Prim",IDC_GEDBG_STEPPRIM,145,2,44,14 PUSHBUTTON "Step &Curve",IDC_GEDBG_STEPCURVE,190,2,44,14 PUSHBUTTON "Step &Into",IDC_GEDBG_STEP,235,2,44,14 - EDITTEXT IDC_GEDBG_PRIMCOUNTER,340,4,44,12,ES_READONLY | NOT WS_BORDER + PUSHBUTTON "Step Cou&nt",IDC_GEDBG_STEPCOUNT,280,2,44,14 + EDITTEXT IDC_GEDBG_PRIMCOUNTER,325,4,50,12,ES_READONLY | NOT WS_BORDER PUSHBUTTON "&Resume",IDC_GEDBG_RESUME,396,2,44,14 PUSHBUTTON "Rec&ord",IDC_GEDBG_RECORD,444,2,44,14 CONTROL "",IDC_GEDBG_TEX,"SimpleGLWindow",WS_CHILD | WS_VISIBLE,10,20,128,128 diff --git a/Windows/resource.h b/Windows/resource.h index 1d56567dcd..ee64c5759f 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -363,6 +363,7 @@ #define ID_OPTIONS_TEXTUREFILTERING_MENU 40196 #define ID_OPTIONS_SCREENFILTER_MENU 40197 #define ID_OPTIONS_TEXTURESCALING_MENU 40198 +#define IDC_GEDBG_STEPCOUNT 40199 // Dummy option to let the buffered rendering hotkey cycle through all the options. #define ID_OPTIONS_BUFFEREDRENDERINGDUMMY 40500 @@ -375,7 +376,7 @@ #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 256 -#define _APS_NEXT_COMMAND_VALUE 40199 +#define _APS_NEXT_COMMAND_VALUE 40200 #define _APS_NEXT_CONTROL_VALUE 1202 #define _APS_NEXT_SYMED_VALUE 101 #endif From ac6106af03f1a20db2859a23a1f41cdc9d118b87 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 1 Dec 2018 09:43:02 -0800 Subject: [PATCH 183/347] Io: Ensure sign extension for error codes. The ternary `cond ? EnumValue : IntValue` was not sign extending consistently across compilers, but we actually want it to always sign extend in either case. --- Core/HLE/sceIo.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index dc85a0816b..e4a525f5d7 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -991,7 +991,7 @@ static u32 sceIoReadAsync(int id, u32 data_addr, int size) { int us; bool complete = __IoRead(result, id, data_addr, size, us); if (complete) { - f->asyncResult = result; + f->asyncResult = (s64)result; DEBUG_LOG(SCEIO, "%llx=sceIoReadAsync(%d, %08x, %x)", f->asyncResult, id, data_addr, size); } else { DEBUG_LOG(SCEIO, "sceIoReadAsync(%d, %08x, %x): deferring result", id, data_addr, size); @@ -1125,7 +1125,7 @@ static u32 sceIoWriteAsync(int id, u32 data_addr, int size) { int us; bool complete = __IoWrite(result, id, data_addr, size, us); if (complete) { - f->asyncResult = result; + f->asyncResult = (s64)result; DEBUG_LOG(SCEIO, "%llx=sceIoWriteAsync(%d, %08x, %x)", f->asyncResult, id, data_addr, size); } else { DEBUG_LOG(SCEIO, "sceIoWriteAsync(%d, %08x, %x): deferring result", id, data_addr, size); @@ -1935,7 +1935,7 @@ static u32 sceIoOpenAsync(const char *filename, int flags, int mode) f = new FileNode(); f->handle = kernelObjects.Create(f); f->fullpath = filename; - f->asyncResult = error == 0 ? SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND : error; + f->asyncResult = error == 0 ? (s64)SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND : (s64)error; f->closePending = true; fd = __IoAllocFd(f); From b1e68c653c0461c6f205d459595993d7c0596594 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 1 Dec 2018 13:59:47 -0800 Subject: [PATCH 184/347] GPU: Avoid a missing virtual destructor warning. --- GPU/Common/DrawEngineCommon.h | 1 + GPU/D3D11/DrawEngineD3D11.cpp | 2 ++ GPU/Vulkan/DrawEngineVulkan.cpp | 3 ++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 21a3d06b2c..0d16cf5fae 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -54,6 +54,7 @@ namespace Spline { struct Weight2D; } class TessellationDataTransfer { public: + virtual ~TessellationDataTransfer() {} void CopyControlPoints(float *pos, float *tex, float *col, int posStride, int texStride, int colStride, const SimpleVertex *const *points, int size, u32 vertType); virtual void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) = 0; }; diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index e7752017dc..129325fc69 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -137,6 +137,8 @@ void DrawEngineD3D11::DestroyDeviceObjects() { ClearTrackedVertexArrays(); ClearInputLayoutMap(); delete tessDataTransferD3D11; + tessDataTransferD3D11 = nullptr; + tessDataTransfer = nullptr; delete pushVerts_; delete pushInds_; depthStencilCache_.Iterate([&](const uint64_t &key, ID3D11DepthStencilState *ds) { diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 330f138b46..bc928c3cb2 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -211,7 +211,8 @@ void DrawEngineVulkan::FrameData::Destroy(VulkanContext *vulkan) { void DrawEngineVulkan::DestroyDeviceObjects() { delete tessDataTransferVulkan; - tessDataTransfer = tessDataTransferVulkan = nullptr; + tessDataTransfer = nullptr; + tessDataTransferVulkan = nullptr; for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) { frame_[i].Destroy(vulkan_); From d8c80afe59ac7b46c20b614e9a5dc8ab2c99f447 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 1 Dec 2018 14:00:32 -0800 Subject: [PATCH 185/347] GPU: Dirty stencil on stencil mask change. Otherwise it doesn't always apply. --- GPU/GPUCommon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 3b55b566db..09389ddccb 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -118,7 +118,7 @@ const CommonCommandTableEntry commonCommandTable[] = { { GE_CMD_BLENDFIXEDA, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE }, { GE_CMD_BLENDFIXEDB, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE }, { GE_CMD_MASKRGB, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE }, - { GE_CMD_MASKALPHA, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE }, + { GE_CMD_MASKALPHA, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_DEPTHSTENCIL_STATE }, { GE_CMD_ZTEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHSTENCIL_STATE }, { GE_CMD_ZTESTENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHSTENCIL_STATE | DIRTY_FRAGMENTSHADER_STATE }, { GE_CMD_ZWRITEDISABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHSTENCIL_STATE | DIRTY_FRAGMENTSHADER_STATE }, From 5932cbabc325bc1085eb99e37ed8f5588a56f5c9 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 1 Dec 2018 14:05:29 -0800 Subject: [PATCH 186/347] GPU: Avoid stencil emulation if possible. This reduces use of replaceAlpha, and reduces use of more complicated blend states. This simplifies fragment shaders a little. --- GPU/Common/GPUStateUtils.cpp | 17 ++++++++++++++--- GPU/Common/GPUStateUtils.h | 1 + GPU/D3D11/StateMappingD3D11.cpp | 2 +- GPU/Directx9/StateMappingDX9.cpp | 2 +- GPU/GLES/StateMappingGLES.cpp | 2 +- GPU/Vulkan/StateMappingVulkan.cpp | 2 +- 6 files changed, 19 insertions(+), 7 deletions(-) diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 2a0e88d216..1a650028bc 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -40,6 +40,17 @@ bool CanUseHardwareTransform(int prim) { return !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES; } +bool IsStencilTestOutputDisabled() { + // The mask applies on all stencil ops. + if (gstate.isStencilTestEnabled() && (gstate.pmska & 0xFF) != 0xFF) { + if (gstate.FrameBufFormat() == GE_FORMAT_565) { + return true; + } + return gstate.getStencilOpZPass() == GE_STENCILOP_KEEP && gstate.getStencilOpZFail() == GE_STENCILOP_KEEP && gstate.getStencilOpSFail() == GE_STENCILOP_KEEP; + } + return true; +} + bool NeedsTestDiscard() { // We assume this is called only when enabled and not trivially true (may also be for color testing.) if (gstate.isStencilTestEnabled() && (gstate.pmska & 0xFF) != 0xFF) @@ -169,7 +180,7 @@ const bool nonAlphaDestFactors[16] = { }; ReplaceAlphaType ReplaceAlphaWithStencil(ReplaceBlendType replaceBlend) { - if (!gstate.isStencilTestEnabled() || gstate.isModeClear()) { + if (IsStencilTestOutputDisabled() || gstate.isModeClear()) { return REPLACE_ALPHA_NO; } @@ -995,7 +1006,7 @@ void ConvertBlendState(GenericBlendState &blendState, bool allowShaderBlend) { int constantAlpha = 255; BlendFactor constantAlphaGL = BlendFactor::ONE; - if (gstate.isStencilTestEnabled() && replaceAlphaWithStencil == REPLACE_ALPHA_NO) { + if (!IsStencilTestOutputDisabled() && replaceAlphaWithStencil == REPLACE_ALPHA_NO) { switch (ReplaceAlphaWithStencilType()) { case STENCIL_VALUE_UNIFORM: constantAlpha = gstate.getStencilTestRef(); @@ -1163,7 +1174,7 @@ void ConvertBlendState(GenericBlendState &blendState, bool allowShaderBlend) { blendState.setFactors(glBlendFuncA, glBlendFuncB, BlendFactor::ONE, BlendFactor::ZERO); break; } - } else if (gstate.isStencilTestEnabled()) { + } else if (!IsStencilTestOutputDisabled()) { switch (ReplaceAlphaWithStencilType()) { case STENCIL_VALUE_KEEP: blendState.setFactors(glBlendFuncA, glBlendFuncB, BlendFactor::ZERO, BlendFactor::ONE); diff --git a/GPU/Common/GPUStateUtils.h b/GPU/Common/GPUStateUtils.h index f6a4e11c21..957c6c42b3 100644 --- a/GPU/Common/GPUStateUtils.h +++ b/GPU/Common/GPUStateUtils.h @@ -45,6 +45,7 @@ bool IsColorTestAgainstZero(); bool IsColorTestTriviallyTrue(); bool IsAlphaTestAgainstZero(); bool NeedsTestDiscard(); +bool IsStencilTestOutputDisabled(); StencilValueType ReplaceAlphaWithStencilType(); ReplaceAlphaType ReplaceAlphaWithStencil(ReplaceBlendType replaceBlend); diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp index f5ff8807dc..0dc7a74e4b 100644 --- a/GPU/D3D11/StateMappingD3D11.cpp +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -223,7 +223,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { #endif // Let's not write to alpha if stencil isn't enabled. - if (!gstate.isStencilTestEnabled()) { + if (IsStencilTestOutputDisabled()) { amask = false; } else { // If the stencil type is set to KEEP, we shouldn't write to the stencil/alpha channel. diff --git a/GPU/Directx9/StateMappingDX9.cpp b/GPU/Directx9/StateMappingDX9.cpp index f555ab3d53..3a9d8ffb0c 100644 --- a/GPU/Directx9/StateMappingDX9.cpp +++ b/GPU/Directx9/StateMappingDX9.cpp @@ -181,7 +181,7 @@ void DrawEngineDX9::ApplyDrawState(int prim) { #endif // Let's not write to alpha if stencil isn't enabled. - if (!gstate.isStencilTestEnabled()) { + if (IsStencilTestOutputDisabled()) { amask = false; } else { // If the stencil type is set to KEEP, we shouldn't write to the stencil/alpha channel. diff --git a/GPU/GLES/StateMappingGLES.cpp b/GPU/GLES/StateMappingGLES.cpp index ec256cd842..5a93dbbbb4 100644 --- a/GPU/GLES/StateMappingGLES.cpp +++ b/GPU/GLES/StateMappingGLES.cpp @@ -143,7 +143,7 @@ void DrawEngineGLES::ApplyDrawState(int prim) { // amask is needed for both stencil and blend state so we keep it outside for now bool amask = (gstate.pmska & 0xFF) < 128; // Let's not write to alpha if stencil isn't enabled. - if (!gstate.isStencilTestEnabled()) { + if (IsStencilTestOutputDisabled()) { amask = false; } else { // If the stencil type is set to KEEP, we shouldn't write to the stencil/alpha channel. diff --git a/GPU/Vulkan/StateMappingVulkan.cpp b/GPU/Vulkan/StateMappingVulkan.cpp index 282b602dd8..ff6c141af5 100644 --- a/GPU/Vulkan/StateMappingVulkan.cpp +++ b/GPU/Vulkan/StateMappingVulkan.cpp @@ -225,7 +225,7 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag #endif // Let's not write to alpha if stencil isn't enabled. - if (!gstate.isStencilTestEnabled()) { + if (IsStencilTestOutputDisabled()) { amask = false; } else { // If the stencil type is set to KEEP, we shouldn't write to the stencil/alpha channel. From 9a7ee411918846d00bc1a6f9c22c983c6af6b793 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 1 Dec 2018 14:10:47 -0800 Subject: [PATCH 187/347] Vulkan: Avoid OpKill workaround with no stencil. It seems like depth gets messed up either way on discard, but behaves sorta better without the write to depth. --- GPU/Common/ShaderId.cpp | 7 ++++++- GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp | 5 +++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index e7ed0b4e87..c0cb1a171e 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -201,8 +201,10 @@ std::string FragmentShaderDesc(const ShaderID &id) { case STENCIL_VALUE_INCR_8: desc << "StenIncr8 "; break; case STENCIL_VALUE_DECR_4: desc << "StenDecr4 "; break; case STENCIL_VALUE_DECR_8: desc << "StenDecr4 "; break; - default: desc << "StenUnknown"; break; + default: desc << "StenUnknown "; break; } + } else if (id.Bit(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE)) { + desc << "StenOff "; } if (id.Bit(FS_BIT_DO_TEXTURE)) { switch (id.Bits(FS_BIT_TEXFUNC, 3)) { @@ -292,6 +294,9 @@ void ComputeFragmentShaderID(ShaderID *id_out) { if (stencilToAlpha != REPLACE_ALPHA_NO) { // 4 bits id.SetBits(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE, 4, ReplaceAlphaWithStencilType()); + } else { + // Use those bits instead for whether stencil output is disabled. + id.SetBit(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE, IsStencilTestOutputDisabled()); } // 2 bits. diff --git a/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp b/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp index 77695e881e..1a880efc8f 100644 --- a/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp @@ -84,12 +84,13 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_ const char *shading = doFlatShading ? "flat" : ""; bool earlyFragmentTests = ((!enableAlphaTest && !enableColorTest) || testForceToZero) && !gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT); + bool hasStencilOutput = stencilToAlpha != REPLACE_ALPHA_NO || id.Bit(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE) == 0; bool isAdreno = vulkanVendorId == VULKAN_VENDOR_QUALCOMM; if (earlyFragmentTests) { WRITE(p, "layout (early_fragment_tests) in;\n"); - } else if (isAdreno) { + } else if (isAdreno && hasStencilOutput && !gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) { WRITE(p, "layout (depth_unchanged) out float gl_FragDepth;\n"); } @@ -585,7 +586,7 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_ WRITE(p, " z = (1.0/65535.0) * floor(z * 65535.0);\n"); } WRITE(p, " gl_FragDepth = z;\n"); - } else if (!earlyFragmentTests && isAdreno) { + } else if (!earlyFragmentTests && isAdreno && hasStencilOutput) { // Adreno (and possibly MESA/others) apply early frag tests even with discard in the shader. // Writing depth prevents the bug, even with depth_unchanged specified. WRITE(p, " gl_FragDepth = gl_FragCoord.z;\n"); From 8b6221e852a42766722f676c562bd02083eee14c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 1 Dec 2018 14:57:18 -0800 Subject: [PATCH 188/347] Vulkan: Avoid using Vulkan by default. Bugs on Adreno, some issues on Intel and AMD. Let's instead prefer Direct3D 11 or GLES for now. --- Core/Config.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index a62dbb21f6..dd8e45681f 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -537,12 +537,6 @@ static int DefaultAndroidHwScale() { } static int DefaultGPUBackend() { -#if PPSSPP_PLATFORM(WINDOWS) || PPSSPP_PLATFORM(ANDROID) - // Where supported, let's use Vulkan. - if (VulkanMayBeAvailable()) { - return (int)GPUBackend::VULKAN; - } -#endif #if PPSSPP_PLATFORM(WINDOWS) // If no Vulkan, use Direct3D 11 on Windows 8+ (most importantly 10.) if (DoesVersionMatchWindows(6, 2, 0, 0, true)) { From f88dc9e821b24ed179e9693ba3385806eb188748 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 1 Dec 2018 15:50:20 -0800 Subject: [PATCH 189/347] GE Debugger: Allow relative prim counts. --- GPU/Debugger/Debugger.cpp | 8 ++++++-- GPU/Debugger/Debugger.h | 2 +- Windows/GEDebugger/GEDebugger.cpp | 8 +++++++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/GPU/Debugger/Debugger.cpp b/GPU/Debugger/Debugger.cpp index 9591cec8c1..2d5da1af3a 100644 --- a/GPU/Debugger/Debugger.cpp +++ b/GPU/Debugger/Debugger.cpp @@ -71,8 +71,12 @@ void SetBreakNext(BreakNext next) { GPUStepping::ResumeFromStepping(); } -void SetBreakCount(int c) { - breakAtCount = c; +void SetBreakCount(int c, bool relative) { + if (relative) { + breakAtCount = primsThisFrame + c; + } else { + breakAtCount = c; + } } static bool IsBreakpoint(u32 pc, u32 op) { diff --git a/GPU/Debugger/Debugger.h b/GPU/Debugger/Debugger.h index b459f5a859..15be467cda 100644 --- a/GPU/Debugger/Debugger.h +++ b/GPU/Debugger/Debugger.h @@ -37,7 +37,7 @@ void SetActive(bool flag); bool IsActive(); void SetBreakNext(BreakNext next); -void SetBreakCount(int c); +void SetBreakCount(int c, bool relative = false); // While debugging is active, these may block. void NotifyCommand(u32 pc); diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index 8ff0223ecd..57f122694e 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -730,7 +730,13 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { std::string value; int count; if (InputBox_GetString(GetModuleHandle(NULL), m_hDlg, L"Prim count", "", value)) { - if (TryParse(value, &count)) { + if (value.length() > 1 && value[0] == '+' && TryParse(value.substr(1), &count)) { + SetBreakNext(BreakNext::COUNT); + SetBreakCount(count, true); + } else if (value.length() > 1 && value[0] == '-' && TryParse(value.substr(1), &count)) { + SetBreakNext(BreakNext::COUNT); + SetBreakCount(-count, true); + } else if (TryParse(value, &count)) { SetBreakNext(BreakNext::COUNT); SetBreakCount(count); } From c90ff6f59df7dc1af70fdd58fb07200ebf29e110 Mon Sep 17 00:00:00 2001 From: 6alileo <42245908+6alileo@users.noreply.github.com> Date: Sat, 1 Dec 2018 16:01:57 -0800 Subject: [PATCH 190/347] Madcatz Fightpad SFvTekken / Hori Mini Wired 4 --- UWP/Content/gamecontrollerdb.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/UWP/Content/gamecontrollerdb.txt b/UWP/Content/gamecontrollerdb.txt index 9c964ede61..6f6e6363b5 100644 --- a/UWP/Content/gamecontrollerdb.txt +++ b/UWP/Content/gamecontrollerdb.txt @@ -151,3 +151,5 @@ d814000000000000cecf000000000000,MC Cthulhu,platform:Mac OS X,leftx:,lefty:,righ 03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,y:b1,x:b0,leftstick:b8,rightstick:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b6,righttrigger:b7,platform:Linux, 030000006f0e00000103000000020000,Logic3 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, 05000000380700006652000025010000,Mad Catz C.T.R.L.R ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +03000000380700008532000010010000,MadCatz Madcatz Fightpad,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,lefttrigger:b5,righttrigger:b7, +030000000d0f0000ee00000011010000,HORI CO.,LTD. HORIPAD mini4,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, From d9cfa3a8fad12d6266b42622ef61e04055d81d9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 2 Dec 2018 21:49:20 +0100 Subject: [PATCH 191/347] Bump shader caches --- GPU/GLES/ShaderManagerGLES.cpp | 2 +- GPU/Vulkan/ShaderManagerVulkan.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 2a20129766..1c390a33b7 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -826,7 +826,7 @@ std::string ShaderManagerGLES::DebugGetShaderString(std::string id, DebugShaderT // as sometimes these features might have an effect on the ID bits. #define CACHE_HEADER_MAGIC 0x83277592 -#define CACHE_VERSION 12 +#define CACHE_VERSION 13 struct CacheHeader { uint32_t magic; uint32_t version; diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index ef0f7cf226..51a9f4a175 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -359,7 +359,7 @@ VulkanFragmentShader *ShaderManagerVulkan::GetFragmentShaderFromModule(VkShaderM // instantaneous. #define CACHE_HEADER_MAGIC 0xff51f420 -#define CACHE_VERSION 14 +#define CACHE_VERSION 15 struct VulkanCacheHeader { uint32_t magic; uint32_t version; From 482487dd8d561acd46742a053c0a4f3f2b799201 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 2 Dec 2018 14:02:46 -0800 Subject: [PATCH 192/347] GPU: Ignore light params for shade mapping. They aren't part of the equation, so this simplifies and slightly reduces number of shaders. --- GPU/Common/ShaderId.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index e7ed0b4e87..c8d602df82 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -60,7 +60,7 @@ std::string VertexShaderDesc(const ShaderID &id) { } void ComputeVertexShaderID(ShaderID *id_out, u32 vertType, bool useHWTransform) { - bool isModeThrough = gstate.isModeThrough(); + bool isModeThrough = (vertType & GE_VTYPE_THROUGH) != 0; bool doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear(); bool doTextureTransform = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX; bool doShadeMapping = doTexture && (gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP); @@ -72,6 +72,7 @@ void ComputeVertexShaderID(ShaderID *id_out, u32 vertType, bool useHWTransform) bool doBezier = gstate_c.bezier; bool doSpline = gstate_c.spline; + // These are the original vertType's values (normalized will always have colors, etc.) bool hasColorTess = (gstate.vertType & GE_VTYPE_COL_MASK) != 0 && (doBezier || doSpline); bool hasTexcoordTess = (gstate.vertType & GE_VTYPE_TC_MASK) != 0 && (doBezier || doSpline); bool hasNormalTess = (gstate.vertType & GE_VTYPE_NRM_MASK) != 0 && (doBezier || doSpline); @@ -115,18 +116,15 @@ void ComputeVertexShaderID(ShaderID *id_out, u32 vertType, bool useHWTransform) id.SetBits(VS_BIT_WEIGHT_FMTSCALE, 2, (vertType & GE_VTYPE_WEIGHT_MASK) >> GE_VTYPE_WEIGHT_SHIFT); } - // Okay, d[1] coming up. ============== - if (gstate.isLightingEnabled() || doShadeMapping) { - // doShadeMapping is stored as UVGenMode, so this is enough for isLightingEnabled. - if (gstate.isLightingEnabled()) { - id.SetBits(VS_BIT_MATERIAL_UPDATE, 3, gstate.getMaterialUpdate() & 7); - id.SetBit(VS_BIT_LIGHTING_ENABLE); - } + if (gstate.isLightingEnabled()) { + // doShadeMapping is stored as UVGenMode, and light type doesn't matter for shade mapping. + id.SetBits(VS_BIT_MATERIAL_UPDATE, 3, gstate.getMaterialUpdate() & 7); + id.SetBit(VS_BIT_LIGHTING_ENABLE); // Light bits for (int i = 0; i < 4; i++) { - bool chanEnabled = gstate.isLightChanEnabled(i) != 0 && gstate.isLightingEnabled(); + bool chanEnabled = gstate.isLightChanEnabled(i) != 0; id.SetBit(VS_BIT_LIGHT0_ENABLE + i, chanEnabled); - if (chanEnabled || (doShadeMapping && (gstate.getUVLS0() == i || gstate.getUVLS1() == i))) { + if (chanEnabled) { id.SetBits(VS_BIT_LIGHT0_COMP + 4 * i, 2, gstate.getLightComputation(i)); id.SetBits(VS_BIT_LIGHT0_TYPE + 4 * i, 2, gstate.getLightType(i)); } From 2bbe0d7e65d2400815ed1624392157c5a1ea8026 Mon Sep 17 00:00:00 2001 From: orbea Date: Sun, 2 Dec 2018 19:54:47 -0800 Subject: [PATCH 193/347] SDL: Allow toggling fullscreen for GLES2 on desktops. Fixes https://github.com/hrydgard/ppsspp/issues/11627 --- SDL/SDLMain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index 6dd6d2242b..db786c3f17 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -441,7 +441,7 @@ int main(int argc, char *argv[]) { } // If we're on mobile, don't try for windowed either. -#if defined(USING_GLES2) || defined(MOBILE_DEVICE) +#if defined(MOBILE_DEVICE) mode |= SDL_WINDOW_FULLSCREEN; #else mode |= SDL_WINDOW_RESIZABLE; From 828dcc26b7580288ac4c63de49b775fcb0e5632d Mon Sep 17 00:00:00 2001 From: orbea Date: Mon, 3 Dec 2018 18:04:13 -0800 Subject: [PATCH 194/347] cmake: Remove the unused RASPBIAN define. --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 479e3c09f1..79d0b260fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,7 +120,6 @@ option(X86_64 "Set to ON if targeting an X86_64 processor" ${X86_64}) option(USING_EGL "Set to ON if target environment uses EGL" ${USING_EGL}) option(USING_FBDEV "Set to ON if target environment uses fbdev (eg. Pandora)" ${USING_FBDEV}) option(USING_GLES2 "Set to ON if target device uses OpenGL ES 2.0" ${USING_GLES2}) -option(RASPBIAN "Set to ON to workaround threading issues when building for ARMV7 on Raspbian" ${RASPBIAN}) option(USING_X11_VULKAN "Set to OFF if target environment doesn't use X11 for Vulkan" ON) option(USE_WAYLAND_WSI "Enable or disable Wayland WSI support for Vulkan" ON) # :: Frontends From 9aed8908a241833a2267600d32a3c2837205fe8b Mon Sep 17 00:00:00 2001 From: orbea Date: Mon, 3 Dec 2018 18:35:48 -0800 Subject: [PATCH 195/347] cmake: Fix CMP0077 policy warnings. Fixes https://github.com/hrydgard/ppsspp/issues/11629 --- CMakeLists.txt | 51 +++++++++++++++++++------------------------------- 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 79d0b260fb..e27986c643 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,6 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules) add_definitions(-D__STDC_CONSTANT_MACROS) - if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") set(CLANG ON) message("Clang enabled") @@ -27,17 +26,17 @@ endif() # Detect CPU from CMAKE configuration. Toolchains should set this up if(CMAKE_SYSTEM_PROCESSOR) if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^arm") - set(ARM ON) - if(UNIX AND NOT APPLE) - execute_process(COMMAND cat /proc/cpuinfo OUTPUT_VARIABLE OUTSTR) - string(FIND "${OUTSTR}" "ODROID-XU" pos) - if(NOT (pos LESS 0)) - add_compile_options(-mfloat-abi=hard -marm -mtune=cortex-a15.cortex-a7 -mcpu=cortex-a15 -fomit-frame-pointer) - set(ARM_NO_VULKAN ON) - endif() + set(ARM_DEVICE ON) + if(UNIX AND NOT APPLE) + execute_process(COMMAND cat /proc/cpuinfo OUTPUT_VARIABLE OUTSTR) + string(FIND "${OUTSTR}" "ODROID-XU" pos) + if(NOT (pos LESS 0)) + add_compile_options(-mfloat-abi=hard -marm -mtune=cortex-a15.cortex-a7 -mcpu=cortex-a15 -fomit-frame-pointer) + set(ARM_NO_VULKAN ON) endif() + endif() if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^armv7") - set(ARMV7 ON) + set(ARMV7_DEVICE ON) add_compile_options(-mfpu=neon) # Horrifying workaround for bug in android cmake stuff for asm files if(ANDROID) @@ -48,12 +47,12 @@ if(CMAKE_SYSTEM_PROCESSOR) set(ARM64 ON) add_definitions(-DARM64) elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^amd64" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "^x86_64" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "^AMD64") - set(X86 ON) - set(X86_64 ON) + set(X86_DEVICE ON) + set(X86_64_DEVICE ON) elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^x86" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "i.86") - set(X86 ON) + set(X86_DEVICE ON) elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^mips") - set(MIPS ON) + set(MIPS_DEVICE ON) else() message("Unknown CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}") endif() @@ -61,9 +60,6 @@ endif() include(ccache) -# Remove soon? -set(USE_FFMPEG ON) - # the libraries in the ffmpeg/ directory are not compatible with mingw if(MINGW AND NOT DEFINED USE_SYSTEM_FFMPEG) set(USE_SYSTEM_FFMPEG ON) @@ -93,10 +89,6 @@ if(ANDROID OR WIN32 OR (UNIX AND NOT APPLE AND NOT ARM_NO_VULKAN)) set(VULKAN ON) endif() -if(NOT DEFINED HEADLESS) - set(HEADLESS OFF) -endif() - if(GOLD) add_definitions(-DGOLD) message("Gold Build") @@ -104,18 +96,13 @@ else() message("Normal Build") endif() -# Doesn't link on some platforms -#if(NOT DEFINED UNITTEST) -# set(UNITTEST OFF) -#endif() - # User-editable options (go into CMakeCache.txt) # :: Processors -option(ARMV7 "Set to ON if targeting an ARMv7 processor" ${ARMV7}) -option(ARM "Set to ON if targeting an ARM processor" ${ARM}) -option(MIPS "Set to ON if targeting a MIPS processor" ${MIPS}) -option(X86 "Set to ON if targeting an X86 processor" ${X86}) -option(X86_64 "Set to ON if targeting an X86_64 processor" ${X86_64}) +option(ARMV7 "Set to ON if targeting an ARMv7 processor" ${ARMV7_DEVICE}) +option(ARM "Set to ON if targeting an ARM processor" ${ARM_DEVICE}) +option(MIPS "Set to ON if targeting a MIPS processor" ${MIPS_DEVICE}) +option(X86 "Set to ON if targeting an X86 processor" ${X86_DEVICE}) +option(X86_64 "Set to ON if targeting an X86_64 processor" ${X86_64_DEVICE}) # :: Environments option(USING_EGL "Set to ON if target environment uses EGL" ${USING_EGL}) option(USING_FBDEV "Set to ON if target environment uses fbdev (eg. Pandora)" ${USING_FBDEV}) @@ -130,7 +117,7 @@ option(UNITTEST "Set to ON to generate the unittest target" ${UNITTEST}) option(SIMULATOR "Set to ON when targeting an x86 simulator of an ARM platform" ${SIMULATOR}) option(LIBRETRO "Set to ON to generate the libretro target" OFF) # :: Options -option(USE_FFMPEG "Build with FFMPEG support" ${USE_FFMPEG}) +option(USE_FFMPEG "Build with FFMPEG support" ON) option(USE_DISCORD "Build with Discord support" ON) option(USE_SYSTEM_SNAPPY "Dynamically link against system snappy" ${USE_SYSTEM_SNAPPY}) option(USE_SYSTEM_FFMPEG "Dynamically link against system FFMPEG" ${USE_SYSTEM_FFMPEG}) From 74d87fa2b4a3c943c1df09cc26a8c70b1335fd30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 4 Dec 2018 14:43:39 +0100 Subject: [PATCH 196/347] Update to 1.7.5, update lang --- README.md | 4 ++-- android/AndroidManifest.xml | 4 ++-- assets/lang | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e67efd66a2..1f7df22625 100644 --- a/README.md +++ b/README.md @@ -24,9 +24,9 @@ For build instructions and other development tutorials, see [the wiki](https://g For game compatibility, see [community compatibility feedback](https://report.ppsspp.org/games). -What's new in 1.7.3/1.7.4 +What's new in 1.7.3/1.7.4/1.7.5 ------------------- -* Attempted fixes for a couple of common crashes +* Fixes for a couple of common crashes * Reverted immersive mode change temporarily to see if it helps misaligned buttons * Change default adhoc server address diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index e118cf6ebc..c9e9cf2050 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -2,8 +2,8 @@ + android:versionCode="17050000" + android:versionName="1.7.5.0"> diff --git a/assets/lang b/assets/lang index a6c1c24e8d..7ea29e4e90 160000 --- a/assets/lang +++ b/assets/lang @@ -1 +1 @@ -Subproject commit a6c1c24e8dfe35afb56210fc46110dbf6fb6f593 +Subproject commit 7ea29e4e90e01b2eabd303236fa5872bf3706ae0 From 21bdc2b4c95030c2ce7b8608e2772b890da1b000 Mon Sep 17 00:00:00 2001 From: xebra Date: Thu, 6 Dec 2018 18:16:54 +0900 Subject: [PATCH 197/347] GE Debugger: Add step count dialog. --- Windows/GEDebugger/GEDebugger.cpp | 59 ++++++++++++++++++++++--------- Windows/GEDebugger/GEDebugger.h | 11 ++++++ Windows/ppsspp.rc | 12 +++++++ Windows/resource.h | 5 +++ 4 files changed, 70 insertions(+), 17 deletions(-) diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index 57f122694e..5bde53fa6f 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -57,13 +57,52 @@ enum PrimaryDisplayType { PRIMARY_STENCILBUF, }; +StepCountDlg::StepCountDlg(HINSTANCE _hInstance, HWND _hParent) : Dialog((LPCSTR)IDD_GEDBG_STEPCOUNT, _hInstance, _hParent) { + for (int i = 0; i < 4; i++) // Add items 1, 10, 100, 1000 + SendMessageA(GetDlgItem(m_hDlg, IDC_GEDBG_STEPCOUNT_COMBO), CB_ADDSTRING, 0, (LPARAM)std::to_string((int)pow(10, i)).c_str()); + SetWindowTextA(GetDlgItem(m_hDlg, IDC_GEDBG_STEPCOUNT_COMBO), "1"); +} + +void StepCountDlg::Jump(bool minus, bool relative) { + char str[5]; + int count; + GetWindowTextA(GetDlgItem(m_hDlg, IDC_GEDBG_STEPCOUNT_COMBO), str, 5); + if (TryParse(str, &count)) { + SetBreakNext(BreakNext::COUNT); + SetBreakCount(count * (minus ? -1 : 1), relative); + } +}; + +BOOL StepCountDlg::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { + switch (message) { + case WM_CLOSE: + Show(false); + return TRUE; + case WM_COMMAND: + switch (wParam) { + case IDC_GEDBG_STEPCOUNT_DEC: + Jump(true, true); + return TRUE; + case IDC_GEDBG_STEPCOUNT_INC: + Jump(false, true); + return TRUE; + case IDC_GEDBG_STEPCOUNT_JUMP: + Jump(false, false); + return TRUE; + } + default: + return FALSE; + } +} + void CGEDebugger::Init() { SimpleGLWindow::RegisterClass(); CtrlDisplayListView::registerClass(); } CGEDebugger::CGEDebugger(HINSTANCE _hInstance, HWND _hParent) - : Dialog((LPCSTR)IDD_GEDEBUGGER, _hInstance, _hParent) { + : Dialog((LPCSTR)IDD_GEDEBUGGER, _hInstance, _hParent) + , stepCountDlg(_hInstance, m_hDlg) { // minimum size = a little more than the default RECT windowRect; GetWindowRect(m_hDlg, &windowRect); @@ -658,6 +697,7 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { case WM_CLOSE: GPUDebug::SetActive(false); + stepCountDlg.Show(false); Show(false); return TRUE; @@ -726,22 +766,7 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { break; case IDC_GEDBG_STEPCOUNT: - { - std::string value; - int count; - if (InputBox_GetString(GetModuleHandle(NULL), m_hDlg, L"Prim count", "", value)) { - if (value.length() > 1 && value[0] == '+' && TryParse(value.substr(1), &count)) { - SetBreakNext(BreakNext::COUNT); - SetBreakCount(count, true); - } else if (value.length() > 1 && value[0] == '-' && TryParse(value.substr(1), &count)) { - SetBreakNext(BreakNext::COUNT); - SetBreakCount(-count, true); - } else if (TryParse(value, &count)) { - SetBreakNext(BreakNext::COUNT); - SetBreakCount(count); - } - } - } + stepCountDlg.Show(true); break; case IDC_GEDBG_BREAKTEX: diff --git a/Windows/GEDebugger/GEDebugger.h b/Windows/GEDebugger/GEDebugger.h index 79db21dc1b..a11de7267e 100644 --- a/Windows/GEDebugger/GEDebugger.h +++ b/Windows/GEDebugger/GEDebugger.h @@ -44,6 +44,15 @@ class TabMatrices; class TabStateWatch; struct GPUgstate; +class StepCountDlg : public Dialog { +public: + StepCountDlg(HINSTANCE _hInstance, HWND _hParent); +protected: + BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); +private: + void Jump(bool minus, bool relative); +}; + class CGEDebugger : public Dialog { public: CGEDebugger(HINSTANCE _hInstance, HWND _hParent); @@ -100,4 +109,6 @@ private: int previewsEnabled_ = 3; int minWidth_; int minHeight_; + + StepCountDlg stepCountDlg; }; diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index 195f92eb05..144a50db06 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -234,6 +234,18 @@ BEGIN PUSHBUTTON "Break on Target...",IDC_GEDBG_BREAKTARGET,394,211,100,14 END +IDD_GEDBG_STEPCOUNT DIALOGEX 0, 0, 124, 18 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_TOOLWINDOW +CAPTION "Step Count" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + COMBOBOX IDC_GEDBG_STEPCOUNT_COMBO,6,3,50,13,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP | ES_NUMBER + PUSHBUTTON "-",IDC_GEDBG_STEPCOUNT_DEC,58,2,14,14 + PUSHBUTTON "+",IDC_GEDBG_STEPCOUNT_INC,73,2,14,14 + PUSHBUTTON "Jump",IDC_GEDBG_STEPCOUNT_JUMP,88,2,30,14 +END + IDD_GEDBG_TAB_VALUES DIALOGEX 0, 0, 316, 183 STYLE DS_SETFONT | WS_CHILD | DS_CONTROL diff --git a/Windows/resource.h b/Windows/resource.h index ee64c5759f..1f701e442e 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -81,6 +81,7 @@ #define IDD_DUMPMEMORY 253 #define IDD_GEDBG_TAB_VERTICES 254 #define IDD_GEDBG_TAB_MATRICES 255 +#define IDD_GEDBG_STEPCOUNT 256 #define IDC_STOPGO 1001 #define IDC_ADDRESS 1002 @@ -364,6 +365,10 @@ #define ID_OPTIONS_SCREENFILTER_MENU 40197 #define ID_OPTIONS_TEXTURESCALING_MENU 40198 #define IDC_GEDBG_STEPCOUNT 40199 +#define IDC_GEDBG_STEPCOUNT_DEC 40200 +#define IDC_GEDBG_STEPCOUNT_INC 40201 +#define IDC_GEDBG_STEPCOUNT_JUMP 40202 +#define IDC_GEDBG_STEPCOUNT_COMBO 40203 // Dummy option to let the buffered rendering hotkey cycle through all the options. #define ID_OPTIONS_BUFFEREDRENDERINGDUMMY 40500 From 070e29d921845fe324baa4f9c403df0898c2d1ca Mon Sep 17 00:00:00 2001 From: xebra Date: Fri, 7 Dec 2018 13:01:16 +0900 Subject: [PATCH 198/347] Disable "Edit & Continue" with VS debug mode. --- Common/Common.vcxproj | 2 ++ Core/Core.vcxproj | 2 ++ GPU/GPU.vcxproj | 2 ++ UI/UI.vcxproj | 2 ++ Windows/PPSSPP.vcxproj | 4 +++- ext/SPIRV-Cross.vcxproj | 2 ++ ext/discord-rpc-build/discord-rpc.vcxproj | 4 +++- ext/glslang.vcxproj | 2 ++ ext/libarmips.vcxproj | 2 ++ ext/libkirk/libkirk.vcxproj | 2 ++ ext/native/native.vcxproj | 2 ++ ext/zlib/zlib.vcxproj | 7 +++++-- headless/Headless.vcxproj | 2 ++ unittest/UnitTests.vcxproj | 2 ++ 14 files changed, 33 insertions(+), 4 deletions(-) diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index 1c378870d1..cf033d00ea 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -80,6 +80,7 @@ true false false + ProgramDatabase Windows @@ -107,6 +108,7 @@ true false false + ProgramDatabase Windows diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index c5a39b54be..34d117cf66 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -79,6 +79,7 @@ false MultiThreadedDebug Common/DbgNew.h + ProgramDatabase true @@ -101,6 +102,7 @@ false MultiThreadedDebug Common/DbgNew.h + ProgramDatabase true diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index b531442bb8..c3f2a1aa10 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -94,6 +94,7 @@ false MultiThreadedDebug Common/DbgNew.h + ProgramDatabase true @@ -116,6 +117,7 @@ _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_64=1;_M_X64=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) MultiThreadedDebug Common/DbgNew.h + ProgramDatabase true diff --git a/UI/UI.vcxproj b/UI/UI.vcxproj index 4d1650482b..f0bec7d79b 100644 --- a/UI/UI.vcxproj +++ b/UI/UI.vcxproj @@ -149,6 +149,7 @@ MultiThreadedDebug Common/DbgNew.h $(EXTERNAL_COMPILE_OPTIONS) + ProgramDatabase Windows @@ -173,6 +174,7 @@ false Common/DbgNew.h $(EXTERNAL_COMPILE_OPTIONS) + ProgramDatabase Windows diff --git a/Windows/PPSSPP.vcxproj b/Windows/PPSSPP.vcxproj index a4efbe1117..9945c91e62 100644 --- a/Windows/PPSSPP.vcxproj +++ b/Windows/PPSSPP.vcxproj @@ -1,4 +1,4 @@ - + @@ -125,6 +125,7 @@ Sync Use Level3 + ProgramDatabase ../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib stdafx.h;Common/DbgNew.h MultiThreadedDebug @@ -161,6 +162,7 @@ Sync Use Level3 + ProgramDatabase ../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib stdafx.h;Common/DbgNew.h MultiThreadedDebug diff --git a/ext/SPIRV-Cross.vcxproj b/ext/SPIRV-Cross.vcxproj index a3dc1386f3..3e1003593c 100644 --- a/ext/SPIRV-Cross.vcxproj +++ b/ext/SPIRV-Cross.vcxproj @@ -94,6 +94,7 @@ false MultiThreadedDebug true + ProgramDatabase Windows @@ -109,6 +110,7 @@ false MultiThreadedDebug true + ProgramDatabase Windows diff --git a/ext/discord-rpc-build/discord-rpc.vcxproj b/ext/discord-rpc-build/discord-rpc.vcxproj index 771c6e4f7d..0ef8d3d62a 100644 --- a/ext/discord-rpc-build/discord-rpc.vcxproj +++ b/ext/discord-rpc-build/discord-rpc.vcxproj @@ -1,4 +1,4 @@ - + @@ -129,6 +129,7 @@ ..\discord-rpc\include;..\discord-rpc\src;..\rapidjson\include MultiThreadedDebug true + ProgramDatabase Windows @@ -144,6 +145,7 @@ ..\discord-rpc\include;..\discord-rpc\src;..\rapidjson\include MultiThreadedDebug true + ProgramDatabase Windows diff --git a/ext/glslang.vcxproj b/ext/glslang.vcxproj index 95eb3ab485..abc83b6c34 100644 --- a/ext/glslang.vcxproj +++ b/ext/glslang.vcxproj @@ -80,6 +80,7 @@ Default glslang/glslang/OSDependent/Windows;glslang/glslang/MachineIndependent true + ProgramDatabase Windows @@ -98,6 +99,7 @@ false Default true + ProgramDatabase Windows diff --git a/ext/libarmips.vcxproj b/ext/libarmips.vcxproj index 4662b65ba3..411af13881 100644 --- a/ext/libarmips.vcxproj +++ b/ext/libarmips.vcxproj @@ -139,6 +139,7 @@ true + ProgramDatabase Windows @@ -159,6 +160,7 @@ true + ProgramDatabase Windows diff --git a/ext/libkirk/libkirk.vcxproj b/ext/libkirk/libkirk.vcxproj index 86f944aea9..bdaa0b01c3 100644 --- a/ext/libkirk/libkirk.vcxproj +++ b/ext/libkirk/libkirk.vcxproj @@ -77,6 +77,7 @@ false MultiThreadedDebug ../../Common/DbgNew.h + ProgramDatabase true @@ -92,6 +93,7 @@ false ../../Common/DbgNew.h _CRTDBG_MAP_ALLOC;_USING_V110_SDK71_;%(PreprocessorDefinitions) + ProgramDatabase true diff --git a/ext/native/native.vcxproj b/ext/native/native.vcxproj index 21b09ed6d7..405888b732 100644 --- a/ext/native/native.vcxproj +++ b/ext/native/native.vcxproj @@ -87,6 +87,7 @@ false MultiThreadedDebug ../../Common/DbgNew.h + ProgramDatabase Windows @@ -109,6 +110,7 @@ MultiThreadedDebug false ../../Common/DbgNew.h + ProgramDatabase Windows diff --git a/ext/zlib/zlib.vcxproj b/ext/zlib/zlib.vcxproj index cc73897541..81d64dcaae 100644 --- a/ext/zlib/zlib.vcxproj +++ b/ext/zlib/zlib.vcxproj @@ -52,7 +52,8 @@ {F761046E-6C38-4428-A5F1-38391A37BB34} Win32Proj zlib - + + @@ -111,6 +112,7 @@ false MultiThreadedDebug ../../Common/DbgNew.h + ProgramDatabase Windows @@ -132,6 +134,7 @@ false MultiThreadedDebug ../../Common/DbgNew.h + ProgramDatabase Windows @@ -193,4 +196,4 @@ - + \ No newline at end of file diff --git a/headless/Headless.vcxproj b/headless/Headless.vcxproj index e4412a822c..5be939c78c 100644 --- a/headless/Headless.vcxproj +++ b/headless/Headless.vcxproj @@ -102,6 +102,7 @@ false MultiThreadedDebug Common/DbgNew.h + ProgramDatabase Console @@ -133,6 +134,7 @@ false MultiThreadedDebug Common/DbgNew.h + ProgramDatabase Console diff --git a/unittest/UnitTests.vcxproj b/unittest/UnitTests.vcxproj index 38b7be99b3..fa377805f9 100644 --- a/unittest/UnitTests.vcxproj +++ b/unittest/UnitTests.vcxproj @@ -96,6 +96,7 @@ false MultiThreadedDebug Common/DbgNew.h + ProgramDatabase Console @@ -118,6 +119,7 @@ MultiThreadedDebug false Common/DbgNew.h + ProgramDatabase Console From c17a211320d3b92b1326ab2af44dc900d90023d6 Mon Sep 17 00:00:00 2001 From: Abbanon <37251822+Abbanon@users.noreply.github.com> Date: Sun, 9 Dec 2018 08:29:58 -0500 Subject: [PATCH 199/347] Attempt to improve Discord Rich Presence --- UI/DiscordIntegration.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/UI/DiscordIntegration.cpp b/UI/DiscordIntegration.cpp index 34fc4d00b5..101c930a79 100644 --- a/UI/DiscordIntegration.cpp +++ b/UI/DiscordIntegration.cpp @@ -102,6 +102,7 @@ void Discord::SetPresenceGame(const char *gameTitle) { std::string details = sc->T("Playing"); discordPresence.details = details.c_str(); discordPresence.startTimestamp = time(0); + discordPresence.largeImageText = "PPSSPP is the best PlayStation Portable emulator around!"; #ifdef GOLD discordPresence.largeImageKey = "icon_gold_png"; #else @@ -126,6 +127,7 @@ void Discord::SetPresenceMenu() { discordPresence.state = sc->T("In menu"); discordPresence.details = ""; discordPresence.startTimestamp = time(0); + discordPresence.largeImageText = "PPSSPP is the best PlayStation Portable emulator around!"; #ifdef GOLD discordPresence.largeImageKey = "icon_gold_png"; #else From 46f11fbfed0b06a72b5a146bda6a9aa4aa56739f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 26 Nov 2018 22:38:10 +0100 Subject: [PATCH 200/347] Just make the optimized (non-release) android build debuggable. --- android/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/android/build.gradle b/android/build.gradle index 93aeaaf75b..a42f360633 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -70,6 +70,7 @@ android { optimized { // Debug signed but optimized. minifyEnabled = false + jniDebuggable true signingConfig android.buildTypes.debug.signingConfig } release { From 4a53853f799071ca438daca6d7cb0b256aa8a47c Mon Sep 17 00:00:00 2001 From: pent0 Date: Mon, 10 Dec 2018 20:55:07 +0700 Subject: [PATCH 201/347] Update UWP port --- Common/FileUtil.cpp | 5 + Core/Debugger/WebSocket/WebSocketUtils.h | 7 + Core/MIPS/ARM/ArmJit.cpp | 2 +- UI/DiscordIntegration.cpp | 2 +- UWP/Armips_UWP/Armips_UWP.vcxproj | 306 ++++++++++++++ UWP/Armips_UWP/Armips_UWP.vcxproj.filters | 317 ++++++++++++++ UWP/Armips_UWP/pch.cpp | 1 + UWP/Armips_UWP/pch.h | 9 + UWP/Armips_UWP/targetver.h | 8 + UWP/CommonUWP/CommonUWP.vcxproj | 4 +- UWP/CoreUWP/CoreUWP.vcxproj | 32 +- UWP/CoreUWP/CoreUWP.vcxproj.filters | 89 ++++ UWP/FastMath_UWP/FastMath_UWP.cpp | 2 + UWP/GPU_UWP/GPU_UWP.vcxproj | 4 +- UWP/GPU_UWP/GPU_UWP.vcxproj.filters | 395 +++++------------- UWP/NativeUWP/NativeUWP.vcxproj | 20 +- UWP/NativeUWP/NativeUWP.vcxproj.filters | 43 ++ UWP/PPSSPP_UWP.sln | 64 ++- UWP/PPSSPP_UWPMain.cpp | 6 +- UWP/SPIRVCross_UWP/SPIRVCross_UWP.vcxproj | 15 +- .../SPIRVCross_UWP.vcxproj.filters | 2 + UWP/UI_UWP/UI_UWP.vcxproj | 6 +- UWP/UWP.vcxproj | 11 +- UWP/UWPHost.cpp | 1 - UWP/XAudioSoundStream.h | 3 +- UWP/glslang_UWP/glslang_UWP.vcxproj | 6 +- UWP/glslang_UWP/glslang_UWP.vcxproj.filters | 6 + UWP/libkirk_UWP/libkirk_UWP.vcxproj | 4 +- UWP/zlib_UWP/zlib_UWP.vcxproj | 4 +- ext/native/math/fast/fast_math.c | 2 + ext/native/net/http_server.cpp | 5 + 31 files changed, 1048 insertions(+), 333 deletions(-) create mode 100644 UWP/Armips_UWP/Armips_UWP.vcxproj create mode 100644 UWP/Armips_UWP/Armips_UWP.vcxproj.filters create mode 100644 UWP/Armips_UWP/pch.cpp create mode 100644 UWP/Armips_UWP/pch.h create mode 100644 UWP/Armips_UWP/targetver.h create mode 100644 UWP/FastMath_UWP/FastMath_UWP.cpp diff --git a/Common/FileUtil.cpp b/Common/FileUtil.cpp index e8dbc62091..2c699e3581 100644 --- a/Common/FileUtil.cpp +++ b/Common/FileUtil.cpp @@ -30,6 +30,7 @@ #ifdef _WIN32 #include "CommonWindows.h" +#include #include // for SHGetFolderPath #include #include // for GetSaveFileName @@ -121,7 +122,11 @@ std::string ResolvePath(const std::string &path) { std::wstring input = ConvertUTF8ToWString(path); if (getFinalPathNameByHandleW) { +#if PPSSPP_PLATFORM(UWP) + HANDLE hFile = CreateFile2(input.c_str(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr); +#else HANDLE hFile = CreateFile(input.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); +#endif if (hFile == INVALID_HANDLE_VALUE) { wcscpy_s(buf, BUF_SIZE - 1, input.c_str()); } else { diff --git a/Core/Debugger/WebSocket/WebSocketUtils.h b/Core/Debugger/WebSocket/WebSocketUtils.h index 85dca3f4a8..0bb6b88760 100644 --- a/Core/Debugger/WebSocket/WebSocketUtils.h +++ b/Core/Debugger/WebSocket/WebSocketUtils.h @@ -24,6 +24,13 @@ #include "net/websocket_server.h" #include "Common/Log.h" +#include "ppsspp_config.h" + +#ifdef PPSSPP_PLATFORM(UWP) +// Enum name overlapped with UWP macro, quick hack to disable it +#undef OPTIONAL +#endif + using namespace json; static inline void DebuggerJsonAddTicket(JsonWriter &writer, const JsonGet &data) { diff --git a/Core/MIPS/ARM/ArmJit.cpp b/Core/MIPS/ARM/ArmJit.cpp index 87bb801087..b41707f285 100644 --- a/Core/MIPS/ARM/ArmJit.cpp +++ b/Core/MIPS/ARM/ArmJit.cpp @@ -46,7 +46,7 @@ using namespace ArmJitConstants; -static void DisassembleArm(const u8 *data, int size) { +void DisassembleArm(const u8 *data, int size) { char temp[256]; for (int i = 0; i < size; i += 4) { const u32 *codePtr = (const u32 *)(data + i); diff --git a/UI/DiscordIntegration.cpp b/UI/DiscordIntegration.cpp index 34fc4d00b5..6842a748cd 100644 --- a/UI/DiscordIntegration.cpp +++ b/UI/DiscordIntegration.cpp @@ -7,7 +7,7 @@ #include "DiscordIntegration.h" #include "i18n/i18n.h" -#if (PPSSPP_PLATFORM(WINDOWS) || PPSSPP_PLATFORM(MAC) || PPSSPP_PLATFORM(LINUX)) && !PPSSPP_PLATFORM(ANDROID) +#if (PPSSPP_PLATFORM(WINDOWS) || PPSSPP_PLATFORM(MAC) || PPSSPP_PLATFORM(LINUX)) && !PPSSPP_PLATFORM(ANDROID) && !PPSSPP_PLATFORM(UWP) #ifdef _MSC_VER #define ENABLE_DISCORD diff --git a/UWP/Armips_UWP/Armips_UWP.vcxproj b/UWP/Armips_UWP/Armips_UWP.vcxproj new file mode 100644 index 0000000000..64e73e0af4 --- /dev/null +++ b/UWP/Armips_UWP/Armips_UWP.vcxproj @@ -0,0 +1,306 @@ + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + {75286959-e7a2-4cbe-8b95-bf05c9c540ff} + StaticLibrary + Armips_UWP + en-US + 14.0 + true + Windows Store + 10.0.17763.0 + 10.0.15063.0 + 10.0 + + + + StaticLibrary + true + v141 + + + StaticLibrary + true + v141 + + + StaticLibrary + true + v141 + + + StaticLibrary + false + true + v141 + + + StaticLibrary + false + true + v141 + + + StaticLibrary + false + true + v141 + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + false + + + false + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips + + + false + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips + + + false + + + false + + + + Use + false + true + + + Console + false + false + + + + + Use + false + true + + + Console + false + false + + + + + NotUsing + false + true + + + Console + false + false + + + + + NotUsing + false + true + + + Console + false + false + + + + + Use + false + true + + + Console + false + false + + + + + Use + false + true + + + Console + false + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + Create + Create + Create + Create + + + + + + \ No newline at end of file diff --git a/UWP/Armips_UWP/Armips_UWP.vcxproj.filters b/UWP/Armips_UWP/Armips_UWP.vcxproj.filters new file mode 100644 index 0000000000..463cc812fe --- /dev/null +++ b/UWP/Armips_UWP/Armips_UWP.vcxproj.filters @@ -0,0 +1,317 @@ + + + + + + Archs\ARM + + + Archs\ARM + + + Archs\ARM + + + Archs\ARM + + + Archs\ARM + + + Archs\ARM + + + Archs\ARM + + + Archs\ARM + + + Archs\ARM + + + Archs\MIPS + + + Archs\MIPS + + + Archs\MIPS + + + Archs\MIPS + + + Archs\MIPS + + + Archs\MIPS + + + Archs\MIPS + + + Archs\MIPS + + + Archs\MIPS + + + Archs + + + Core\ELF + + + Core\ELF + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Commands + + + Commands + + + Commands + + + Commands + + + Commands + + + Commands + + + Commands + + + Commands + + + Parser + + + Parser + + + Parser + + + Parser + + + Util + + + Util + + + Util + + + Util + + + Util + + + + + + + + Archs\ARM + + + Archs\ARM + + + Archs\ARM + + + Archs\ARM + + + Archs\ARM + + + Archs\ARM + + + Archs\ARM + + + Archs\ARM + + + Archs\ARM + + + Archs\MIPS + + + Archs\MIPS + + + Archs\MIPS + + + Archs\MIPS + + + Archs\MIPS + + + Archs\MIPS + + + Archs\MIPS + + + Archs\MIPS + + + Archs\MIPS + + + Archs + + + Core\ELF + + + Core\ELF + + + Core\ELF + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Commands + + + Commands + + + Commands + + + Commands + + + Commands + + + Commands + + + Commands + + + Commands + + + Parser + + + Parser + + + Parser + + + Parser + + + Util + + + Util + + + Util + + + Util + + + Util + + + + + + {bb50e347-768c-4786-84ed-552556adbe31} + + + {1b78b12e-91fd-4345-977d-a834b2aaaa0e} + + + {bef7b4a2-b049-4d00-810c-6d8d6605c2a3} + + + {2ce1016b-f93c-48b9-abe5-d3fbbcd24780} + + + {350e6968-15a4-41a0-8db6-0c0c4167ece2} + + + {1f209da4-5400-4997-bcd1-729c3e8efc7a} + + + {51922c53-0a94-4ccf-bc91-01c49e1ab80a} + + + {019ffa9d-12b6-420e-9af3-2c02795d73c8} + + + \ No newline at end of file diff --git a/UWP/Armips_UWP/pch.cpp b/UWP/Armips_UWP/pch.cpp new file mode 100644 index 0000000000..bcb5590be1 --- /dev/null +++ b/UWP/Armips_UWP/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/UWP/Armips_UWP/pch.h b/UWP/Armips_UWP/pch.h new file mode 100644 index 0000000000..529bbb17fe --- /dev/null +++ b/UWP/Armips_UWP/pch.h @@ -0,0 +1,9 @@ +#pragma once + +#include "targetver.h" + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#include diff --git a/UWP/Armips_UWP/targetver.h b/UWP/Armips_UWP/targetver.h new file mode 100644 index 0000000000..a66ecb00f1 --- /dev/null +++ b/UWP/Armips_UWP/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include diff --git a/UWP/CommonUWP/CommonUWP.vcxproj b/UWP/CommonUWP/CommonUWP.vcxproj index ac94b54c2e..6696b15898 100644 --- a/UWP/CommonUWP/CommonUWP.vcxproj +++ b/UWP/CommonUWP/CommonUWP.vcxproj @@ -46,9 +46,9 @@ 14.0 true Windows Store - 10.0.14393.0 + 10.0.15063.0 10.0 - 10.0.16299.0 + 10.0.17763.0 diff --git a/UWP/CoreUWP/CoreUWP.vcxproj b/UWP/CoreUWP/CoreUWP.vcxproj index 7cd70cfa70..22101489c7 100644 --- a/UWP/CoreUWP/CoreUWP.vcxproj +++ b/UWP/CoreUWP/CoreUWP.vcxproj @@ -46,9 +46,9 @@ 14.0 true Windows Store - 10.0.14393.0 + 10.0.15063.0 10.0 - 10.0.16299.0 + 10.0.17763.0 @@ -310,6 +310,19 @@ + + + + + + + + + + + + + @@ -405,6 +418,7 @@ + @@ -506,6 +520,19 @@ + + + + + + + + + + + + + @@ -599,6 +626,7 @@ + diff --git a/UWP/CoreUWP/CoreUWP.vcxproj.filters b/UWP/CoreUWP/CoreUWP.vcxproj.filters index d0efa332ed..9366bca1a1 100644 --- a/UWP/CoreUWP/CoreUWP.vcxproj.filters +++ b/UWP/CoreUWP/CoreUWP.vcxproj.filters @@ -65,6 +65,9 @@ {9c6552c2-9858-41da-a920-31ea5628d417} + + {2c71417c-cc7b-42cb-880d-ac0cb45ab5bb} + @@ -621,6 +624,49 @@ HLE + + + HLE + + + Debugger + + + Debugger\WebSocket + + + Debugger\WebSocket + + + Debugger\WebSocket + + + Debugger\WebSocket + + + Debugger\WebSocket + + + Debugger\WebSocket + + + Debugger\WebSocket + + + Debugger\WebSocket + + + Debugger\WebSocket + + + Debugger\WebSocket + + + Debugger\WebSocket + + + Debugger\WebSocket + @@ -1160,5 +1206,48 @@ HLE + + + HLE + + + Debugger + + + Debugger\WebSocket + + + Debugger\WebSocket + + + Debugger\WebSocket + + + Debugger\WebSocket + + + Debugger\WebSocket + + + Debugger\WebSocket + + + Debugger\WebSocket + + + Debugger\WebSocket + + + Debugger\WebSocket + + + Debugger\WebSocket + + + Debugger\WebSocket + + + Debugger\WebSocket + \ No newline at end of file diff --git a/UWP/FastMath_UWP/FastMath_UWP.cpp b/UWP/FastMath_UWP/FastMath_UWP.cpp new file mode 100644 index 0000000000..aca0e62da6 --- /dev/null +++ b/UWP/FastMath_UWP/FastMath_UWP.cpp @@ -0,0 +1,2 @@ +#include "pch.h" +#include "FastMath_UWP.h" diff --git a/UWP/GPU_UWP/GPU_UWP.vcxproj b/UWP/GPU_UWP/GPU_UWP.vcxproj index f3cfa762bf..5f674f79b2 100644 --- a/UWP/GPU_UWP/GPU_UWP.vcxproj +++ b/UWP/GPU_UWP/GPU_UWP.vcxproj @@ -46,9 +46,9 @@ 14.0 true Windows Store - 10.0.14393.0 + 10.0.15063.0 10.0 - 10.0.16299.0 + 10.0.17763.0 diff --git a/UWP/GPU_UWP/GPU_UWP.vcxproj.filters b/UWP/GPU_UWP/GPU_UWP.vcxproj.filters index 6108deb70b..5f71cb0d67 100644 --- a/UWP/GPU_UWP/GPU_UWP.vcxproj.filters +++ b/UWP/GPU_UWP/GPU_UWP.vcxproj.filters @@ -1,315 +1,114 @@  - + - - {73b2cfa4-f51e-48f5-a9fd-2c4df203a4f0} - - - {7634891c-a60e-48d4-abdb-d8fe347dfef5} - - - {508714cf-18c6-4a82-b92d-1527d9a100f0} - - - {15dc3187-4c49-46a7-8027-6ff23564cc22} - - - {b5c82a80-e146-4133-b199-a07a427f04cc} - - - - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - D3D11 - - - D3D11 - - - D3D11 - - - D3D11 - - - D3D11 - - - D3D11 - - - D3D11 - - - D3D11 - - - D3D11 - - - D3D11 - - - D3D11 - - - D3D11 - - - D3D9 - - - D3D9 - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - Software - - - Software - - - Software - - - Software - - - Software - - - Debugger - - - Debugger - - - Debugger - - - Common - - - Software - - - Debugger - - - Common - + + + + + + + - - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - D3D11 - - - D3D11 - - - D3D11 - - - D3D11 - - - D3D11 - - - D3D11 - - - D3D11 - - - D3D11 - - - D3D11 - - - D3D11 - - - D3D11 - - - D3D9 - - - D3D9 - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - Software - - - Software - - - Software - - - Software - - - Software - - - Debugger - - - Debugger - - - Debugger - - - Software - - - Debugger - - - Common - + + + + + + + + \ No newline at end of file diff --git a/UWP/NativeUWP/NativeUWP.vcxproj b/UWP/NativeUWP/NativeUWP.vcxproj index da5942bbfb..94d9984e97 100644 --- a/UWP/NativeUWP/NativeUWP.vcxproj +++ b/UWP/NativeUWP/NativeUWP.vcxproj @@ -46,9 +46,9 @@ 14.0 true Windows Store - 10.0.14393.0 + 10.0.15063.0 10.0 - 10.0.16299.0 + 10.0.17763.0 @@ -215,7 +215,7 @@ true pch.h ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) + NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;_CRT_SECURE_NO_WARNINGS;%(ClCompile.PreprocessorDefinitions) Console @@ -230,7 +230,7 @@ true pch.h ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) + NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;_CRT_SECURE_NO_WARNINGS;%(ClCompile.PreprocessorDefinitions) Console @@ -245,7 +245,7 @@ true pch.h ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) + NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;_CRT_SECURE_NO_WARNINGS;%(ClCompile.PreprocessorDefinitions) Console @@ -312,10 +312,12 @@ + + @@ -328,6 +330,8 @@ + + @@ -366,6 +370,7 @@ + @@ -397,8 +402,10 @@ + + @@ -1160,6 +1167,8 @@ NotUsing NotUsing + + @@ -1279,6 +1288,7 @@ + diff --git a/UWP/NativeUWP/NativeUWP.vcxproj.filters b/UWP/NativeUWP/NativeUWP.vcxproj.filters index ce9603f332..2d641216cd 100644 --- a/UWP/NativeUWP/NativeUWP.vcxproj.filters +++ b/UWP/NativeUWP/NativeUWP.vcxproj.filters @@ -55,6 +55,15 @@ {4d23e7d3-0b9b-4dbe-95df-6ab250782a66} + + {fb517d8e-e6c4-4eaf-a579-9970daa96541} + + + {6c81d960-607b-4da7-b114-a6c57dff4360} + + + {b68fe6a0-b55f-4411-91f4-63ab1eaf47a3} + @@ -448,6 +457,23 @@ math + + + + ext\gason + + + ext\rg_etc1 + + + ext\sha1 + + + net + + + data + @@ -707,5 +733,22 @@ data + + + + ext\gason + + + ext\rg_etc1 + + + ext\sha1 + + + net + + + data + \ No newline at end of file diff --git a/UWP/PPSSPP_UWP.sln b/UWP/PPSSPP_UWP.sln index 1b251ca1c7..b68bce01d5 100644 --- a/UWP/PPSSPP_UWP.sln +++ b/UWP/PPSSPP_UWP.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.136 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CommonUWP", "CommonUWP\CommonUWP.vcxproj", "{ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}" EndProject @@ -22,141 +22,167 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glslang_UWP", "glslang_UWP\ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SPIRVCross_UWP", "SPIRVCross_UWP\SPIRVCross_UWP.vcxproj", "{2B2D16BD-1D37-46AF-A3F8-552900951B26}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Armips_UWP", "Armips_UWP\Armips_UWP.vcxproj", "{75286959-E7A2-4CBE-8B95-BF05C9C540FF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM + Debug|ARM64 = Debug|ARM64 Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 Release|ARM = Release|ARM + Release|ARM64 = Release|ARM64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 UWP Gold|ARM = UWP Gold|ARM + UWP Gold|ARM64 = UWP Gold|ARM64 UWP Gold|Win32 = UWP Gold|Win32 UWP Gold|x64 = UWP Gold|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}.Debug|ARM.ActiveCfg = Debug|ARM {ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}.Debug|ARM.Build.0 = Debug|ARM + {ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}.Debug|ARM64.ActiveCfg = Debug|Win32 {ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}.Debug|Win32.ActiveCfg = Debug|Win32 {ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}.Debug|Win32.Build.0 = Debug|Win32 {ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}.Debug|x64.ActiveCfg = Debug|x64 {ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}.Debug|x64.Build.0 = Debug|x64 {ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}.Release|ARM.ActiveCfg = Release|ARM {ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}.Release|ARM.Build.0 = Release|ARM + {ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}.Release|ARM64.ActiveCfg = Release|Win32 {ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}.Release|Win32.ActiveCfg = Release|Win32 {ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}.Release|Win32.Build.0 = Release|Win32 {ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}.Release|x64.ActiveCfg = Release|x64 {ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}.Release|x64.Build.0 = Release|x64 {ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}.UWP Gold|ARM.ActiveCfg = UWP Gold|ARM {ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}.UWP Gold|ARM.Build.0 = UWP Gold|ARM + {ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}.UWP Gold|ARM64.ActiveCfg = UWP Gold|Win32 {ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}.UWP Gold|Win32.ActiveCfg = UWP Gold|Win32 {ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}.UWP Gold|Win32.Build.0 = UWP Gold|Win32 {ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}.UWP Gold|x64.ActiveCfg = UWP Gold|x64 {ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}.UWP Gold|x64.Build.0 = UWP Gold|x64 {40B76674-02DE-40EF-889B-FAD1489685E7}.Debug|ARM.ActiveCfg = Debug|ARM {40B76674-02DE-40EF-889B-FAD1489685E7}.Debug|ARM.Build.0 = Debug|ARM + {40B76674-02DE-40EF-889B-FAD1489685E7}.Debug|ARM64.ActiveCfg = Debug|Win32 {40B76674-02DE-40EF-889B-FAD1489685E7}.Debug|Win32.ActiveCfg = Debug|Win32 {40B76674-02DE-40EF-889B-FAD1489685E7}.Debug|Win32.Build.0 = Debug|Win32 {40B76674-02DE-40EF-889B-FAD1489685E7}.Debug|x64.ActiveCfg = Debug|x64 {40B76674-02DE-40EF-889B-FAD1489685E7}.Debug|x64.Build.0 = Debug|x64 {40B76674-02DE-40EF-889B-FAD1489685E7}.Release|ARM.ActiveCfg = Release|ARM {40B76674-02DE-40EF-889B-FAD1489685E7}.Release|ARM.Build.0 = Release|ARM + {40B76674-02DE-40EF-889B-FAD1489685E7}.Release|ARM64.ActiveCfg = Release|Win32 {40B76674-02DE-40EF-889B-FAD1489685E7}.Release|Win32.ActiveCfg = Release|Win32 {40B76674-02DE-40EF-889B-FAD1489685E7}.Release|Win32.Build.0 = Release|Win32 {40B76674-02DE-40EF-889B-FAD1489685E7}.Release|x64.ActiveCfg = Release|x64 {40B76674-02DE-40EF-889B-FAD1489685E7}.Release|x64.Build.0 = Release|x64 {40B76674-02DE-40EF-889B-FAD1489685E7}.UWP Gold|ARM.ActiveCfg = UWP Gold|ARM {40B76674-02DE-40EF-889B-FAD1489685E7}.UWP Gold|ARM.Build.0 = UWP Gold|ARM + {40B76674-02DE-40EF-889B-FAD1489685E7}.UWP Gold|ARM64.ActiveCfg = UWP Gold|Win32 {40B76674-02DE-40EF-889B-FAD1489685E7}.UWP Gold|Win32.ActiveCfg = UWP Gold|Win32 {40B76674-02DE-40EF-889B-FAD1489685E7}.UWP Gold|Win32.Build.0 = UWP Gold|Win32 {40B76674-02DE-40EF-889B-FAD1489685E7}.UWP Gold|x64.ActiveCfg = UWP Gold|x64 {40B76674-02DE-40EF-889B-FAD1489685E7}.UWP Gold|x64.Build.0 = UWP Gold|x64 {5D271429-C288-4534-98AF-94475D940058}.Debug|ARM.ActiveCfg = Debug|ARM {5D271429-C288-4534-98AF-94475D940058}.Debug|ARM.Build.0 = Debug|ARM + {5D271429-C288-4534-98AF-94475D940058}.Debug|ARM64.ActiveCfg = Debug|Win32 {5D271429-C288-4534-98AF-94475D940058}.Debug|Win32.ActiveCfg = Debug|Win32 {5D271429-C288-4534-98AF-94475D940058}.Debug|Win32.Build.0 = Debug|Win32 {5D271429-C288-4534-98AF-94475D940058}.Debug|x64.ActiveCfg = Debug|x64 {5D271429-C288-4534-98AF-94475D940058}.Debug|x64.Build.0 = Debug|x64 {5D271429-C288-4534-98AF-94475D940058}.Release|ARM.ActiveCfg = Release|ARM {5D271429-C288-4534-98AF-94475D940058}.Release|ARM.Build.0 = Release|ARM + {5D271429-C288-4534-98AF-94475D940058}.Release|ARM64.ActiveCfg = Release|Win32 {5D271429-C288-4534-98AF-94475D940058}.Release|Win32.ActiveCfg = Release|Win32 {5D271429-C288-4534-98AF-94475D940058}.Release|Win32.Build.0 = Release|Win32 {5D271429-C288-4534-98AF-94475D940058}.Release|x64.ActiveCfg = Release|x64 {5D271429-C288-4534-98AF-94475D940058}.Release|x64.Build.0 = Release|x64 {5D271429-C288-4534-98AF-94475D940058}.UWP Gold|ARM.ActiveCfg = UWP Gold|ARM {5D271429-C288-4534-98AF-94475D940058}.UWP Gold|ARM.Build.0 = UWP Gold|ARM + {5D271429-C288-4534-98AF-94475D940058}.UWP Gold|ARM64.ActiveCfg = UWP Gold|Win32 {5D271429-C288-4534-98AF-94475D940058}.UWP Gold|Win32.ActiveCfg = UWP Gold|Win32 {5D271429-C288-4534-98AF-94475D940058}.UWP Gold|Win32.Build.0 = UWP Gold|Win32 {5D271429-C288-4534-98AF-94475D940058}.UWP Gold|x64.ActiveCfg = UWP Gold|x64 {5D271429-C288-4534-98AF-94475D940058}.UWP Gold|x64.Build.0 = UWP Gold|x64 {935028AF-B850-4AD7-A00E-7BA84FB97D05}.Debug|ARM.ActiveCfg = Debug|ARM {935028AF-B850-4AD7-A00E-7BA84FB97D05}.Debug|ARM.Build.0 = Debug|ARM + {935028AF-B850-4AD7-A00E-7BA84FB97D05}.Debug|ARM64.ActiveCfg = Debug|Win32 {935028AF-B850-4AD7-A00E-7BA84FB97D05}.Debug|Win32.ActiveCfg = Debug|Win32 {935028AF-B850-4AD7-A00E-7BA84FB97D05}.Debug|Win32.Build.0 = Debug|Win32 {935028AF-B850-4AD7-A00E-7BA84FB97D05}.Debug|x64.ActiveCfg = Debug|x64 {935028AF-B850-4AD7-A00E-7BA84FB97D05}.Debug|x64.Build.0 = Debug|x64 {935028AF-B850-4AD7-A00E-7BA84FB97D05}.Release|ARM.ActiveCfg = Release|ARM {935028AF-B850-4AD7-A00E-7BA84FB97D05}.Release|ARM.Build.0 = Release|ARM + {935028AF-B850-4AD7-A00E-7BA84FB97D05}.Release|ARM64.ActiveCfg = Release|Win32 {935028AF-B850-4AD7-A00E-7BA84FB97D05}.Release|Win32.ActiveCfg = Release|Win32 {935028AF-B850-4AD7-A00E-7BA84FB97D05}.Release|Win32.Build.0 = Release|Win32 {935028AF-B850-4AD7-A00E-7BA84FB97D05}.Release|x64.ActiveCfg = Release|x64 {935028AF-B850-4AD7-A00E-7BA84FB97D05}.Release|x64.Build.0 = Release|x64 {935028AF-B850-4AD7-A00E-7BA84FB97D05}.UWP Gold|ARM.ActiveCfg = UWP Gold|ARM {935028AF-B850-4AD7-A00E-7BA84FB97D05}.UWP Gold|ARM.Build.0 = UWP Gold|ARM + {935028AF-B850-4AD7-A00E-7BA84FB97D05}.UWP Gold|ARM64.ActiveCfg = UWP Gold|Win32 {935028AF-B850-4AD7-A00E-7BA84FB97D05}.UWP Gold|Win32.ActiveCfg = UWP Gold|Win32 {935028AF-B850-4AD7-A00E-7BA84FB97D05}.UWP Gold|Win32.Build.0 = UWP Gold|Win32 {935028AF-B850-4AD7-A00E-7BA84FB97D05}.UWP Gold|x64.ActiveCfg = UWP Gold|x64 {935028AF-B850-4AD7-A00E-7BA84FB97D05}.UWP Gold|x64.Build.0 = UWP Gold|x64 {5FAC15BD-7397-4512-99D5-66CDC03AF5B7}.Debug|ARM.ActiveCfg = Debug|ARM {5FAC15BD-7397-4512-99D5-66CDC03AF5B7}.Debug|ARM.Build.0 = Debug|ARM + {5FAC15BD-7397-4512-99D5-66CDC03AF5B7}.Debug|ARM64.ActiveCfg = Debug|Win32 {5FAC15BD-7397-4512-99D5-66CDC03AF5B7}.Debug|Win32.ActiveCfg = Debug|Win32 {5FAC15BD-7397-4512-99D5-66CDC03AF5B7}.Debug|Win32.Build.0 = Debug|Win32 {5FAC15BD-7397-4512-99D5-66CDC03AF5B7}.Debug|x64.ActiveCfg = Debug|x64 {5FAC15BD-7397-4512-99D5-66CDC03AF5B7}.Debug|x64.Build.0 = Debug|x64 {5FAC15BD-7397-4512-99D5-66CDC03AF5B7}.Release|ARM.ActiveCfg = Release|ARM {5FAC15BD-7397-4512-99D5-66CDC03AF5B7}.Release|ARM.Build.0 = Release|ARM + {5FAC15BD-7397-4512-99D5-66CDC03AF5B7}.Release|ARM64.ActiveCfg = Release|Win32 {5FAC15BD-7397-4512-99D5-66CDC03AF5B7}.Release|Win32.ActiveCfg = Release|Win32 {5FAC15BD-7397-4512-99D5-66CDC03AF5B7}.Release|Win32.Build.0 = Release|Win32 {5FAC15BD-7397-4512-99D5-66CDC03AF5B7}.Release|x64.ActiveCfg = Release|x64 {5FAC15BD-7397-4512-99D5-66CDC03AF5B7}.Release|x64.Build.0 = Release|x64 {5FAC15BD-7397-4512-99D5-66CDC03AF5B7}.UWP Gold|ARM.ActiveCfg = UWP Gold|ARM {5FAC15BD-7397-4512-99D5-66CDC03AF5B7}.UWP Gold|ARM.Build.0 = UWP Gold|ARM + {5FAC15BD-7397-4512-99D5-66CDC03AF5B7}.UWP Gold|ARM64.ActiveCfg = UWP Gold|Win32 {5FAC15BD-7397-4512-99D5-66CDC03AF5B7}.UWP Gold|Win32.ActiveCfg = UWP Gold|Win32 {5FAC15BD-7397-4512-99D5-66CDC03AF5B7}.UWP Gold|Win32.Build.0 = UWP Gold|Win32 {5FAC15BD-7397-4512-99D5-66CDC03AF5B7}.UWP Gold|x64.ActiveCfg = UWP Gold|x64 {5FAC15BD-7397-4512-99D5-66CDC03AF5B7}.UWP Gold|x64.Build.0 = UWP Gold|x64 {2F911C05-B341-4291-8BF5-09EDECBDD5F5}.Debug|ARM.ActiveCfg = Debug|ARM {2F911C05-B341-4291-8BF5-09EDECBDD5F5}.Debug|ARM.Build.0 = Debug|ARM + {2F911C05-B341-4291-8BF5-09EDECBDD5F5}.Debug|ARM64.ActiveCfg = Debug|Win32 {2F911C05-B341-4291-8BF5-09EDECBDD5F5}.Debug|Win32.ActiveCfg = Debug|Win32 {2F911C05-B341-4291-8BF5-09EDECBDD5F5}.Debug|Win32.Build.0 = Debug|Win32 {2F911C05-B341-4291-8BF5-09EDECBDD5F5}.Debug|x64.ActiveCfg = Debug|x64 {2F911C05-B341-4291-8BF5-09EDECBDD5F5}.Debug|x64.Build.0 = Debug|x64 {2F911C05-B341-4291-8BF5-09EDECBDD5F5}.Release|ARM.ActiveCfg = Release|ARM {2F911C05-B341-4291-8BF5-09EDECBDD5F5}.Release|ARM.Build.0 = Release|ARM + {2F911C05-B341-4291-8BF5-09EDECBDD5F5}.Release|ARM64.ActiveCfg = Release|Win32 {2F911C05-B341-4291-8BF5-09EDECBDD5F5}.Release|Win32.ActiveCfg = Release|Win32 {2F911C05-B341-4291-8BF5-09EDECBDD5F5}.Release|Win32.Build.0 = Release|Win32 {2F911C05-B341-4291-8BF5-09EDECBDD5F5}.Release|x64.ActiveCfg = Release|x64 {2F911C05-B341-4291-8BF5-09EDECBDD5F5}.Release|x64.Build.0 = Release|x64 {2F911C05-B341-4291-8BF5-09EDECBDD5F5}.UWP Gold|ARM.ActiveCfg = UWP Gold|ARM {2F911C05-B341-4291-8BF5-09EDECBDD5F5}.UWP Gold|ARM.Build.0 = UWP Gold|ARM + {2F911C05-B341-4291-8BF5-09EDECBDD5F5}.UWP Gold|ARM64.ActiveCfg = UWP Gold|Win32 {2F911C05-B341-4291-8BF5-09EDECBDD5F5}.UWP Gold|Win32.ActiveCfg = UWP Gold|Win32 {2F911C05-B341-4291-8BF5-09EDECBDD5F5}.UWP Gold|Win32.Build.0 = UWP Gold|Win32 {2F911C05-B341-4291-8BF5-09EDECBDD5F5}.UWP Gold|x64.ActiveCfg = UWP Gold|x64 {2F911C05-B341-4291-8BF5-09EDECBDD5F5}.UWP Gold|x64.Build.0 = UWP Gold|x64 {DDF90203-0AAE-4F38-B589-2E9637658CE6}.Debug|ARM.ActiveCfg = Debug|ARM {DDF90203-0AAE-4F38-B589-2E9637658CE6}.Debug|ARM.Build.0 = Debug|ARM + {DDF90203-0AAE-4F38-B589-2E9637658CE6}.Debug|ARM64.ActiveCfg = Debug|Win32 {DDF90203-0AAE-4F38-B589-2E9637658CE6}.Debug|Win32.ActiveCfg = Debug|Win32 {DDF90203-0AAE-4F38-B589-2E9637658CE6}.Debug|Win32.Build.0 = Debug|Win32 {DDF90203-0AAE-4F38-B589-2E9637658CE6}.Debug|x64.ActiveCfg = Debug|x64 {DDF90203-0AAE-4F38-B589-2E9637658CE6}.Debug|x64.Build.0 = Debug|x64 {DDF90203-0AAE-4F38-B589-2E9637658CE6}.Release|ARM.ActiveCfg = Release|ARM {DDF90203-0AAE-4F38-B589-2E9637658CE6}.Release|ARM.Build.0 = Release|ARM + {DDF90203-0AAE-4F38-B589-2E9637658CE6}.Release|ARM64.ActiveCfg = Release|Win32 {DDF90203-0AAE-4F38-B589-2E9637658CE6}.Release|Win32.ActiveCfg = Release|Win32 {DDF90203-0AAE-4F38-B589-2E9637658CE6}.Release|Win32.Build.0 = Release|Win32 {DDF90203-0AAE-4F38-B589-2E9637658CE6}.Release|x64.ActiveCfg = Release|x64 {DDF90203-0AAE-4F38-B589-2E9637658CE6}.Release|x64.Build.0 = Release|x64 {DDF90203-0AAE-4F38-B589-2E9637658CE6}.UWP Gold|ARM.ActiveCfg = UWP Gold|ARM {DDF90203-0AAE-4F38-B589-2E9637658CE6}.UWP Gold|ARM.Build.0 = UWP Gold|ARM + {DDF90203-0AAE-4F38-B589-2E9637658CE6}.UWP Gold|ARM64.ActiveCfg = UWP Gold|Win32 {DDF90203-0AAE-4F38-B589-2E9637658CE6}.UWP Gold|Win32.ActiveCfg = UWP Gold|Win32 {DDF90203-0AAE-4F38-B589-2E9637658CE6}.UWP Gold|Win32.Build.0 = UWP Gold|Win32 {DDF90203-0AAE-4F38-B589-2E9637658CE6}.UWP Gold|x64.ActiveCfg = UWP Gold|x64 @@ -164,6 +190,7 @@ Global {01D7D581-09A3-4A26-94BD-A7C529B29329}.Debug|ARM.ActiveCfg = Debug|ARM {01D7D581-09A3-4A26-94BD-A7C529B29329}.Debug|ARM.Build.0 = Debug|ARM {01D7D581-09A3-4A26-94BD-A7C529B29329}.Debug|ARM.Deploy.0 = Debug|ARM + {01D7D581-09A3-4A26-94BD-A7C529B29329}.Debug|ARM64.ActiveCfg = Debug|Win32 {01D7D581-09A3-4A26-94BD-A7C529B29329}.Debug|Win32.ActiveCfg = Debug|Win32 {01D7D581-09A3-4A26-94BD-A7C529B29329}.Debug|Win32.Build.0 = Debug|Win32 {01D7D581-09A3-4A26-94BD-A7C529B29329}.Debug|Win32.Deploy.0 = Debug|Win32 @@ -173,6 +200,7 @@ Global {01D7D581-09A3-4A26-94BD-A7C529B29329}.Release|ARM.ActiveCfg = Release|ARM {01D7D581-09A3-4A26-94BD-A7C529B29329}.Release|ARM.Build.0 = Release|ARM {01D7D581-09A3-4A26-94BD-A7C529B29329}.Release|ARM.Deploy.0 = Release|ARM + {01D7D581-09A3-4A26-94BD-A7C529B29329}.Release|ARM64.ActiveCfg = Release|Win32 {01D7D581-09A3-4A26-94BD-A7C529B29329}.Release|Win32.ActiveCfg = Release|Win32 {01D7D581-09A3-4A26-94BD-A7C529B29329}.Release|Win32.Build.0 = Release|Win32 {01D7D581-09A3-4A26-94BD-A7C529B29329}.Release|Win32.Deploy.0 = Release|Win32 @@ -182,6 +210,7 @@ Global {01D7D581-09A3-4A26-94BD-A7C529B29329}.UWP Gold|ARM.ActiveCfg = UWP Gold|ARM {01D7D581-09A3-4A26-94BD-A7C529B29329}.UWP Gold|ARM.Build.0 = UWP Gold|ARM {01D7D581-09A3-4A26-94BD-A7C529B29329}.UWP Gold|ARM.Deploy.0 = UWP Gold|ARM + {01D7D581-09A3-4A26-94BD-A7C529B29329}.UWP Gold|ARM64.ActiveCfg = UWP Gold|Win32 {01D7D581-09A3-4A26-94BD-A7C529B29329}.UWP Gold|Win32.ActiveCfg = UWP Gold|Win32 {01D7D581-09A3-4A26-94BD-A7C529B29329}.UWP Gold|Win32.Build.0 = UWP Gold|Win32 {01D7D581-09A3-4A26-94BD-A7C529B29329}.UWP Gold|Win32.Deploy.0 = UWP Gold|Win32 @@ -190,42 +219,73 @@ Global {01D7D581-09A3-4A26-94BD-A7C529B29329}.UWP Gold|x64.Deploy.0 = UWP Gold|x64 {D326891E-ECE4-4B94-B5E7-8AA0A8E8ECBC}.Debug|ARM.ActiveCfg = Debug|ARM {D326891E-ECE4-4B94-B5E7-8AA0A8E8ECBC}.Debug|ARM.Build.0 = Debug|ARM + {D326891E-ECE4-4B94-B5E7-8AA0A8E8ECBC}.Debug|ARM64.ActiveCfg = Debug|Win32 {D326891E-ECE4-4B94-B5E7-8AA0A8E8ECBC}.Debug|Win32.ActiveCfg = Debug|Win32 {D326891E-ECE4-4B94-B5E7-8AA0A8E8ECBC}.Debug|Win32.Build.0 = Debug|Win32 {D326891E-ECE4-4B94-B5E7-8AA0A8E8ECBC}.Debug|x64.ActiveCfg = Debug|x64 {D326891E-ECE4-4B94-B5E7-8AA0A8E8ECBC}.Debug|x64.Build.0 = Debug|x64 {D326891E-ECE4-4B94-B5E7-8AA0A8E8ECBC}.Release|ARM.ActiveCfg = Release|ARM {D326891E-ECE4-4B94-B5E7-8AA0A8E8ECBC}.Release|ARM.Build.0 = Release|ARM + {D326891E-ECE4-4B94-B5E7-8AA0A8E8ECBC}.Release|ARM64.ActiveCfg = Release|Win32 {D326891E-ECE4-4B94-B5E7-8AA0A8E8ECBC}.Release|Win32.ActiveCfg = Release|Win32 {D326891E-ECE4-4B94-B5E7-8AA0A8E8ECBC}.Release|Win32.Build.0 = Release|Win32 {D326891E-ECE4-4B94-B5E7-8AA0A8E8ECBC}.Release|x64.ActiveCfg = Release|x64 {D326891E-ECE4-4B94-B5E7-8AA0A8E8ECBC}.Release|x64.Build.0 = Release|x64 {D326891E-ECE4-4B94-B5E7-8AA0A8E8ECBC}.UWP Gold|ARM.ActiveCfg = UWP Gold|ARM {D326891E-ECE4-4B94-B5E7-8AA0A8E8ECBC}.UWP Gold|ARM.Build.0 = UWP Gold|ARM + {D326891E-ECE4-4B94-B5E7-8AA0A8E8ECBC}.UWP Gold|ARM64.ActiveCfg = UWP Gold|Win32 {D326891E-ECE4-4B94-B5E7-8AA0A8E8ECBC}.UWP Gold|Win32.ActiveCfg = UWP Gold|Win32 {D326891E-ECE4-4B94-B5E7-8AA0A8E8ECBC}.UWP Gold|Win32.Build.0 = UWP Gold|Win32 {D326891E-ECE4-4B94-B5E7-8AA0A8E8ECBC}.UWP Gold|x64.ActiveCfg = UWP Gold|x64 {D326891E-ECE4-4B94-B5E7-8AA0A8E8ECBC}.UWP Gold|x64.Build.0 = UWP Gold|x64 {2B2D16BD-1D37-46AF-A3F8-552900951B26}.Debug|ARM.ActiveCfg = Debug|ARM {2B2D16BD-1D37-46AF-A3F8-552900951B26}.Debug|ARM.Build.0 = Debug|ARM + {2B2D16BD-1D37-46AF-A3F8-552900951B26}.Debug|ARM64.ActiveCfg = Debug|Win32 {2B2D16BD-1D37-46AF-A3F8-552900951B26}.Debug|Win32.ActiveCfg = Debug|Win32 {2B2D16BD-1D37-46AF-A3F8-552900951B26}.Debug|Win32.Build.0 = Debug|Win32 {2B2D16BD-1D37-46AF-A3F8-552900951B26}.Debug|x64.ActiveCfg = Debug|x64 {2B2D16BD-1D37-46AF-A3F8-552900951B26}.Debug|x64.Build.0 = Debug|x64 {2B2D16BD-1D37-46AF-A3F8-552900951B26}.Release|ARM.ActiveCfg = Release|ARM {2B2D16BD-1D37-46AF-A3F8-552900951B26}.Release|ARM.Build.0 = Release|ARM + {2B2D16BD-1D37-46AF-A3F8-552900951B26}.Release|ARM64.ActiveCfg = Release|Win32 {2B2D16BD-1D37-46AF-A3F8-552900951B26}.Release|Win32.ActiveCfg = Release|Win32 {2B2D16BD-1D37-46AF-A3F8-552900951B26}.Release|Win32.Build.0 = Release|Win32 {2B2D16BD-1D37-46AF-A3F8-552900951B26}.Release|x64.ActiveCfg = Release|x64 {2B2D16BD-1D37-46AF-A3F8-552900951B26}.Release|x64.Build.0 = Release|x64 {2B2D16BD-1D37-46AF-A3F8-552900951B26}.UWP Gold|ARM.ActiveCfg = UWP Gold|ARM {2B2D16BD-1D37-46AF-A3F8-552900951B26}.UWP Gold|ARM.Build.0 = UWP Gold|ARM + {2B2D16BD-1D37-46AF-A3F8-552900951B26}.UWP Gold|ARM64.ActiveCfg = UWP Gold|Win32 {2B2D16BD-1D37-46AF-A3F8-552900951B26}.UWP Gold|Win32.ActiveCfg = UWP Gold|Win32 {2B2D16BD-1D37-46AF-A3F8-552900951B26}.UWP Gold|Win32.Build.0 = UWP Gold|Win32 {2B2D16BD-1D37-46AF-A3F8-552900951B26}.UWP Gold|x64.ActiveCfg = UWP Gold|x64 {2B2D16BD-1D37-46AF-A3F8-552900951B26}.UWP Gold|x64.Build.0 = UWP Gold|x64 + {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.Debug|ARM.ActiveCfg = Debug|ARM + {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.Debug|ARM.Build.0 = Debug|ARM + {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.Debug|ARM64.ActiveCfg = Debug|Win32 + {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.Debug|Win32.ActiveCfg = Debug|Win32 + {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.Debug|Win32.Build.0 = Debug|Win32 + {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.Debug|x64.ActiveCfg = Debug|x64 + {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.Debug|x64.Build.0 = Debug|x64 + {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.Release|ARM.ActiveCfg = Release|ARM + {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.Release|ARM.Build.0 = Release|ARM + {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.Release|ARM64.ActiveCfg = Release|Win32 + {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.Release|Win32.ActiveCfg = Release|Win32 + {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.Release|Win32.Build.0 = Release|Win32 + {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.Release|x64.ActiveCfg = Release|x64 + {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.Release|x64.Build.0 = Release|x64 + {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.UWP Gold|ARM.ActiveCfg = Release|ARM + {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.UWP Gold|ARM.Build.0 = Release|ARM + {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.UWP Gold|ARM64.ActiveCfg = Release|x64 + {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.UWP Gold|ARM64.Build.0 = Release|x64 + {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.UWP Gold|Win32.ActiveCfg = Release|Win32 + {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.UWP Gold|Win32.Build.0 = Release|Win32 + {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.UWP Gold|x64.ActiveCfg = Release|x64 + {75286959-E7A2-4CBE-8B95-BF05C9C540FF}.UWP Gold|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2C8B6968-85F7-4F06-9D3D-7CD2309F5B0E} + EndGlobalSection EndGlobal diff --git a/UWP/PPSSPP_UWPMain.cpp b/UWP/PPSSPP_UWPMain.cpp index 994871cff1..b7271d5288 100644 --- a/UWP/PPSSPP_UWPMain.cpp +++ b/UWP/PPSSPP_UWPMain.cpp @@ -120,7 +120,7 @@ PPSSPP_UWPMain::PPSSPP_UWPMain(App ^app, const std::shared_ptrLocalFolder->Path->Data()); - NativeInit(1, argv, "", "", cacheFolder.c_str(), false); + NativeInit(1, argv, "", "", cacheFolder.c_str()); NativeInitGraphics(ctx_.get()); NativeResized(); @@ -322,8 +322,10 @@ void PPSSPP_UWPMain::LoadStorageFile(StorageFile ^file) { } UWPGraphicsContext::UWPGraphicsContext(std::shared_ptr resources) { + std::vector adapterNames; + draw_ = Draw::T3DCreateD3D11Context( - resources->GetD3DDevice(), resources->GetD3DDeviceContext(), resources->GetD3DDevice(), resources->GetD3DDeviceContext(), resources->GetDeviceFeatureLevel(), 0); + resources->GetD3DDevice(), resources->GetD3DDeviceContext(), resources->GetD3DDevice(), resources->GetD3DDeviceContext(), resources->GetDeviceFeatureLevel(), 0, adapterNames); bool success = draw_->CreatePresets(); assert(success); } diff --git a/UWP/SPIRVCross_UWP/SPIRVCross_UWP.vcxproj b/UWP/SPIRVCross_UWP/SPIRVCross_UWP.vcxproj index fe4a09e6a7..4c4c18f190 100644 --- a/UWP/SPIRVCross_UWP/SPIRVCross_UWP.vcxproj +++ b/UWP/SPIRVCross_UWP/SPIRVCross_UWP.vcxproj @@ -46,9 +46,9 @@ 14.0 true Windows Store - 10.0.14393.0 + 10.0.15063.0 10.0 - 10.0.16299.0 + 10.0.17763.0 @@ -169,6 +169,7 @@ false true pch.h + _UNICODE;UNICODE;%(PreprocessorDefinitions);NOMINMAX Console @@ -182,6 +183,7 @@ false true pch.h + _UNICODE;UNICODE;%(PreprocessorDefinitions);NOMINMAX Console @@ -195,6 +197,7 @@ false true pch.h + _UNICODE;UNICODE;%(PreprocessorDefinitions);NOMINMAX Console @@ -208,6 +211,7 @@ false true pch.h + _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions);NOMINMAX Console @@ -221,6 +225,7 @@ false true pch.h + _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions);NOMINMAX Console @@ -234,6 +239,7 @@ false true pch.h + _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions);NOMINMAX Console @@ -247,6 +253,7 @@ false true pch.h + _UNICODE;UNICODE;%(PreprocessorDefinitions);NOMINMAX Console @@ -260,6 +267,7 @@ false true pch.h + _UNICODE;UNICODE;%(PreprocessorDefinitions);NOMINMAX Console @@ -273,6 +281,7 @@ false true pch.h + _UNICODE;UNICODE;%(PreprocessorDefinitions);NOMINMAX Console @@ -314,4 +323,4 @@ - + \ No newline at end of file diff --git a/UWP/SPIRVCross_UWP/SPIRVCross_UWP.vcxproj.filters b/UWP/SPIRVCross_UWP/SPIRVCross_UWP.vcxproj.filters index cedc522ec9..ae84b6bb46 100644 --- a/UWP/SPIRVCross_UWP/SPIRVCross_UWP.vcxproj.filters +++ b/UWP/SPIRVCross_UWP/SPIRVCross_UWP.vcxproj.filters @@ -13,6 +13,7 @@ + @@ -24,5 +25,6 @@ + \ No newline at end of file diff --git a/UWP/UI_UWP/UI_UWP.vcxproj b/UWP/UI_UWP/UI_UWP.vcxproj index 3b54be0228..a73d6f94a5 100644 --- a/UWP/UI_UWP/UI_UWP.vcxproj +++ b/UWP/UI_UWP/UI_UWP.vcxproj @@ -46,9 +46,9 @@ 14.0 true Windows Store - 10.0.14393.0 + 10.0.15063.0 10.0 - 10.0.16299.0 + 10.0.17763.0 @@ -378,4 +378,4 @@ - + \ No newline at end of file diff --git a/UWP/UWP.vcxproj b/UWP/UWP.vcxproj index 5d791cfa75..d785bf6c56 100644 --- a/UWP/UWP.vcxproj +++ b/UWP/UWP.vcxproj @@ -46,10 +46,10 @@ 14.0 true Windows Store - 10.0.14393.0 + 10.0.15063.0 10.0 PPSSPP_UWP - 10.0.16299.0 + 10.0.17763.0 @@ -156,7 +156,7 @@ PPSSPP_UWP_TemporaryKey.pfx True False - Never + Never B57919568D3F60B8D25EC6856DE94173682C548C @@ -464,6 +464,9 @@ copy AssetsGold\*.* Assets /Y + + {75286959-e7a2-4cbe-8b95-bf05c9c540ff} + {acb316ca-3ecb-48e5-be0a-91e72d5b0f12} @@ -506,4 +509,4 @@ copy AssetsGold\*.* Assets /Y - + \ No newline at end of file diff --git a/UWP/UWPHost.cpp b/UWP/UWPHost.cpp index 72dd263857..8bbe1cb4a6 100644 --- a/UWP/UWPHost.cpp +++ b/UWP/UWPHost.cpp @@ -31,7 +31,6 @@ #include "UI/OnScreenDisplay.h" #include "Windows/XinputDevice.h" -#include "Windows/DSoundStream.h" #include "UWP/XAudioSoundStream.h" #include "UWP/UWPHost.h" diff --git a/UWP/XAudioSoundStream.h b/UWP/XAudioSoundStream.h index 35b26f0abf..be53b7d8d4 100644 --- a/UWP/XAudioSoundStream.h +++ b/UWP/XAudioSoundStream.h @@ -2,7 +2,8 @@ #include "Common/CommonWindows.h" #include "Core/Config.h" -#include "Windows/DSoundStream.h" + +#include "Windows/WindowsAudio.h" // Factory WindowsAudioBackend *CreateAudioBackend(AudioBackendType type); diff --git a/UWP/glslang_UWP/glslang_UWP.vcxproj b/UWP/glslang_UWP/glslang_UWP.vcxproj index 591ece0c89..446c6d00d4 100644 --- a/UWP/glslang_UWP/glslang_UWP.vcxproj +++ b/UWP/glslang_UWP/glslang_UWP.vcxproj @@ -46,9 +46,9 @@ 14.0 true Windows Store - 10.0.14393.0 + 10.0.15063.0 10.0 - 10.0.16299.0 + 10.0.17763.0 @@ -302,6 +302,7 @@ + @@ -347,6 +348,7 @@ + diff --git a/UWP/glslang_UWP/glslang_UWP.vcxproj.filters b/UWP/glslang_UWP/glslang_UWP.vcxproj.filters index 26316f364e..9d3fc6da3c 100644 --- a/UWP/glslang_UWP/glslang_UWP.vcxproj.filters +++ b/UWP/glslang_UWP/glslang_UWP.vcxproj.filters @@ -160,6 +160,9 @@ OGLCompilersDLL + + glslang\MachineIndependent + @@ -317,5 +320,8 @@ OGLCompilersDLL + + glslang\MachineIndependent + \ No newline at end of file diff --git a/UWP/libkirk_UWP/libkirk_UWP.vcxproj b/UWP/libkirk_UWP/libkirk_UWP.vcxproj index d993e1145e..579034284b 100644 --- a/UWP/libkirk_UWP/libkirk_UWP.vcxproj +++ b/UWP/libkirk_UWP/libkirk_UWP.vcxproj @@ -46,9 +46,9 @@ 14.0 true Windows Store - 10.0.14393.0 + 10.0.15063.0 10.0 - 10.0.16299.0 + 10.0.17763.0 diff --git a/UWP/zlib_UWP/zlib_UWP.vcxproj b/UWP/zlib_UWP/zlib_UWP.vcxproj index 347bd1ea74..48995ec5a3 100644 --- a/UWP/zlib_UWP/zlib_UWP.vcxproj +++ b/UWP/zlib_UWP/zlib_UWP.vcxproj @@ -46,9 +46,9 @@ 14.0 true Windows Store - 10.0.14393.0 + 10.0.15063.0 10.0 - 10.0.16299.0 + 10.0.17763.0 diff --git a/ext/native/math/fast/fast_math.c b/ext/native/math/fast/fast_math.c index 5363a32830..8976122646 100644 --- a/ext/native/math/fast/fast_math.c +++ b/ext/native/math/fast/fast_math.c @@ -5,8 +5,10 @@ void InitFastMath(int enableNEON) { // Every architecture has its own define. This needs to be added to. if (enableNEON) { +#ifndef _MSC_VER #if PPSSPP_ARCH(ARM_NEON) && !PPSSPP_ARCH(ARM64) fast_matrix_mul_4x4 = &fast_matrix_mul_4x4_neon; +#endif #endif } } diff --git a/ext/native/net/http_server.cpp b/ext/native/net/http_server.cpp index f7cae6cd30..be74e4337e 100644 --- a/ext/native/net/http_server.cpp +++ b/ext/native/net/http_server.cpp @@ -1,4 +1,5 @@ #include "base/timeutil.h" +#include "ppsspp_config.h" #ifdef _WIN32 @@ -23,6 +24,10 @@ #endif +#ifdef PPSSPP_PLATFORM(UWP) +#define in6addr_any IN6ADDR_ANY_INIT +#endif + #include #include From d8458c212e208dd10244c95c56be89a839a9df60 Mon Sep 17 00:00:00 2001 From: pent0 Date: Mon, 10 Dec 2018 21:29:27 +0700 Subject: [PATCH 202/347] Disable SDL check with armips dependency Uninitialized pointer --- UWP/.gitignore | 1 + UWP/Armips_UWP/Armips_UWP.vcxproj | 4 ++-- UWP/FastMath_UWP/FastMath_UWP.cpp | 2 -- 3 files changed, 3 insertions(+), 4 deletions(-) delete mode 100644 UWP/FastMath_UWP/FastMath_UWP.cpp diff --git a/UWP/.gitignore b/UWP/.gitignore index 0abc1926b8..e9662c04b3 100644 --- a/UWP/.gitignore +++ b/UWP/.gitignore @@ -3,6 +3,7 @@ Package.appxmanifest Assets x64 +ARM *.VC.db *.VC.VC.opendb ipch diff --git a/UWP/Armips_UWP/Armips_UWP.vcxproj b/UWP/Armips_UWP/Armips_UWP.vcxproj index 64e73e0af4..b78bdf9e41 100644 --- a/UWP/Armips_UWP/Armips_UWP.vcxproj +++ b/UWP/Armips_UWP/Armips_UWP.vcxproj @@ -145,7 +145,7 @@ NotUsing false - true + false Console @@ -157,7 +157,7 @@ NotUsing false - true + false Console diff --git a/UWP/FastMath_UWP/FastMath_UWP.cpp b/UWP/FastMath_UWP/FastMath_UWP.cpp deleted file mode 100644 index aca0e62da6..0000000000 --- a/UWP/FastMath_UWP/FastMath_UWP.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "pch.h" -#include "FastMath_UWP.h" From b282d83258d8a675cc9bb39cb43cb91dce7d746b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 10 Dec 2018 23:48:28 +0100 Subject: [PATCH 203/347] Revert 6fd1c0e3d and eba6c00 which experimentally disabled dual src on Adreno. I don't think we have any indications that it doesn't work. --- Common/Vulkan/VulkanContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index 299641d268..aeb29f20ea 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -513,7 +513,7 @@ void VulkanContext::ChooseDevice(int physical_device) { memset(&featuresEnabled_, 0, sizeof(featuresEnabled_)); // Enable a few safe ones if they are available. - if (featuresAvailable_.dualSrcBlend && physicalDeviceProperties_[physical_device_].vendorID != VULKAN_VENDOR_QUALCOMM) { + if (featuresAvailable_.dualSrcBlend) { featuresEnabled_.dualSrcBlend = true; } if (featuresAvailable_.largePoints) { From 25b2ba013bd6112bea50e47244d4b03d97a9dba2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 11 Dec 2018 00:22:16 +0100 Subject: [PATCH 204/347] VK: Add INI options to disable some vendor checks, and to disable the shader cache. --- Core/Config.cpp | 2 ++ Core/Config.h | 2 ++ GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp | 4 +++- GPU/Vulkan/GPU_Vulkan.cpp | 12 +++++++++--- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index dd8e45681f..11bb6d597d 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -605,6 +605,8 @@ static ConfigSetting graphicsSettings[] = { #ifdef _WIN32 ConfigSetting("D3D11Device", &g_Config.sD3D11Device, "", true, false), #endif + ConfigSetting("VendorChecksEnabled", &g_Config.bVendorChecksEnabled, true, false, false), + ConfigSetting("ShaderCacheEnabled", &g_Config.bShaderCacheEnabled, true, false, false), ReportedConfigSetting("RenderingMode", &g_Config.iRenderingMode, &DefaultRenderingMode, true, true), ConfigSetting("SoftwareRenderer", &g_Config.bSoftwareRendering, false, true, true), ReportedConfigSetting("HardwareTransform", &g_Config.bHardwareTransform, true, true, true), diff --git a/Core/Config.h b/Core/Config.h index 311516d769..c36bd2eb43 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -131,6 +131,8 @@ public: bool bSoftwareRendering; bool bHardwareTransform; // only used in the GLES backend bool bSoftwareSkinning; // may speed up some games + bool bVendorChecksEnabled; + bool bShaderCacheEnabled; int iRenderingMode; // 0 = non-buffered rendering 1 = buffered rendering int iTexFiltering; // 1 = off , 2 = nearest , 3 = linear , 4 = linear(CG) diff --git a/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp b/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp index 1a880efc8f..2250a70f47 100644 --- a/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp @@ -86,7 +86,9 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_ bool earlyFragmentTests = ((!enableAlphaTest && !enableColorTest) || testForceToZero) && !gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT); bool hasStencilOutput = stencilToAlpha != REPLACE_ALPHA_NO || id.Bit(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE) == 0; - bool isAdreno = vulkanVendorId == VULKAN_VENDOR_QUALCOMM; + // TODO: This is a bug affecting shader cache generality - we CANNOT check anything but the shader ID and (indirectly) the game ID in here really. + // Need to move this check somehow to the shader ID generator. That's tricky though because it's generic... + bool isAdreno = vulkanVendorId == VULKAN_VENDOR_QUALCOMM && g_Config.bVendorChecksEnabled; if (earlyFragmentTests) { WRITE(p, "layout (early_fragment_tests) in;\n"); diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 6b81da93d1..2b95a8ea46 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -101,7 +101,7 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw) // Load shader cache. std::string discID = g_paramSFO.GetDiscID(); - if (discID.size()) { + if (discID.size() && g_Config.bShaderCacheEnabled) { File::CreateFullPath(GetSysDirectory(DIRECTORY_APP_CACHE)); shaderCachePath_ = GetSysDirectory(DIRECTORY_APP_CACHE) + "/" + discID + ".vkshadercache"; shaderCacheLoaded_ = false; @@ -201,6 +201,10 @@ void GPU_Vulkan::CheckGPUFeatures() { break; } + // Might enable this later - in the first round we are mostly looking at depth/stencil/discard. + // if (g_Config.bDisableVendorChecks) + // features |= GPU_SUPPORTS_ACCURATE_DEPTH; + // Mandatory features on Vulkan, which may be checked in "centralized" code features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; features |= GPU_SUPPORTS_FBO; @@ -224,7 +228,7 @@ void GPU_Vulkan::CheckGPUFeatures() { // We thought we had a bug here on nVidia but turns out we accidentally #ifdef-ed out crucial // code on Android. case VULKAN_VENDOR_INTEL: - // Workaround for Intel driver bug. + // Workaround for Intel driver bug. TODO: Re-enable after some driver version break; case VULKAN_VENDOR_AMD: // See issue #10074, and also #10065 (AMD) and #10109 for the choice of the driver version to check for @@ -235,6 +239,8 @@ void GPU_Vulkan::CheckGPUFeatures() { features |= GPU_SUPPORTS_DUALSOURCE_BLEND; break; } + if (!g_Config.bVendorChecksEnabled) + features |= GPU_SUPPORTS_DUALSOURCE_BLEND; } if (vulkan_->GetFeaturesEnabled().logicOp) { features |= GPU_SUPPORTS_LOGIC_OP; @@ -501,7 +507,7 @@ void GPU_Vulkan::DeviceLost() { while (!IsReady()) { sleep_ms(10); } - if (!shaderCachePath_.empty()) { + if (!shaderCachePath_.empty() && g_Config.bShaderCacheEnabled) { SaveCache(shaderCachePath_); } DestroyDeviceObjects(); From 02d2aa40693657e1a2ace100de19163a496d4778 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 10 Dec 2018 23:04:46 -0800 Subject: [PATCH 205/347] Windows: Hide Vulkan/D3D11 if not available. We only were doing this in the settings screen before. Fixes #11657. --- Windows/MainWindowMenu.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index ce9baab828..057872be4f 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -14,6 +14,8 @@ #include "Common/Log.h" #include "Common/LogManager.h" #include "Common/ConsoleListener.h" +#include "Common/OSVersion.h" +#include "Common/Vulkan/VulkanLoader.h" #include "GPU/GLES/TextureScalerGLES.h" #include "GPU/GLES/TextureCacheGLES.h" #include "UI/OnScreenDisplay.h" @@ -1268,12 +1270,15 @@ namespace MainWindow { CheckMenuItem(menu, savestateSlot[i], MF_BYCOMMAND | ((i == g_Config.iCurrentStateSlot) ? MF_CHECKED : MF_UNCHECKED)); } + bool allowD3D11 = DoesVersionMatchWindows(6, 0, 0, 0, true); + bool allowVulkan = VulkanMayBeAvailable(); + switch (GetGPUBackend()) { case GPUBackend::DIRECT3D9: EnableMenuItem(menu, ID_OPTIONS_DIRECT3D9, MF_GRAYED); - EnableMenuItem(menu, ID_OPTIONS_DIRECT3D11, MF_ENABLED); + EnableMenuItem(menu, ID_OPTIONS_DIRECT3D11, allowD3D11 ? MF_ENABLED : MF_GRAYED); EnableMenuItem(menu, ID_OPTIONS_OPENGL, MF_ENABLED); - EnableMenuItem(menu, ID_OPTIONS_VULKAN, MF_ENABLED); + EnableMenuItem(menu, ID_OPTIONS_VULKAN, allowVulkan ? MF_ENABLED : MF_GRAYED); CheckMenuItem(menu, ID_OPTIONS_DIRECT3D9, MF_CHECKED); CheckMenuItem(menu, ID_OPTIONS_DIRECT3D11, MF_UNCHECKED); CheckMenuItem(menu, ID_OPTIONS_OPENGL, MF_UNCHECKED); @@ -1281,9 +1286,9 @@ namespace MainWindow { break; case GPUBackend::OPENGL: EnableMenuItem(menu, ID_OPTIONS_DIRECT3D9, MF_ENABLED); - EnableMenuItem(menu, ID_OPTIONS_DIRECT3D11, MF_ENABLED); + EnableMenuItem(menu, ID_OPTIONS_DIRECT3D11, allowD3D11 ? MF_ENABLED : MF_GRAYED); EnableMenuItem(menu, ID_OPTIONS_OPENGL, MF_GRAYED); - EnableMenuItem(menu, ID_OPTIONS_VULKAN, MF_ENABLED); + EnableMenuItem(menu, ID_OPTIONS_VULKAN, allowVulkan ? MF_ENABLED : MF_GRAYED); CheckMenuItem(menu, ID_OPTIONS_DIRECT3D9, MF_UNCHECKED); CheckMenuItem(menu, ID_OPTIONS_DIRECT3D11, MF_UNCHECKED); CheckMenuItem(menu, ID_OPTIONS_OPENGL, MF_CHECKED); @@ -1291,7 +1296,7 @@ namespace MainWindow { break; case GPUBackend::VULKAN: EnableMenuItem(menu, ID_OPTIONS_DIRECT3D9, MF_ENABLED); - EnableMenuItem(menu, ID_OPTIONS_DIRECT3D11, MF_ENABLED); + EnableMenuItem(menu, ID_OPTIONS_DIRECT3D11, allowD3D11 ? MF_ENABLED : MF_GRAYED); EnableMenuItem(menu, ID_OPTIONS_OPENGL, MF_ENABLED); EnableMenuItem(menu, ID_OPTIONS_VULKAN, MF_GRAYED); CheckMenuItem(menu, ID_OPTIONS_DIRECT3D9, MF_UNCHECKED); @@ -1303,7 +1308,7 @@ namespace MainWindow { EnableMenuItem(menu, ID_OPTIONS_DIRECT3D9, MF_ENABLED); EnableMenuItem(menu, ID_OPTIONS_DIRECT3D11, MF_GRAYED); EnableMenuItem(menu, ID_OPTIONS_OPENGL, MF_ENABLED); - EnableMenuItem(menu, ID_OPTIONS_VULKAN, MF_ENABLED); + EnableMenuItem(menu, ID_OPTIONS_VULKAN, allowVulkan ? MF_ENABLED : MF_GRAYED); CheckMenuItem(menu, ID_OPTIONS_DIRECT3D9, MF_UNCHECKED); CheckMenuItem(menu, ID_OPTIONS_DIRECT3D11, MF_CHECKED); CheckMenuItem(menu, ID_OPTIONS_OPENGL, MF_UNCHECKED); From bb7d9646f28bded21ad92398c9a9b5d6187a277a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 10 Dec 2018 23:05:42 -0800 Subject: [PATCH 206/347] GE Debugger: Fix dump replay ticks accounting. Sometimes a list ends earlier than now, we don't need to eat cycles then. Fixes #11655. --- GPU/Debugger/Record.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/GPU/Debugger/Record.cpp b/GPU/Debugger/Record.cpp index 255612e3f6..0014d5eddf 100644 --- a/GPU/Debugger/Record.cpp +++ b/GPU/Debugger/Record.cpp @@ -872,7 +872,10 @@ void DumpExecute::SyncStall() { gpu->UpdateStall(execListID, execListPos); s64 listTicks = gpu->GetListTicks(execListID); if (listTicks != -1) { - currentMIPS->downcount -= listTicks - CoreTiming::GetTicks(); + s64 nowTicks = CoreTiming::GetTicks(); + if (listTicks > nowTicks) { + currentMIPS->downcount -= listTicks - nowTicks; + } } // Make sure downcount doesn't overflow. From d9fab1c4e0c4693f5df1ca00d86f48940452e77d Mon Sep 17 00:00:00 2001 From: pent0 Date: Tue, 11 Dec 2018 23:09:51 +0700 Subject: [PATCH 207/347] Disable precompiled header for all configurations of Armips --- UWP/Armips_UWP/Armips_UWP.vcxproj | 16 ++++++++++------ UWP/NativeUWP/NativeUWP.vcxproj | 18 +++++++++--------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/UWP/Armips_UWP/Armips_UWP.vcxproj b/UWP/Armips_UWP/Armips_UWP.vcxproj index b78bdf9e41..fabf7943e9 100644 --- a/UWP/Armips_UWP/Armips_UWP.vcxproj +++ b/UWP/Armips_UWP/Armips_UWP.vcxproj @@ -99,27 +99,31 @@ false + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips; false + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips; false - $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips; false - $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips; false + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips; false + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips; - Use + NotUsing false true @@ -131,7 +135,7 @@ - Use + NotUsing false true @@ -167,7 +171,7 @@ - Use + NotUsing false true @@ -179,7 +183,7 @@ - Use + NotUsing false true diff --git a/UWP/NativeUWP/NativeUWP.vcxproj b/UWP/NativeUWP/NativeUWP.vcxproj index 94d9984e97..b9af0a361c 100644 --- a/UWP/NativeUWP/NativeUWP.vcxproj +++ b/UWP/NativeUWP/NativeUWP.vcxproj @@ -170,7 +170,7 @@ true pch.h ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) + NOMINMAX;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) Console @@ -185,7 +185,7 @@ true pch.h ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) + NOMINMAX;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) Console @@ -200,7 +200,7 @@ true pch.h ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) + NOMINMAX;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) Console @@ -215,7 +215,7 @@ true pch.h ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;_CRT_SECURE_NO_WARNINGS;%(ClCompile.PreprocessorDefinitions) + NOMINMAX;_CRT_SECURE_NO_WARNINGS;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) Console @@ -230,7 +230,7 @@ true pch.h ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;_CRT_SECURE_NO_WARNINGS;%(ClCompile.PreprocessorDefinitions) + NOMINMAX;_CRT_SECURE_NO_WARNINGS;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) Console @@ -245,7 +245,7 @@ true pch.h ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;_CRT_SECURE_NO_WARNINGS;%(ClCompile.PreprocessorDefinitions) + NOMINMAX;_CRT_SECURE_NO_WARNINGS;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) Console @@ -260,7 +260,7 @@ true pch.h ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) + NOMINMAX;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) Console @@ -275,7 +275,7 @@ true pch.h ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) + NOMINMAX;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) Console @@ -290,7 +290,7 @@ true pch.h ../..;../../ext/native/ext;../..;../../ext/native;../../ext/zlib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) - NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions) + NOMINMAX;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) Console From 3f8aec514749d016f12f86d4c7f1607830ea846b Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 14 Dec 2018 13:54:03 +0100 Subject: [PATCH 208/347] Remove the "Disable stencil test" hack. Doesn't seem to serve much purpose anymore. --- Core/Config.cpp | 1 - Core/Config.h | 1 - Core/HLE/ReplaceTables.cpp | 2 +- GPU/Common/GPUStateUtils.cpp | 2 +- GPU/Directx9/StateMappingDX9.cpp | 4 +--- GPU/GLES/StateMappingGLES.cpp | 3 +-- UI/GameSettingsScreen.cpp | 3 --- 7 files changed, 4 insertions(+), 12 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index dd8e45681f..5d859b404f 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -654,7 +654,6 @@ static ConfigSetting graphicsSettings[] = { ReportedConfigSetting("TexScalingType", &g_Config.iTexScalingType, 0, true, true), ReportedConfigSetting("TexDeposterize", &g_Config.bTexDeposterize, false, true, true), ConfigSetting("VSyncInterval", &g_Config.bVSync, false, true, true), - ReportedConfigSetting("DisableStencilTest", &g_Config.bDisableStencilTest, false, true, true), ReportedConfigSetting("BloomHack", &g_Config.iBloomHack, 0, true, true), // Not really a graphics setting... diff --git a/Core/Config.h b/Core/Config.h index 311516d769..482882076d 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -184,7 +184,6 @@ public: bool bEnableCheats; bool bReloadCheats; int iCwCheatRefreshRate; - bool bDisableStencilTest; int iBloomHack; //0 = off, 1 = safe, 2 = balanced, 3 = aggressive bool bTimerHack; bool bBlockTransferGPU; diff --git a/Core/HLE/ReplaceTables.cpp b/Core/HLE/ReplaceTables.cpp index dec3f24636..e64adef5fa 100644 --- a/Core/HLE/ReplaceTables.cpp +++ b/Core/HLE/ReplaceTables.cpp @@ -661,7 +661,7 @@ static int Hook_hexyzforce_monoclome_thread() { static int Hook_starocean_write_stencil() { const u32 fb_address = currentMIPS->r[MIPS_REG_T7]; - if (Memory::IsVRAMAddress(fb_address) && !g_Config.bDisableStencilTest) { + if (Memory::IsVRAMAddress(fb_address)) { gpu->PerformStencilUpload(fb_address, 0x00088000); } return 0; diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 1a650028bc..515caa74d9 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -1342,7 +1342,7 @@ static void ConvertStencilFunc5551(GenericStencilFuncState &state) { } void ConvertStencilFuncState(GenericStencilFuncState &state) { - state.enabled = gstate.isStencilTestEnabled() && !g_Config.bDisableStencilTest; + state.enabled = gstate.isStencilTestEnabled(); if (!state.enabled) return; diff --git a/GPU/Directx9/StateMappingDX9.cpp b/GPU/Directx9/StateMappingDX9.cpp index 3a9d8ffb0c..4e46ecdff4 100644 --- a/GPU/Directx9/StateMappingDX9.cpp +++ b/GPU/Directx9/StateMappingDX9.cpp @@ -194,8 +194,6 @@ void DrawEngineDX9::ApplyDrawState(int prim) { } } - bool enableStencilTest = !g_Config.bDisableStencilTest; - if (gstate_c.IsDirty(DIRTY_RASTER_STATE)) { gstate_c.Clean(DIRTY_RASTER_STATE); // Set Dither @@ -231,7 +229,7 @@ void DrawEngineDX9::ApplyDrawState(int prim) { // Stencil Test bool alphaMask = gstate.isClearModeAlphaMask(); - if (alphaMask && enableStencilTest) { + if (alphaMask) { dxstate.stencilTest.enable(); dxstate.stencilOp.set(D3DSTENCILOP_REPLACE, D3DSTENCILOP_REPLACE, D3DSTENCILOP_REPLACE); dxstate.stencilFunc.set(D3DCMP_ALWAYS, 255, 0xFF); diff --git a/GPU/GLES/StateMappingGLES.cpp b/GPU/GLES/StateMappingGLES.cpp index 5a93dbbbb4..e6636b87e2 100644 --- a/GPU/GLES/StateMappingGLES.cpp +++ b/GPU/GLES/StateMappingGLES.cpp @@ -271,13 +271,12 @@ void DrawEngineGLES::ApplyDrawState(int prim) { if (gstate_c.IsDirty(DIRTY_DEPTHSTENCIL_STATE)) { gstate_c.Clean(DIRTY_DEPTHSTENCIL_STATE); - bool enableStencilTest = !g_Config.bDisableStencilTest; if (gstate.isModeClear()) { // Depth Test if (gstate.isClearModeDepthMask()) { framebufferManager_->SetDepthUpdated(); } - renderManager->SetStencilFunc(gstate.isClearModeAlphaMask() && enableStencilTest, GL_ALWAYS, 0xFF, 0xFF); + renderManager->SetStencilFunc(gstate.isClearModeAlphaMask(), GL_ALWAYS, 0xFF, 0xFF); renderManager->SetStencilOp(0xFF, GL_REPLACE, GL_REPLACE, GL_REPLACE); renderManager->SetDepth(true, gstate.isClearModeDepthMask() ? true : false, GL_ALWAYS); } else { diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index c3b98df7a1..752f84caa3 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -467,9 +467,6 @@ void GameSettingsScreen::CreateViews() { return UI::EVENT_CONTINUE; }); - CheckBox *stencilTest = graphicsSettings->Add(new CheckBox(&g_Config.bDisableStencilTest, gr->T("Disable Stencil Test"))); - stencilTest->SetDisabledPtr(&g_Config.bSoftwareRendering); - static const char *bloomHackOptions[] = { "Off", "Safe", "Balanced", "Aggressive" }; PopupMultiChoice *bloomHack = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iBloomHack, gr->T("Lower resolution for effects (reduces artifacts)"), bloomHackOptions, 0, ARRAY_SIZE(bloomHackOptions), gr->GetName(), screenManager())); bloomHackEnable_ = !g_Config.bSoftwareRendering && (g_Config.iInternalResolution != 1); From 0fdea30ac3ba3b0d1a5b35956561e6fffb3f27f0 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 14 Dec 2018 13:56:42 +0100 Subject: [PATCH 209/347] Remove "Timer Hack" setting. Untested, probably low usage and unclear utility. --- Core/Config.cpp | 1 - Core/CoreTiming.cpp | 7 ------- UI/GameSettingsScreen.cpp | 5 ----- 3 files changed, 13 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index dd8e45681f..da6e4c0d74 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -658,7 +658,6 @@ static ConfigSetting graphicsSettings[] = { ReportedConfigSetting("BloomHack", &g_Config.iBloomHack, 0, true, true), // Not really a graphics setting... - ReportedConfigSetting("TimerHack", &g_Config.bTimerHack, &DefaultTimerHack, true, true), ReportedConfigSetting("SplineBezierQuality", &g_Config.iSplineBezierQuality, 2, true, true), ReportedConfigSetting("HardwareTessellation", &g_Config.bHardwareTessellation, false, true, true), ReportedConfigSetting("PostShader", &g_Config.sPostShaderName, "Off", true, true), diff --git a/Core/CoreTiming.cpp b/Core/CoreTiming.cpp index 150f5599ea..0e80ddc3a7 100644 --- a/Core/CoreTiming.cpp +++ b/Core/CoreTiming.cpp @@ -120,15 +120,8 @@ u64 GetGlobalTimeUsScaled() { s64 ticksSinceLast = GetTicks() - lastGlobalTimeTicks; int freq = GetClockFrequencyMHz(); - if (g_Config.bTimerHack) { - float vps; - __DisplayGetVPS(&vps); - if (vps > 4.0f) - freq *= (vps / 59.94f); - } s64 usSinceLast = ticksSinceLast / freq; return lastGlobalTimeUs + usSinceLast; - } u64 GetGlobalTimeUs() diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index c3b98df7a1..643526d6d6 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -461,11 +461,6 @@ void GameSettingsScreen::CreateViews() { #endif graphicsSettings->Add(new ItemHeader(gr->T("Hack Settings", "Hack Settings (these WILL cause glitches)"))); - CheckBox *timerHack = graphicsSettings->Add(new CheckBox(&g_Config.bTimerHack, gr->T("Timer Hack"))); - timerHack->OnClick.Add([=](EventParams &e) { - settingInfo_->Show(gr->T("TimerHack Tip", "Changes game clock based on emu speed, may break games"), e.v); - return UI::EVENT_CONTINUE; - }); CheckBox *stencilTest = graphicsSettings->Add(new CheckBox(&g_Config.bDisableStencilTest, gr->T("Disable Stencil Test"))); stencilTest->SetDisabledPtr(&g_Config.bSoftwareRendering); From 56bc7b1d5275355bd940cc5c24f2370a4d4293e1 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 14 Dec 2018 14:01:08 +0100 Subject: [PATCH 210/347] Remove outdated TrueColor setting. --- Core/Config.cpp | 1 - Core/Config.h | 1 - GPU/Common/FramebufferCommon.cpp | 31 +++++-------------------------- GPU/Common/FramebufferCommon.h | 1 - headless/Headless.cpp | 1 - libretro/libretro.cpp | 3 --- 6 files changed, 5 insertions(+), 33 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index dd8e45681f..baf55ef675 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -645,7 +645,6 @@ static ConfigSetting graphicsSettings[] = { ConfigSetting("ImmersiveMode", &g_Config.bImmersiveMode, false, true, true), ConfigSetting("SustainedPerformanceMode", &g_Config.bSustainedPerformanceMode, false, true, true), - ReportedConfigSetting("TrueColor", &g_Config.bTrueColor, true, true, true), ReportedConfigSetting("ReplaceTextures", &g_Config.bReplaceTextures, true, true, true), ReportedConfigSetting("SaveNewTextures", &g_Config.bSaveNewTextures, false, true, true), ReportedConfigSetting("IgnoreTextureFilenames", &g_Config.bIgnoreTextureFilenames, true, true, false), diff --git a/Core/Config.h b/Core/Config.h index 311516d769..53b20555ad 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -166,7 +166,6 @@ public: int iInternalResolution; // 0 = Auto (native), 1 = 1x (480x272), 2 = 2x, 3 = 3x, 4 = 4x and so on. int iAnisotropyLevel; // 0 - 5, powers of 2: 0 = 1x = no aniso int bHighQualityDepth; - bool bTrueColor; bool bReplaceTextures; bool bSaveNewTextures; bool bIgnoreTextureFilenames; diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index 09b7968a55..7468b2258f 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -148,14 +148,13 @@ void FramebufferManagerCommon::Init() { bool FramebufferManagerCommon::UpdateSize() { const bool newRender = renderWidth_ != (float)PSP_CoreParameter().renderWidth || renderHeight_ != (float)PSP_CoreParameter().renderHeight; - const bool newSettings = bloomHack_ != g_Config.iBloomHack || trueColor_ != g_Config.bTrueColor || useBufferedRendering_ != (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE); + const bool newSettings = bloomHack_ != g_Config.iBloomHack || useBufferedRendering_ != (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE); renderWidth_ = (float)PSP_CoreParameter().renderWidth; renderHeight_ = (float)PSP_CoreParameter().renderHeight; pixelWidth_ = PSP_CoreParameter().pixelWidth; pixelHeight_ = PSP_CoreParameter().pixelHeight; bloomHack_ = g_Config.iBloomHack; - trueColor_ = g_Config.bTrueColor; useBufferedRendering_ = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; return newRender || newSettings; @@ -1151,30 +1150,10 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, SetRenderSize(vfb); - bool trueColor = trueColor_; - if (PSP_CoreParameter().compat.flags().Force04154000Download && vfb->fb_address == 0x00154000) { - trueColor = true; - } - - if (trueColor) { - vfb->colorDepth = Draw::FBO_8888; - } else { - switch (vfb->format) { - case GE_FORMAT_4444: - vfb->colorDepth = Draw::FBO_4444; - break; - case GE_FORMAT_5551: - vfb->colorDepth = Draw::FBO_5551; - break; - case GE_FORMAT_565: - vfb->colorDepth = Draw::FBO_565; - break; - case GE_FORMAT_8888: - default: - vfb->colorDepth = Draw::FBO_8888; - break; - } - } + // During hardware rendering, we always render at full color depth even if the game wouldn't on real hardware. + // It's not worth the trouble trying to support lower bit-depth rendering, just + // more cases to test that nobody will ever use. + vfb->colorDepth = Draw::FBO_8888; textureCache_->ForgetLastTexture(); diff --git a/GPU/Common/FramebufferCommon.h b/GPU/Common/FramebufferCommon.h index 235d319924..9a954c1975 100644 --- a/GPU/Common/FramebufferCommon.h +++ b/GPU/Common/FramebufferCommon.h @@ -404,7 +404,6 @@ protected: int pixelWidth_; int pixelHeight_; int bloomHack_ = 0; - bool trueColor_ = false; // Used by post-processing shaders std::vector extraFBOs_; diff --git a/headless/Headless.cpp b/headless/Headless.cpp index a099118f74..e4bf824602 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -354,7 +354,6 @@ int main(int argc, const char* argv[]) g_Config.bHardwareTransform = true; g_Config.iAnisotropyLevel = 0; // When testing mipmapping we really don't want this. g_Config.bVertexCache = true; - g_Config.bTrueColor = true; g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH; g_Config.iTimeFormat = PSP_SYSTEMPARAM_TIME_FORMAT_24HR; g_Config.bEncryptSave = true; diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index 22615e27f4..7ea47093b9 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -167,7 +167,6 @@ static RetroOption ppsspp_cpu_core("ppsspp_cpu_core", "CPU Core", { { " static RetroOption ppsspp_locked_cpu_speed("ppsspp_locked_cpu_speed", "Locked CPU Speed", { { "off", 0 }, { "222MHz", 222 }, { "266MHz", 266 }, { "333MHz", 333 } }); static RetroOption ppsspp_language("ppsspp_language", "Language", { { "automatic", -1 }, { "english", PSP_SYSTEMPARAM_LANGUAGE_ENGLISH }, { "japanese", PSP_SYSTEMPARAM_LANGUAGE_JAPANESE }, { "french", PSP_SYSTEMPARAM_LANGUAGE_FRENCH }, { "spanish", PSP_SYSTEMPARAM_LANGUAGE_SPANISH }, { "german", PSP_SYSTEMPARAM_LANGUAGE_GERMAN }, { "italian", PSP_SYSTEMPARAM_LANGUAGE_ITALIAN }, { "dutch", PSP_SYSTEMPARAM_LANGUAGE_DUTCH }, { "portuguese", PSP_SYSTEMPARAM_LANGUAGE_PORTUGUESE }, { "russian", PSP_SYSTEMPARAM_LANGUAGE_RUSSIAN }, { "korean", PSP_SYSTEMPARAM_LANGUAGE_KOREAN }, { "chinese_traditional", PSP_SYSTEMPARAM_LANGUAGE_CHINESE_TRADITIONAL }, { "chinese_simplified", PSP_SYSTEMPARAM_LANGUAGE_CHINESE_SIMPLIFIED } }); static RetroOption ppsspp_rendering_mode("ppsspp_rendering_mode", "Rendering Mode", { { "buffered", FB_BUFFERED_MODE }, { "nonbuffered", FB_NON_BUFFERED_MODE } }); -static RetroOption ppsspp_true_color("ppsspp_true_color", "True Color Depth", true); static RetroOption ppsspp_auto_frameskip("ppsspp_auto_frameskip", "Auto Frameskip", false); static RetroOption ppsspp_frameskip("ppsspp_frameskip", "Frameskip", 0, 10); static RetroOption ppsspp_frameskiptype("ppsspp_frameskiptype", "Frameskip Type", 0, 10); @@ -196,7 +195,6 @@ void retro_set_environment(retro_environment_t cb) { vars.push_back(ppsspp_locked_cpu_speed.GetOptions()); vars.push_back(ppsspp_language.GetOptions()); vars.push_back(ppsspp_rendering_mode.GetOptions()); - vars.push_back(ppsspp_true_color.GetOptions()); vars.push_back(ppsspp_auto_frameskip.GetOptions()); vars.push_back(ppsspp_frameskip.GetOptions()); vars.push_back(ppsspp_frameskiptype.GetOptions()); @@ -272,7 +270,6 @@ static void check_variables(CoreParameter &coreParam) { ppsspp_frameskip.Update(&g_Config.iFrameSkip); ppsspp_frameskiptype.Update(&g_Config.iFrameSkipType); ppsspp_audio_latency.Update(&g_Config.iAudioLatency); - ppsspp_true_color.Update(&g_Config.bTrueColor); ppsspp_auto_frameskip.Update(&g_Config.bAutoFrameSkip); ppsspp_block_transfer_gpu.Update(&g_Config.bBlockTransferGPU); ppsspp_texture_filtering.Update(&g_Config.iTexFiltering); From ee88bc79ffcee4cb19a49336533b8dd0ff831f3d Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 14 Dec 2018 16:14:43 +0100 Subject: [PATCH 211/347] Oops, x2 --- Core/Config.h | 1 - Core/Reporting.cpp | 2 -- 2 files changed, 3 deletions(-) diff --git a/Core/Config.h b/Core/Config.h index 311516d769..55cf03b3d2 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -186,7 +186,6 @@ public: int iCwCheatRefreshRate; bool bDisableStencilTest; int iBloomHack; //0 = off, 1 = safe, 2 = balanced, 3 = aggressive - bool bTimerHack; bool bBlockTransferGPU; bool bDisableSlowFramebufEffects; bool bFragmentTestCache; diff --git a/Core/Reporting.cpp b/Core/Reporting.cpp index a927c55510..6aeeadfbc3 100644 --- a/Core/Reporting.cpp +++ b/Core/Reporting.cpp @@ -458,8 +458,6 @@ namespace Reporting bool IsSupported() { // Disabled when using certain hacks, because they make for poor reports. - if (g_Config.bTimerHack) - return false; if (CheatsInEffect()) return false; if (g_Config.iLockedCPUSpeed != 0) From d82ec339eedff71571a32694c31917c0ac7ac076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 15 Dec 2018 10:44:05 +0100 Subject: [PATCH 212/347] Remove the DisableShaderCache setting, rename the other --- Core/Config.cpp | 3 +-- Core/Config.h | 3 +-- GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp | 2 +- GPU/Vulkan/GPU_Vulkan.cpp | 8 ++++---- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 11bb6d597d..3c1773b020 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -605,8 +605,7 @@ static ConfigSetting graphicsSettings[] = { #ifdef _WIN32 ConfigSetting("D3D11Device", &g_Config.sD3D11Device, "", true, false), #endif - ConfigSetting("VendorChecksEnabled", &g_Config.bVendorChecksEnabled, true, false, false), - ConfigSetting("ShaderCacheEnabled", &g_Config.bShaderCacheEnabled, true, false, false), + ConfigSetting("VendorBugChecksEnabled", &g_Config.bVendorBugChecksEnabled, true, false, false), ReportedConfigSetting("RenderingMode", &g_Config.iRenderingMode, &DefaultRenderingMode, true, true), ConfigSetting("SoftwareRenderer", &g_Config.bSoftwareRendering, false, true, true), ReportedConfigSetting("HardwareTransform", &g_Config.bHardwareTransform, true, true, true), diff --git a/Core/Config.h b/Core/Config.h index c36bd2eb43..c020cfd689 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -131,8 +131,7 @@ public: bool bSoftwareRendering; bool bHardwareTransform; // only used in the GLES backend bool bSoftwareSkinning; // may speed up some games - bool bVendorChecksEnabled; - bool bShaderCacheEnabled; + bool bVendorBugChecksEnabled; int iRenderingMode; // 0 = non-buffered rendering 1 = buffered rendering int iTexFiltering; // 1 = off , 2 = nearest , 3 = linear , 4 = linear(CG) diff --git a/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp b/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp index 2250a70f47..92196f2a1e 100644 --- a/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp @@ -88,7 +88,7 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_ // TODO: This is a bug affecting shader cache generality - we CANNOT check anything but the shader ID and (indirectly) the game ID in here really. // Need to move this check somehow to the shader ID generator. That's tricky though because it's generic... - bool isAdreno = vulkanVendorId == VULKAN_VENDOR_QUALCOMM && g_Config.bVendorChecksEnabled; + bool isAdreno = vulkanVendorId == VULKAN_VENDOR_QUALCOMM && g_Config.bVendorBugChecksEnabled; if (earlyFragmentTests) { WRITE(p, "layout (early_fragment_tests) in;\n"); diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 2b95a8ea46..b41eff7888 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -101,7 +101,7 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw) // Load shader cache. std::string discID = g_paramSFO.GetDiscID(); - if (discID.size() && g_Config.bShaderCacheEnabled) { + if (discID.size()) { File::CreateFullPath(GetSysDirectory(DIRECTORY_APP_CACHE)); shaderCachePath_ = GetSysDirectory(DIRECTORY_APP_CACHE) + "/" + discID + ".vkshadercache"; shaderCacheLoaded_ = false; @@ -202,7 +202,7 @@ void GPU_Vulkan::CheckGPUFeatures() { } // Might enable this later - in the first round we are mostly looking at depth/stencil/discard. - // if (g_Config.bDisableVendorChecks) + // if (g_Config.bDisableVendorBugChecks) // features |= GPU_SUPPORTS_ACCURATE_DEPTH; // Mandatory features on Vulkan, which may be checked in "centralized" code @@ -239,7 +239,7 @@ void GPU_Vulkan::CheckGPUFeatures() { features |= GPU_SUPPORTS_DUALSOURCE_BLEND; break; } - if (!g_Config.bVendorChecksEnabled) + if (!g_Config.bVendorBugChecksEnabled) features |= GPU_SUPPORTS_DUALSOURCE_BLEND; } if (vulkan_->GetFeaturesEnabled().logicOp) { @@ -507,7 +507,7 @@ void GPU_Vulkan::DeviceLost() { while (!IsReady()) { sleep_ms(10); } - if (!shaderCachePath_.empty() && g_Config.bShaderCacheEnabled) { + if (!shaderCachePath_.empty()) { SaveCache(shaderCachePath_); } DestroyDeviceObjects(); From 8a7ec4fc1911a2803e18998353e8ac87cf53a570 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 16 Dec 2018 13:00:36 -0800 Subject: [PATCH 213/347] GPU: Fix curve breakage due to cull flipping. --- GPU/Common/DrawEngineCommon.h | 4 ++-- GPU/Common/SplineCommon.cpp | 2 +- GPU/GPUCommon.cpp | 2 +- GPU/Null/NullGpu.cpp | 2 +- GPU/Software/TransformUnit.cpp | 3 ++- GPU/Software/TransformUnit.h | 4 ++-- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 0d16cf5fae..362a0ce712 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -75,8 +75,8 @@ public: // This would seem to be unnecessary now, but is still required for splines/beziers to work in the software backend since SubmitPrim // is different. Should probably refactor that. // Note that vertTypeID should be computed using GetVertTypeID(). - virtual void DispatchSubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, int *bytesRead) { - SubmitPrim(verts, inds, prim, vertexCount, vertTypeID, -1, bytesRead); + virtual void DispatchSubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, int cullMode, int *bytesRead) { + SubmitPrim(verts, inds, prim, vertexCount, vertTypeID, cullMode, bytesRead); } bool TestBoundingBox(void* control_points, int vertexCount, u32 vertType, int *bytesRead); diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 73104649e5..0e10a4e8ec 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -562,7 +562,7 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic uint32_t vertTypeID = GetVertTypeID(vertTypeWithIndex16, gstate.getUVGenMode()); int generatedBytesRead; - DispatchSubmitPrim(output.vertices, output.indices, PatchPrimToPrim(surface.primType), output.count, vertTypeID, &generatedBytesRead); + DispatchSubmitPrim(output.vertices, output.indices, PatchPrimToPrim(surface.primType), output.count, vertTypeID, gstate.getCullMode(), &generatedBytesRead); DispatchFlush(); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 09389ddccb..ef11d91974 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -2237,7 +2237,7 @@ void GPUCommon::FlushImm() { int bytesRead; uint32_t vertTypeID = GetVertTypeID(vtype, 0); - drawEngineCommon_->DispatchSubmitPrim(temp, nullptr, immPrim_, immCount_, vertTypeID, &bytesRead); + drawEngineCommon_->DispatchSubmitPrim(temp, nullptr, immPrim_, immCount_, vertTypeID, gstate.getCullMode(), &bytesRead); drawEngineCommon_->DispatchFlush(); // TOOD: In the future, make a special path for these. // drawEngineCommon_->DispatchSubmitImm(immBuffer_, immCount_); diff --git a/GPU/Null/NullGpu.cpp b/GPU/Null/NullGpu.cpp index c4b345d96e..34f6b1d77d 100644 --- a/GPU/Null/NullGpu.cpp +++ b/GPU/Null/NullGpu.cpp @@ -29,7 +29,7 @@ class NullDrawEngine : public DrawEngineCommon { public: void DispatchFlush() override { } - void DispatchSubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, int *bytesRead) override { + void DispatchSubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, int cullMode, int *bytesRead) override { } }; diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index c7799eaf3e..5baf3a3b42 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -52,7 +52,8 @@ SoftwareDrawEngine::~SoftwareDrawEngine() { void SoftwareDrawEngine::DispatchFlush() { } -void SoftwareDrawEngine::DispatchSubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, int *bytesRead) { +void SoftwareDrawEngine::DispatchSubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, int cullMode, int *bytesRead) { + _assert_msg_(G3D, cullMode == gstate.getCullMode(), "Mixed cull mode not supported."); transformUnit.SubmitPrimitive(verts, inds, prim, vertexCount, vertTypeID, bytesRead, this); } diff --git a/GPU/Software/TransformUnit.h b/GPU/Software/TransformUnit.h index 68beaab5e1..70c75fadd8 100644 --- a/GPU/Software/TransformUnit.h +++ b/GPU/Software/TransformUnit.h @@ -144,9 +144,9 @@ public: ~SoftwareDrawEngine(); void DispatchFlush() override; - void DispatchSubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int *bytesRead) override; + void DispatchSubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int cullMode, int *bytesRead) override; VertexDecoder *FindVertexDecoder(u32 vtype); TransformUnit transformUnit; -}; \ No newline at end of file +}; From 0f880696bed73db661b6244abccab3ea7e8351bd Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 16 Dec 2018 13:13:54 -0800 Subject: [PATCH 214/347] SoftGPU: Respect stencil write mask on test fail. --- GPU/GPUState.h | 1 + GPU/Software/Rasterizer.cpp | 17 +++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/GPU/GPUState.h b/GPU/GPUState.h index a3e2e4e9d4..5a119aa680 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -252,6 +252,7 @@ struct GPUgstate { // Color Mask u32 getColorMask() const { return (pmskc & 0xFFFFFF) | ((pmska & 0xFF) << 24); } + u8 getStencilWriteMask() const { return pmska & 0xFF; } bool isLogicOpEnabled() const { return logicOpEnable & 1; } GELogicOp getLogicOp() const { return static_cast(lop & 0xF); } diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index f210325a96..3b04e93396 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -423,32 +423,33 @@ static inline bool StencilTestPassed(u8 stencil) static inline u8 ApplyStencilOp(int op, u8 old_stencil) { // TODO: Apply mask to reference or old stencil? u8 reference_stencil = gstate.getStencilTestRef(); // TODO: Apply mask? + const u8 write_mask = gstate.getStencilWriteMask(); switch (op) { case GE_STENCILOP_KEEP: return old_stencil; case GE_STENCILOP_ZERO: - return 0; + return old_stencil & write_mask; case GE_STENCILOP_REPLACE: - return reference_stencil; + return (reference_stencil & ~write_mask) | (old_stencil & write_mask); case GE_STENCILOP_INVERT: - return ~old_stencil; + return (~old_stencil & ~write_mask) | (old_stencil & write_mask); case GE_STENCILOP_INCR: switch (gstate.FrameBufFormat()) { case GE_FORMAT_8888: if (old_stencil != 0xFF) { - return old_stencil + 1; + return ((old_stencil + 1) & ~write_mask) | (old_stencil & write_mask); } return old_stencil; case GE_FORMAT_5551: - return 0xFF; + return ~write_mask | (old_stencil & write_mask); case GE_FORMAT_4444: if (old_stencil < 0xF0) { - return old_stencil + 0x10; + return ((old_stencil + 0x10) & ~write_mask) | (old_stencil & write_mask); } return old_stencil; default: @@ -460,11 +461,11 @@ static inline u8 ApplyStencilOp(int op, u8 old_stencil) { switch (gstate.FrameBufFormat()) { case GE_FORMAT_4444: if (old_stencil >= 0x10) - return old_stencil - 0x10; + return ((old_stencil - 0x10) & ~write_mask) | (old_stencil & write_mask); break; default: if (old_stencil != 0) - return old_stencil - 1; + return ((old_stencil - 1) & ~write_mask) | (old_stencil & write_mask); return old_stencil; } break; From aa3b026bfe666dedb7f2911656ae59e4065d60b3 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 16 Dec 2018 13:16:05 -0800 Subject: [PATCH 215/347] SoftGPU: Fix crash on garbage index data. --- GPU/Software/TransformUnit.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index c7799eaf3e..f6e8d6868c 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -581,12 +581,16 @@ bool TransformUnit::GetCurrentSimpleVertices(int count, std::vector temp_buffer; static std::vector simpleVertices; - temp_buffer.resize(65536 * 24 / sizeof(u32)); + temp_buffer.resize(std::max((int)indexUpperBound, 8192) * 128 / sizeof(u32)); simpleVertices.resize(indexUpperBound + 1); VertexDecoder vdecoder; VertexDecoderOptions options{}; vdecoder.SetVertexType(gstate.vertType, options); + + if (!Memory::IsValidRange(gstate_c.vertexAddr, (indexUpperBound + 1) * vdecoder.VertexSize())) + return false; + DrawEngineCommon::NormalizeVertices((u8 *)(&simpleVertices[0]), (u8 *)(&temp_buffer[0]), Memory::GetPointer(gstate_c.vertexAddr), &vdecoder, indexLowerBound, indexUpperBound, gstate.vertType); float world[16]; From 57767ba1f866799c565086db291940b57bdca71c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 16 Dec 2018 13:21:10 -0800 Subject: [PATCH 216/347] GLES: Use depth textures where possible. --- ext/native/thin3d/GLQueueRunner.cpp | 111 ++++++++++++++++---------- ext/native/thin3d/GLRenderManager.cpp | 6 +- ext/native/thin3d/GLRenderManager.h | 4 +- 3 files changed, 78 insertions(+), 43 deletions(-) diff --git a/ext/native/thin3d/GLQueueRunner.cpp b/ext/native/thin3d/GLQueueRunner.cpp index 02bfc979b1..96d117f053 100644 --- a/ext/native/thin3d/GLQueueRunner.cpp +++ b/ext/native/thin3d/GLQueueRunner.cpp @@ -388,31 +388,56 @@ void GLQueueRunner::InitCreateFramebuffer(const GLRInitStep &step) { #endif CHECK_GL_ERROR_IF_DEBUG(); + auto initFBOTexture = [&](GLRTexture &tex, GLint internalFormat, GLenum format, GLenum type, bool linear) { + glGenTextures(1, &tex.texture); + tex.target = GL_TEXTURE_2D; + tex.maxLod = 0.0f; + + // Create the surfaces. + glBindTexture(GL_TEXTURE_2D, tex.texture); + glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, fbo->width, fbo->height, 0, format, type, nullptr); + + tex.wrapS = GL_CLAMP_TO_EDGE; + tex.wrapT = GL_CLAMP_TO_EDGE; + tex.magFilter = linear ? GL_LINEAR : GL_NEAREST; + tex.minFilter = linear ? GL_LINEAR : GL_NEAREST; + tex.canWrap = isPowerOf2(fbo->width) && isPowerOf2(fbo->height); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, tex.wrapS); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, tex.wrapT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, tex.magFilter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, tex.minFilter); + if (!gl_extensions.IsGLES || gl_extensions.GLES3) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + } + }; + // Color texture is same everywhere glGenFramebuffers(1, &fbo->handle); - glGenTextures(1, &fbo->color_texture.texture); - fbo->color_texture.target = GL_TEXTURE_2D; - fbo->color_texture.maxLod = 0.0f; - - // Create the surfaces. - glBindTexture(GL_TEXTURE_2D, fbo->color_texture.texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fbo->width, fbo->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - - fbo->color_texture.wrapS = GL_CLAMP_TO_EDGE; - fbo->color_texture.wrapT = GL_CLAMP_TO_EDGE; - fbo->color_texture.magFilter = GL_LINEAR; - fbo->color_texture.minFilter = GL_LINEAR; - fbo->color_texture.canWrap = isPowerOf2(fbo->width) && isPowerOf2(fbo->height); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, fbo->color_texture.wrapS); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, fbo->color_texture.wrapT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, fbo->color_texture.magFilter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, fbo->color_texture.minFilter); - if (!gl_extensions.IsGLES || gl_extensions.GLES3) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); - } + initFBOTexture(fbo->color_texture, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, true); if (gl_extensions.IsGLES) { - if (gl_extensions.OES_packed_depth_stencil) { + if (gl_extensions.OES_packed_depth_stencil && (gl_extensions.OES_depth_texture || gl_extensions.GLES3)) { + ILOG("Creating %i x %i FBO using DEPTH24_STENCIL8 texture", fbo->width, fbo->height); + fbo->z_stencil_buffer = 0; + fbo->stencil_buffer = 0; + fbo->z_buffer = 0; + + if (gl_extensions.GLES3) { + initFBOTexture(fbo->z_stencil_texture, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, false); + } else { + initFBOTexture(fbo->z_stencil_texture, GL_DEPTH_STENCIL, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, false); + } + + // Bind it all together + glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture.texture, 0); + if (gl_extensions.GLES3) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, fbo->z_stencil_texture.texture, 0); + } else { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, fbo->z_stencil_texture.texture, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, fbo->z_stencil_texture.texture, 0); + } + } else if (gl_extensions.OES_packed_depth_stencil) { ILOG("Creating %i x %i FBO using DEPTH24_STENCIL8", fbo->width, fbo->height); // Standard method fbo->stencil_buffer = 0; @@ -448,6 +473,18 @@ void GLQueueRunner::InitCreateFramebuffer(const GLRInitStep &step) { glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo->z_buffer); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->stencil_buffer); } + } else if (gl_extensions.VersionGEThan(3, 0)) { + ILOG("Creating %i x %i FBO using DEPTH24_STENCIL8 texture", fbo->width, fbo->height); + fbo->z_stencil_buffer = 0; + fbo->stencil_buffer = 0; + fbo->z_buffer = 0; + + initFBOTexture(fbo->z_stencil_texture, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, false); + + // Bind it all together + glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture.texture, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, fbo->z_stencil_texture.texture, 0); } else { fbo->stencil_buffer = 0; fbo->z_buffer = 0; @@ -472,7 +509,7 @@ void GLQueueRunner::InitCreateFramebuffer(const GLRInitStep &step) { ELOG("GL_FRAMEBUFFER_UNSUPPORTED"); break; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - ELOG("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT "); + ELOG("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"); break; default: FLOG("Other framebuffer error: %i", status); @@ -1458,36 +1495,30 @@ GLRFramebuffer::~GLRFramebuffer() { return; CHECK_GL_ERROR_IF_DEBUG(); - if (gl_extensions.ARB_framebuffer_object || gl_extensions.IsGLES) { - if (handle) { + if (handle) { + if (gl_extensions.ARB_framebuffer_object || gl_extensions.IsGLES) { glBindFramebuffer(GL_FRAMEBUFFER, handle); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, g_defaultFBO); glDeleteFramebuffers(1, &handle); - } - if (z_stencil_buffer) - glDeleteRenderbuffers(1, &z_stencil_buffer); - if (z_buffer) - glDeleteRenderbuffers(1, &z_buffer); - if (stencil_buffer) - glDeleteRenderbuffers(1, &stencil_buffer); - } else if (gl_extensions.EXT_framebuffer_object) { #ifndef USING_GLES2 - if (handle) { + } else if (gl_extensions.EXT_framebuffer_object) { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, handle); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER_EXT, 0); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, g_defaultFBO); glDeleteFramebuffersEXT(1, &handle); - } - if (z_stencil_buffer) - glDeleteRenderbuffers(1, &z_stencil_buffer); - if (z_buffer) - glDeleteRenderbuffers(1, &z_buffer); - if (stencil_buffer) - glDeleteRenderbuffers(1, &stencil_buffer); #endif + } } + + // These can only be set when supported. + if (z_stencil_buffer) + glDeleteRenderbuffers(1, &z_stencil_buffer); + if (z_buffer) + glDeleteRenderbuffers(1, &z_buffer); + if (stencil_buffer) + glDeleteRenderbuffers(1, &stencil_buffer); CHECK_GL_ERROR_IF_DEBUG(); } diff --git a/ext/native/thin3d/GLRenderManager.cpp b/ext/native/thin3d/GLRenderManager.cpp index 56317029f4..bc9defccad 100644 --- a/ext/native/thin3d/GLRenderManager.cpp +++ b/ext/native/thin3d/GLRenderManager.cpp @@ -61,10 +61,12 @@ void GLDeleter::Perform(GLRenderManager *renderManager, bool skipGLCalls) { inputLayouts.clear(); for (auto framebuffer : framebuffers) { if (skipGLCalls) { + framebuffer->handle = 0; + framebuffer->color_texture.texture = 0; + framebuffer->z_stencil_buffer = 0; + framebuffer->z_stencil_texture.texture = 0; framebuffer->z_buffer = 0; framebuffer->stencil_buffer = 0; - framebuffer->z_stencil_buffer = 0; - framebuffer->handle = 0; } delete framebuffer; } diff --git a/ext/native/thin3d/GLRenderManager.h b/ext/native/thin3d/GLRenderManager.h index 9cc4ca4f7d..719ad156e6 100644 --- a/ext/native/thin3d/GLRenderManager.h +++ b/ext/native/thin3d/GLRenderManager.h @@ -52,7 +52,9 @@ public: GLuint handle = 0; GLRTexture color_texture; - GLuint z_stencil_buffer = 0; // Either this is set, or the two below. + // Either z_stencil_texture, z_stencil_buffer, or (z_buffer and stencil_buffer) are set. + GLuint z_stencil_buffer = 0; + GLRTexture z_stencil_texture; GLuint z_buffer = 0; GLuint stencil_buffer = 0; From 2dc3912d0a9f0366e4ac0663a7ce77035b4b64d5 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 16 Dec 2018 13:28:48 -0800 Subject: [PATCH 217/347] GLES: Actually support depthless FBOs. We use these for temp buffers. This might at least save some VRAM. --- ext/native/thin3d/GLQueueRunner.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/ext/native/thin3d/GLQueueRunner.cpp b/ext/native/thin3d/GLQueueRunner.cpp index 96d117f053..6ecae517a1 100644 --- a/ext/native/thin3d/GLQueueRunner.cpp +++ b/ext/native/thin3d/GLQueueRunner.cpp @@ -415,7 +415,20 @@ void GLQueueRunner::InitCreateFramebuffer(const GLRInitStep &step) { glGenFramebuffers(1, &fbo->handle); initFBOTexture(fbo->color_texture, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, true); - if (gl_extensions.IsGLES) { +retry_depth: + if (!fbo->z_stencil_) { + ILOG("Creating %i x %i FBO using no depth", fbo->width, fbo->height); + + fbo->z_stencil_buffer = 0; + fbo->stencil_buffer = 0; + fbo->z_buffer = 0; + + // Bind it all together + glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture.texture, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0); + } else if (gl_extensions.IsGLES) { if (gl_extensions.OES_packed_depth_stencil && (gl_extensions.OES_depth_texture || gl_extensions.GLES3)) { ILOG("Creating %i x %i FBO using DEPTH24_STENCIL8 texture", fbo->width, fbo->height); fbo->z_stencil_buffer = 0; @@ -501,6 +514,13 @@ void GLQueueRunner::InitCreateFramebuffer(const GLRInitStep &step) { } GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE && !fbo->z_buffer) { + CHECK_GL_ERROR_IF_DEBUG(); + // Uh oh, maybe we need a z/stencil. Platforms sometimes, right? + fbo->z_stencil_ = true; + goto retry_depth; + } + switch (status) { case GL_FRAMEBUFFER_COMPLETE: // ILOG("Framebuffer verified complete."); From e49568f67d7c04db725df17123f499f6fe02dd08 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 16 Dec 2018 14:48:33 -0800 Subject: [PATCH 218/347] GLES: Move depth packing code to dedicated file. --- CMakeLists.txt | 1 + GPU/GLES/DepthBufferGLES.cpp | 64 +++++++++++++++++++++++++++++ GPU/GLES/FramebufferManagerGLES.cpp | 42 ------------------- GPU/GPU.vcxproj | 1 + GPU/GPU.vcxproj.filters | 3 ++ android/jni/Android.mk | 1 + libretro/Makefile.common | 1 + 7 files changed, 71 insertions(+), 42 deletions(-) create mode 100644 GPU/GLES/DepthBufferGLES.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e27986c643..4394ff27c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1223,6 +1223,7 @@ endif() set(GPU_GLES GPU/GLES/DepalettizeShaderGLES.cpp GPU/GLES/DepalettizeShaderGLES.h + GPU/GLES/DepthBufferGLES.cpp GPU/GLES/GPU_GLES.cpp GPU/GLES/GPU_GLES.h GPU/GLES/FragmentShaderGeneratorGLES.cpp diff --git a/GPU/GLES/DepthBufferGLES.cpp b/GPU/GLES/DepthBufferGLES.cpp new file mode 100644 index 0000000000..d142f8b9a4 --- /dev/null +++ b/GPU/GLES/DepthBufferGLES.cpp @@ -0,0 +1,64 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include + +#include "Core/Reporting.h" +#include "GPU/Common/GPUStateUtils.h" +#include "GPU/GLES/FramebufferManagerGLES.h" + +void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h) { + if (!vfb->fbo) { + ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "PackDepthbuffer: vfb->fbo == 0"); + return; + } + + // Pixel size always 4 here because we always request float + const u32 bufSize = vfb->z_stride * (h - y) * 4; + const u32 z_address = vfb->z_address; + const int packWidth = std::min(vfb->z_stride, std::min(x + w, (int)vfb->width)); + + if (!convBuf_ || convBufSize_ < bufSize) { + delete[] convBuf_; + convBuf_ = new u8[bufSize]; + convBufSize_ = bufSize; + } + + DEBUG_LOG(FRAMEBUF, "Reading depthbuffer to mem at %08x for vfb=%08x", z_address, vfb->fb_address); + + draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_DEPTH_BIT, 0, y, packWidth, h, Draw::DataFormat::D32F, convBuf_, vfb->z_stride); + + int dstByteOffset = y * vfb->z_stride * sizeof(u16); + u16 *depth = (u16 *)Memory::GetPointer(z_address + dstByteOffset); + GLfloat *packed = (GLfloat *)convBuf_; + + int totalPixels = h == 1 ? packWidth : vfb->z_stride * h; + for (int yp = 0; yp < h; ++yp) { + int row_offset = vfb->z_stride * yp; + for (int xp = 0; xp < packWidth; ++xp) { + const int i = row_offset + xp; + float scaled = FromScaledDepth(packed[i]); + if (scaled <= 0.0f) { + depth[i] = 0; + } else if (scaled >= 65535.0f) { + depth[i] = 65535; + } else { + depth[i] = (int)scaled; + } + } + } +} diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 780735da13..144ca24dc7 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -650,48 +650,6 @@ void FramebufferManagerGLES::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE); } -void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h) { - if (!vfb->fbo) { - ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "PackDepthbuffer: vfb->fbo == 0"); - return; - } - - // Pixel size always 4 here because we always request float - const u32 bufSize = vfb->z_stride * (h - y) * 4; - const u32 z_address = (0x04000000) | vfb->z_address; - const int packWidth = std::min(vfb->z_stride, std::min(x + w, (int)vfb->width)); - - if (!convBuf_ || convBufSize_ < bufSize) { - delete [] convBuf_; - convBuf_ = new u8[bufSize]; - convBufSize_ = bufSize; - } - - DEBUG_LOG(FRAMEBUF, "Reading depthbuffer to mem at %08x for vfb=%08x", z_address, vfb->fb_address); - - draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_DEPTH_BIT, 0, y, packWidth, h, Draw::DataFormat::D32F, convBuf_, vfb->z_stride); - - int dstByteOffset = y * vfb->z_stride * sizeof(u16); - u16 *depth = (u16 *)Memory::GetPointer(z_address + dstByteOffset); - GLfloat *packed = (GLfloat *)convBuf_; - - int totalPixels = h == 1 ? packWidth : vfb->z_stride * h; - for (int yp = 0; yp < h; ++yp) { - int row_offset = vfb->z_stride * yp; - for (int xp = 0; xp < packWidth; ++xp) { - const int i = row_offset + xp; - float scaled = FromScaledDepth(packed[i]); - if (scaled <= 0.0f) { - depth[i] = 0; - } else if (scaled >= 65535.0f) { - depth[i] = 65535; - } else { - depth[i] = (int)scaled; - } - } - } -} - void FramebufferManagerGLES::EndFrame() { } diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index c3f2a1aa10..13264c837c 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -339,6 +339,7 @@ + diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index 1710c3f790..76b0113d10 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -548,5 +548,8 @@ Debugger + + GLES + \ No newline at end of file diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 1ed3b4eb69..7e5d2829d6 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -247,6 +247,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/GPU/Debugger/Stepping.cpp \ $(SRC)/GPU/GLES/FramebufferManagerGLES.cpp \ $(SRC)/GPU/GLES/DepalettizeShaderGLES.cpp \ + $(SRC)/GPU/GLES/DepthBufferGLES.cpp.arm \ $(SRC)/GPU/GLES/GPU_GLES.cpp.arm \ $(SRC)/GPU/GLES/StencilBufferGLES.cpp.arm \ $(SRC)/GPU/GLES/TextureCacheGLES.cpp.arm \ diff --git a/libretro/Makefile.common b/libretro/Makefile.common index f127fab167..44d56478e3 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -188,6 +188,7 @@ SOURCES_CXX += \ $(GPUDIR)/Software/Lighting.cpp \ $(GPUDIR)/Software/Rasterizer.cpp \ $(GPUDIR)/GLES/DepalettizeShaderGLES.cpp \ + $(GPUDIR)/GLES/DepthBufferGLES.cpp \ $(GPUDIR)/GLES/VertexShaderGeneratorGLES.cpp \ $(GPUDIR)/GLES/DrawEngineGLES.cpp \ $(GPUDIR)/GLES/GPU_GLES.cpp \ From 27e8720e14b268307a48e68487d917063703854e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 16 Dec 2018 17:32:31 -0800 Subject: [PATCH 219/347] GLES: Download depth values via shader. Working on desktop, but not on mobile... --- GPU/GLES/DepthBufferGLES.cpp | 147 +++++++++++++++++++++++++--- GPU/GLES/FramebufferManagerGLES.cpp | 4 + GPU/GLES/FramebufferManagerGLES.h | 4 + GPU/GLES/StencilBufferGLES.cpp | 3 +- ext/native/thin3d/GLQueueRunner.cpp | 9 +- 5 files changed, 150 insertions(+), 17 deletions(-) diff --git a/GPU/GLES/DepthBufferGLES.cpp b/GPU/GLES/DepthBufferGLES.cpp index d142f8b9a4..16bd8568a7 100644 --- a/GPU/GLES/DepthBufferGLES.cpp +++ b/GPU/GLES/DepthBufferGLES.cpp @@ -16,10 +16,58 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include - +#include "gfx_es2/gpu_features.h" +#include "Core/ConfigValues.h" #include "Core/Reporting.h" #include "GPU/Common/GPUStateUtils.h" +#include "GPU/GLES/DrawEngineGLES.h" #include "GPU/GLES/FramebufferManagerGLES.h" +#include "GPU/GLES/ShaderManagerGLES.h" +#include "GPU/GLES/TextureCacheGLES.h" + +static const char *depth_dl_fs = R"( +#ifdef GL_ES +precision highp float; +#endif +#if __VERSION__ >= 130 +#define varying in +#define texture2D texture +#define gl_FragColor fragColor0 +out vec4 fragColor0; +#endif +varying vec2 v_texcoord0; +uniform float u_depthScaleFactor; +uniform sampler2D tex; +void main() { + float depth = texture2D(tex, v_texcoord0).r; + float offset = 0.5 * (u_depthScaleFactor - 1.0) * (1.0 / u_depthScaleFactor); + // At this point, clamped maps [0, 1] to [0, 65535]. + float clamped = clamp((depth - offset) * u_depthScaleFactor, 0.0, 1.0); + + vec4 enc = vec4(16777215.0, 16777215.0 / 256.0, 16777215.0 / 65536.0, 16777215.0 / 16777216.0) * clamped; + enc = floor(mod(enc, 256.0)); + enc = enc * vec4(1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0); + // Let's ignore the bits outside 16 bit precision. + gl_FragColor = enc.yzww; +} +)"; + +static const char *depth_vs = R"( +#ifdef GL_ES +precision highp float; +#endif +#if __VERSION__ >= 130 +#define attribute in +#define varying out +#endif +attribute vec4 a_position; +attribute vec2 a_texcoord0; +varying vec2 v_texcoord0; +void main() { + v_texcoord0 = a_texcoord0; + gl_Position = a_position; +} +)"; void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h) { if (!vfb->fbo) { @@ -40,25 +88,96 @@ void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int DEBUG_LOG(FRAMEBUF, "Reading depthbuffer to mem at %08x for vfb=%08x", z_address, vfb->fb_address); - draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_DEPTH_BIT, 0, y, packWidth, h, Draw::DataFormat::D32F, convBuf_, vfb->z_stride); + // TODO: On desktop, we can just directly download, but for now testing. + const bool useColorPath = true; // gl_extensions.IsGLES; + bool format16Bit = false; + + if (useColorPath) { + if (!depthDownloadProgram_) { + std::string errorString; + static std::string vs_code, fs_code; + vs_code = ApplyGLSLPrelude(depth_vs, GL_VERTEX_SHADER); + fs_code = ApplyGLSLPrelude(depth_dl_fs, GL_FRAGMENT_SHADER); + std::vector shaders; + shaders.push_back(render_->CreateShader(GL_VERTEX_SHADER, vs_code, "depth_dl")); + shaders.push_back(render_->CreateShader(GL_FRAGMENT_SHADER, fs_code, "depth_dl")); + std::vector semantics; + semantics.push_back({ 0, "a_position" }); + semantics.push_back({ 1, "a_texcoord0" }); + std::vector queries; + queries.push_back({ &u_depthDownloadTex, "tex" }); + queries.push_back({ &u_depthDownloadFactor, "u_depthScaleFactor" }); + std::vector inits; + inits.push_back({ &u_depthDownloadTex, 0, TEX_SLOT_PSP_TEXTURE }); + depthDownloadProgram_ = render_->CreateProgram(shaders, semantics, queries, inits, false); + for (auto iter : shaders) { + render_->DeleteShader(iter); + } + if (!depthDownloadProgram_) { + ERROR_LOG_REPORT(G3D, "Failed to compile depthDownloadProgram! This shouldn't happen.\n%s", errorString.c_str()); + } + } + + shaderManagerGL_->DirtyLastShader(); + auto *blitFBO = GetTempFBO(TempFBO::COPY, vfb->renderWidth, vfb->renderHeight, Draw::FBO_8888); + draw_->BindFramebufferAsRenderTarget(blitFBO, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }); + render_->SetViewport({ 0, 0, (float)vfb->renderWidth, (float)vfb->renderHeight, 0.0f, 1.0f }); + textureCacheGL_->ForgetLastTexture(); + + // We must bind the program after starting the render pass, and set the color mask after clearing. + render_->SetScissor({ 0, 0, vfb->renderWidth, vfb->renderHeight }); + render_->SetDepth(false, false, GL_ALWAYS); + render_->SetRaster(false, GL_CCW, GL_FRONT, GL_FALSE); + render_->BindProgram(depthDownloadProgram_); + + if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { + render_->SetUniformF1(&u_depthDownloadFactor, 1.0f); + } else { + render_->SetUniformF1(&u_depthDownloadFactor, DepthSliceFactor()); + } + draw_->BindFramebufferAsTexture(vfb->fbo, TEX_SLOT_PSP_TEXTURE, Draw::FB_DEPTH_BIT, 0); + float u1 = 1.0f; + float v1 = 1.0f; + DrawActiveTexture(x, y, w, h, vfb->renderWidth, vfb->renderHeight, 0.0f, 0.0f, u1, v1, ROTATION_LOCKED_HORIZONTAL, DRAWTEX_NEAREST); + + draw_->CopyFramebufferToMemorySync(blitFBO, Draw::FB_COLOR_BIT, 0, y, packWidth, h, Draw::DataFormat::R8G8B8A8_UNORM, convBuf_, vfb->z_stride); + // TODO: Use 4444 so we can copy lines directly? + format16Bit = true; + } else { + draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_DEPTH_BIT, 0, y, packWidth, h, Draw::DataFormat::D32F, convBuf_, vfb->z_stride); + format16Bit = false; + } int dstByteOffset = y * vfb->z_stride * sizeof(u16); u16 *depth = (u16 *)Memory::GetPointer(z_address + dstByteOffset); - GLfloat *packed = (GLfloat *)convBuf_; + u32_le *packed32 = (u32_le *)convBuf_; + GLfloat *packedf = (GLfloat *)convBuf_; int totalPixels = h == 1 ? packWidth : vfb->z_stride * h; - for (int yp = 0; yp < h; ++yp) { - int row_offset = vfb->z_stride * yp; - for (int xp = 0; xp < packWidth; ++xp) { - const int i = row_offset + xp; - float scaled = FromScaledDepth(packed[i]); - if (scaled <= 0.0f) { - depth[i] = 0; - } else if (scaled >= 65535.0f) { - depth[i] = 65535; - } else { - depth[i] = (int)scaled; + if (format16Bit) { + for (int yp = 0; yp < h; ++yp) { + int row_offset = vfb->z_stride * yp; + for (int xp = 0; xp < packWidth; ++xp) { + const int i = row_offset + xp; + depth[i] = packed32[i] & 0xFFFF; + } + } + } else { + for (int yp = 0; yp < h; ++yp) { + int row_offset = vfb->z_stride * yp; + for (int xp = 0; xp < packWidth; ++xp) { + const int i = row_offset + xp; + float scaled = FromScaledDepth(packedf[i]); + if (scaled <= 0.0f) { + depth[i] = 0; + } else if (scaled >= 65535.0f) { + depth[i] = 65535; + } else { + depth[i] = (int)scaled; + } } } } + + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE); } diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 144ca24dc7..6d9887b422 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -324,6 +324,10 @@ void FramebufferManagerGLES::DestroyDeviceObjects() { render_->DeleteProgram(stencilUploadProgram_); stencilUploadProgram_ = nullptr; } + if (depthDownloadProgram_) { + render_->DeleteProgram(depthDownloadProgram_); + depthDownloadProgram_ = nullptr; + } } FramebufferManagerGLES::~FramebufferManagerGLES() { diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index 8c0be0ac1e..db10d01583 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -103,6 +103,10 @@ private: int u_stencilUploadTex = -1; int u_stencilValue = -1; int u_postShaderTex = -1; + + GLRProgram *depthDownloadProgram_ = nullptr; + int u_depthDownloadTex = -1; + int u_depthDownloadFactor = -1; // Cached uniform locs int u_draw2d_tex = -1; diff --git a/GPU/GLES/StencilBufferGLES.cpp b/GPU/GLES/StencilBufferGLES.cpp index 17d7469dfa..164e7ae6d0 100644 --- a/GPU/GLES/StencilBufferGLES.cpp +++ b/GPU/GLES/StencilBufferGLES.cpp @@ -20,6 +20,7 @@ #include "Core/ConfigValues.h" #include "Core/Reporting.h" #include "GPU/Common/StencilCommon.h" +#include "GPU/GLES/DrawEngineGLES.h" #include "GPU/GLES/FramebufferManagerGLES.h" #include "GPU/GLES/ShaderManagerGLES.h" #include "GPU/GLES/TextureCacheGLES.h" @@ -137,7 +138,7 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZe queries.push_back({ &u_stencilUploadTex, "tex" }); queries.push_back({ &u_stencilValue, "u_stencilValue" }); std::vector inits; - inits.push_back({ &u_stencilUploadTex, 0, 0 }); + inits.push_back({ &u_stencilUploadTex, 0, TEX_SLOT_PSP_TEXTURE }); stencilUploadProgram_ = render_->CreateProgram(shaders, semantics, queries, inits, false); for (auto iter : shaders) { render_->DeleteShader(iter); diff --git a/ext/native/thin3d/GLQueueRunner.cpp b/ext/native/thin3d/GLQueueRunner.cpp index 6ecae517a1..cf4dd780dd 100644 --- a/ext/native/thin3d/GLQueueRunner.cpp +++ b/ext/native/thin3d/GLQueueRunner.cpp @@ -249,6 +249,7 @@ void GLQueueRunner::RunInitSteps(const std::vector &steps, bool ski switch (init.type) { case 0: glUniform1i(uniform, init.value); + break; } } } @@ -951,10 +952,14 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) { } if (c.bind_fb_texture.aspect == GL_COLOR_BUFFER_BIT) { if (curTex[slot] != &c.bind_fb_texture.framebuffer->color_texture) - glBindTexture(GL_TEXTURE_2D, c.bind_fb_texture.framebuffer->color_texture.texture); + glBindTexture(GL_TEXTURE_2D, c.bind_fb_texture.framebuffer->color_texture.texture); curTex[slot] = &c.bind_fb_texture.framebuffer->color_texture; + } else if (c.bind_fb_texture.aspect == GL_DEPTH_BUFFER_BIT) { + if (curTex[slot] != &c.bind_fb_texture.framebuffer->z_stencil_texture) + glBindTexture(GL_TEXTURE_2D, c.bind_fb_texture.framebuffer->z_stencil_texture.texture); + curTex[slot] = &c.bind_fb_texture.framebuffer->z_stencil_texture; } else { - // TODO: Depth texturing? + // TODO: Stencil texturing? curTex[slot] = nullptr; } CHECK_GL_ERROR_IF_DEBUG(); From f64156c8e757ff9968418e64b14ed1cc5438bb51 Mon Sep 17 00:00:00 2001 From: xebra Date: Tue, 18 Dec 2018 00:27:02 +0900 Subject: [PATCH 220/347] GE Debugger: Improve step count dialog. --- Windows/GEDebugger/GEDebugger.cpp | 50 +++++++++++++++++++++++-------- Windows/GEDebugger/GEDebugger.h | 3 +- 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index 5bde53fa6f..9f20c87d36 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -58,22 +58,34 @@ enum PrimaryDisplayType { }; StepCountDlg::StepCountDlg(HINSTANCE _hInstance, HWND _hParent) : Dialog((LPCSTR)IDD_GEDBG_STEPCOUNT, _hInstance, _hParent) { + DialogManager::AddDlg(this); + for (int i = 0; i < 4; i++) // Add items 1, 10, 100, 1000 SendMessageA(GetDlgItem(m_hDlg, IDC_GEDBG_STEPCOUNT_COMBO), CB_ADDSTRING, 0, (LPARAM)std::to_string((int)pow(10, i)).c_str()); SetWindowTextA(GetDlgItem(m_hDlg, IDC_GEDBG_STEPCOUNT_COMBO), "1"); } -void StepCountDlg::Jump(bool minus, bool relative) { - char str[5]; - int count; - GetWindowTextA(GetDlgItem(m_hDlg, IDC_GEDBG_STEPCOUNT_COMBO), str, 5); - if (TryParse(str, &count)) { - SetBreakNext(BreakNext::COUNT); - SetBreakCount(count * (minus ? -1 : 1), relative); - } +StepCountDlg::~StepCountDlg() { + DialogManager::RemoveDlg(this); +} + +void StepCountDlg::Jump(int count, bool relative) { + if (relative && count == 0) + return; + SetBreakNext(BreakNext::COUNT); + SetBreakCount(count, relative); }; BOOL StepCountDlg::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { + int count; + bool relative; + auto GetValue = [&]() { + char str[7]; // +/-99999\0 + GetWindowTextA(GetDlgItem(m_hDlg, IDC_GEDBG_STEPCOUNT_COMBO), str, 7); + relative = str[0] == '+' || str[0] == '-'; + return TryParse(str, &count); + }; + switch (message) { case WM_CLOSE: Show(false); @@ -81,18 +93,30 @@ BOOL StepCountDlg::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { case WM_COMMAND: switch (wParam) { case IDC_GEDBG_STEPCOUNT_DEC: - Jump(true, true); + if (GetValue()) + Jump(-abs(count), true); return TRUE; case IDC_GEDBG_STEPCOUNT_INC: - Jump(false, true); + if (GetValue()) + Jump(abs(count), true); return TRUE; case IDC_GEDBG_STEPCOUNT_JUMP: - Jump(false, false); + if (GetValue()) + Jump(abs(count), false); + return TRUE; + case IDOK: + if (GetValue()) + Jump(count, relative); + Show(false); + return TRUE; + case IDCANCEL: + SetFocus(m_hParent); + Show(false); return TRUE; } - default: - return FALSE; + break; } + return FALSE; } void CGEDebugger::Init() { diff --git a/Windows/GEDebugger/GEDebugger.h b/Windows/GEDebugger/GEDebugger.h index a11de7267e..271d20569e 100644 --- a/Windows/GEDebugger/GEDebugger.h +++ b/Windows/GEDebugger/GEDebugger.h @@ -47,10 +47,11 @@ struct GPUgstate; class StepCountDlg : public Dialog { public: StepCountDlg(HINSTANCE _hInstance, HWND _hParent); + ~StepCountDlg(); protected: BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); private: - void Jump(bool minus, bool relative); + void Jump(int value, bool relative); }; class CGEDebugger : public Dialog { From ab407a4a21c6384af78fd7e24d100a3629bcb0bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 17 Dec 2018 21:07:52 +0100 Subject: [PATCH 221/347] TWo warning fixes --- Core/Debugger/WebSocket/WebSocketUtils.h | 2 +- ext/native/net/http_server.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/Debugger/WebSocket/WebSocketUtils.h b/Core/Debugger/WebSocket/WebSocketUtils.h index 0bb6b88760..ac75838583 100644 --- a/Core/Debugger/WebSocket/WebSocketUtils.h +++ b/Core/Debugger/WebSocket/WebSocketUtils.h @@ -26,7 +26,7 @@ #include "ppsspp_config.h" -#ifdef PPSSPP_PLATFORM(UWP) +#if PPSSPP_PLATFORM(UWP) // Enum name overlapped with UWP macro, quick hack to disable it #undef OPTIONAL #endif diff --git a/ext/native/net/http_server.cpp b/ext/native/net/http_server.cpp index be74e4337e..d6faa8558c 100644 --- a/ext/native/net/http_server.cpp +++ b/ext/native/net/http_server.cpp @@ -24,7 +24,7 @@ #endif -#ifdef PPSSPP_PLATFORM(UWP) +#if PPSSPP_PLATFORM(UWP) #define in6addr_any IN6ADDR_ANY_INIT #endif From 2d01db805e53b7522704b22636b249d82478f4c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 18 Dec 2018 10:10:53 +0100 Subject: [PATCH 222/347] Remove no-op DrawBuffer::End() --- GPU/Vulkan/DebugVisVulkan.cpp | 1 - UI/ControlMappingScreen.cpp | 3 +-- UI/EmuScreen.cpp | 3 +-- UI/MiscScreens.cpp | 2 -- UI/NativeApp.cpp | 1 - ext/native/gfx_es2/draw_buffer.cpp | 4 ---- ext/native/gfx_es2/draw_buffer.h | 4 +--- ext/native/ui/ui.cpp | 9 --------- ext/native/ui/ui.h | 6 +----- ext/native/ui/ui_context.cpp | 7 ------- ext/native/ui/ui_context.h | 1 - ext/native/ui/ui_screen.cpp | 1 - 12 files changed, 4 insertions(+), 38 deletions(-) diff --git a/GPU/Vulkan/DebugVisVulkan.cpp b/GPU/Vulkan/DebugVisVulkan.cpp index bc0e17ad63..d93195bc16 100644 --- a/GPU/Vulkan/DebugVisVulkan.cpp +++ b/GPU/Vulkan/DebugVisVulkan.cpp @@ -37,7 +37,6 @@ void DrawAllocatorVis(UIContext *ui, GPUInterface *gpu) { int x = padding; int y = starty; int w = columnWidth; // We will double this when actually drawing to make the pixels visible. - ui->End(); ui->Begin(); diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 3412cc34b5..68448d059b 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -478,10 +478,9 @@ void JoystickHistoryView::Draw(UIContext &dc) { dc.Draw()->DrawImage(I_CROSS, x, y, 0.8f, colorAlpha(0xFFFFFF, alpha), ALIGN_CENTER); a++; } - dc.End(); dc.BeginNoTex(); dc.Draw()->RectOutline(bounds_.centerX() - minRadius, bounds_.centerY() - minRadius, minRadius * 2, minRadius * 2, 0x80FFFFFF); - dc.End(); + dc.Flush(); dc.Begin(); } else { dc.DrawText("N/A", bounds_.centerX(), bounds_.centerY(), 0xFFFFFFFF, ALIGN_CENTER); diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 91220e16b5..83442497b0 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1351,8 +1351,7 @@ void EmuScreen::renderUI() { DrawProfile(*ctx); } #endif - - ctx->End(); + ctx->Flush(); } void EmuScreen::autoLoad() { diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index 74bb4cfc5f..8d7891c08a 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -513,7 +513,6 @@ void LogoScreen::render() { dc.DrawText(gr->T(apiName), bounds.centerX(), ppsspp_org_y + 50, textColor, ALIGN_CENTER); #endif - dc.End(); dc.Flush(); } @@ -768,6 +767,5 @@ void CreditsScreen::render() { y += itemHeight; } - dc.End(); dc.Flush(); } diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 2dd8ca97f5..d4ad6b19ad 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -928,7 +928,6 @@ void RenderOverlays(UIContext *dc, void *userdata) { UI::Drawable solid(colors[i & 3]); dc->FillRect(solid, bounds); } - dc->End(); dc->Flush(); } diff --git a/ext/native/gfx_es2/draw_buffer.cpp b/ext/native/gfx_es2/draw_buffer.cpp index 7f343ee928..603d49ee8e 100644 --- a/ext/native/gfx_es2/draw_buffer.cpp +++ b/ext/native/gfx_es2/draw_buffer.cpp @@ -80,10 +80,6 @@ void DrawBuffer::Begin(Draw::Pipeline *program) { count_ = 0; } -void DrawBuffer::End() { - // Currently does nothing, but call it! -} - void DrawBuffer::Flush(bool set_blend_state) { using namespace Draw; if (count_ == 0) diff --git a/ext/native/gfx_es2/draw_buffer.h b/ext/native/gfx_es2/draw_buffer.h index e797152554..4b504dfcb8 100644 --- a/ext/native/gfx_es2/draw_buffer.h +++ b/ext/native/gfx_es2/draw_buffer.h @@ -63,7 +63,7 @@ public: ~DrawBuffer(); void Begin(Draw::Pipeline *pipeline); - void End(); + void Flush(bool set_blend_state = true); // TODO: Enforce these. Now Init is autocalled and shutdown not called. void Init(Draw::DrawContext *t3d, Draw::Pipeline *pipeline); @@ -74,8 +74,6 @@ public: int Count() const { return count_; } - void Flush(bool set_blend_state = true); - void Rect(float x, float y, float w, float h, uint32_t color, int align = ALIGN_TOPLEFT); void hLine(float x1, float y, float x2, uint32_t color); void vLine(float x, float y1, float y2, uint32_t color); diff --git a/ext/native/ui/ui.cpp b/ext/native/ui/ui.cpp index 0ed93c504c..c0bfb3fad7 100644 --- a/ext/native/ui/ui.cpp +++ b/ext/native/ui/ui.cpp @@ -24,12 +24,3 @@ void UIFlush() { ui_draw2d.Flush(); ui_draw2d_front.Flush(); } - -void UIEnd() { - ui_draw2d.End(); - ui_draw2d_front.End(); - - ui_draw2d.Flush(); - ui_draw2d_front.Flush(); -} - diff --git a/ext/native/ui/ui.h b/ext/native/ui/ui.h index 369c3ce4b1..f3e2ff327f 100644 --- a/ext/native/ui/ui.h +++ b/ext/native/ui/ui.h @@ -60,11 +60,7 @@ private: }; -// Call at start of frame +// Begins/flushes the two UI drawbuffers together. void UIBegin(Draw::Pipeline *shaderSet); - -// Call at end of frame. - -void UIEnd(); void UIFlush(); diff --git a/ext/native/ui/ui_context.cpp b/ext/native/ui/ui_context.cpp index a148a0b60d..492191442a 100644 --- a/ext/native/ui/ui_context.cpp +++ b/ext/native/ui/ui_context.cpp @@ -58,20 +58,13 @@ void UIContext::RebindTexture() const { void UIContext::Flush() { if (uidrawbuffer_) { - uidrawbuffer_->End(); uidrawbuffer_->Flush(); } if (uidrawbufferTop_) { - uidrawbufferTop_->End(); uidrawbufferTop_->Flush(); } } -void UIContext::End() { - UIEnd(); - Flush(); -} - // TODO: Support transformed bounds using stencil instead. void UIContext::PushScissor(const Bounds &bounds) { Flush(); diff --git a/ext/native/ui/ui_context.h b/ext/native/ui/ui_context.h index 3b6c4d7e43..8d9d1c1f65 100644 --- a/ext/native/ui/ui_context.h +++ b/ext/native/ui/ui_context.h @@ -52,7 +52,6 @@ public: void Begin(); void BeginNoTex(); void Flush(); - void End(); void RebindTexture() const; diff --git a/ext/native/ui/ui_screen.cpp b/ext/native/ui/ui_screen.cpp index 3339c8d25b..eb87763ed6 100644 --- a/ext/native/ui/ui_screen.cpp +++ b/ext/native/ui/ui_screen.cpp @@ -113,7 +113,6 @@ void UIScreen::render() { uiContext->Begin(); DrawBackground(*uiContext); root_->Draw(*uiContext); - uiContext->End(); uiContext->Flush(); uiContext->PopTransform(); From 260fd3c9eea18fdf4aec7bcfc4cf2f4c41fa0777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 18 Dec 2018 10:23:22 +0100 Subject: [PATCH 223/347] ActivateTopScissor doesn't belong in UIContext::Begin. --- UI/EmuScreen.cpp | 8 ++------ UI/EmuScreen.h | 1 - ext/native/ui/ui_context.cpp | 2 +- ext/native/ui/ui_screen.cpp | 2 +- 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 83442497b0..dc19ce2977 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1165,11 +1165,6 @@ void EmuScreen::preRender() { using namespace Draw; DrawContext *draw = screenManager()->getDrawContext(); draw->BeginFrame(); - // Let's be consistent for the entire frame. We skip the UI texture if we don't need it. - hasVisibleUI_ = hasVisibleUI(); - if (hasVisibleUI_) { - screenManager()->getUIContext()->BeginFrame(); - } // Here we do NOT bind the backbuffer or clear the screen, unless non-buffered. // The emuscreen is different than the others - we really want to allow the game to render to framebuffers // before we ever bind the backbuffer for rendering. On mobile GPUs, switching back and forth between render @@ -1268,7 +1263,8 @@ void EmuScreen::render() { if (invalid_) return; - if (hasVisibleUI_) { + if (hasVisibleUI()) { + screenManager()->getUIContext()->BeginFrame(); renderUI(); } diff --git a/UI/EmuScreen.h b/UI/EmuScreen.h index 0dd44e614a..0ac62e76e7 100644 --- a/UI/EmuScreen.h +++ b/UI/EmuScreen.h @@ -80,7 +80,6 @@ private: bool invalid_; bool quit_; bool stopRender_ = false; - bool hasVisibleUI_ = true; std::string errorMessage_; // If set, pauses at the end of the frame. diff --git a/ext/native/ui/ui_context.cpp b/ext/native/ui/ui_context.cpp index 492191442a..914c849931 100644 --- a/ext/native/ui/ui_context.cpp +++ b/ext/native/ui/ui_context.cpp @@ -38,12 +38,12 @@ void UIContext::BeginFrame() { FLOG("Failed to load ui_atlas.zim"); } } + ActivateTopScissor(); } void UIContext::Begin() { draw_->BindSamplerStates(0, 1, &sampler_); draw_->BindTexture(0, uitexture_->GetTexture()); - ActivateTopScissor(); UIBegin(ui_pipeline_); } diff --git a/ext/native/ui/ui_screen.cpp b/ext/native/ui/ui_screen.cpp index eb87763ed6..a49877327d 100644 --- a/ext/native/ui/ui_screen.cpp +++ b/ext/native/ui/ui_screen.cpp @@ -78,9 +78,9 @@ void UIScreen::preRender() { return; } draw->BeginFrame(); - screenManager()->getUIContext()->BeginFrame(); // Bind and clear the back buffer draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }); + screenManager()->getUIContext()->BeginFrame(); Draw::Viewport viewport; viewport.TopLeftX = 0; From de4dec2a803df7d6f271811f52a34973b0ab12ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 18 Dec 2018 10:32:17 +0100 Subject: [PATCH 224/347] Use raw strings for more shaders --- GPU/D3D11/DepalettizeShaderD3D11.cpp | 31 ++++++------ GPU/Directx9/DepalettizeShaderDX9.cpp | 31 ++++++------ GPU/Directx9/StencilBufferDX9.cpp | 58 ++++++++++----------- GPU/GLES/DepalettizeShaderGLES.cpp | 46 +++++++++-------- GPU/GLES/StencilBufferGLES.cpp | 72 ++++++++++++++------------- 5 files changed, 123 insertions(+), 115 deletions(-) diff --git a/GPU/D3D11/DepalettizeShaderD3D11.cpp b/GPU/D3D11/DepalettizeShaderD3D11.cpp index 88520f404b..ddd17dc3a8 100644 --- a/GPU/D3D11/DepalettizeShaderD3D11.cpp +++ b/GPU/D3D11/DepalettizeShaderD3D11.cpp @@ -33,21 +33,22 @@ #define SHADERLOG #endif -static const char *depalVShaderHLSL = -"struct VS_IN {\n" -" float3 a_position : POSITION;\n" -" float2 a_texcoord0 : TEXCOORD0;\n" -"};\n" -"struct VS_OUT {\n" -" float2 Texcoord : TEXCOORD0;\n" -" float4 Position : SV_Position;\n" -"};\n" -"VS_OUT main(VS_IN input) {\n" -" VS_OUT output;\n" -" output.Texcoord = input.a_texcoord0;\n" -" output.Position = float4(input.a_position, 1.0);\n" -" return output;\n" -"}\n"; +static const char *depalVShaderHLSL = R"( +struct VS_IN { + float3 a_position : POSITION; + float2 a_texcoord0 : TEXCOORD0; +}; +struct VS_OUT { + float2 Texcoord : TEXCOORD0; + float4 Position : SV_Position; +}; +VS_OUT main(VS_IN input) { + VS_OUT output; + output.Texcoord = input.a_texcoord0; + output.Position = float4(input.a_position, 1.0); + return output; +}; +)"; static const D3D11_INPUT_ELEMENT_DESC g_DepalVertexElements[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, }, diff --git a/GPU/Directx9/DepalettizeShaderDX9.cpp b/GPU/Directx9/DepalettizeShaderDX9.cpp index 08824b7a98..6c387e1618 100644 --- a/GPU/Directx9/DepalettizeShaderDX9.cpp +++ b/GPU/Directx9/DepalettizeShaderDX9.cpp @@ -36,21 +36,22 @@ static const int DEPAL_TEXTURE_OLD_AGE = 120; #define SHADERLOG #endif -static const char *depalVShaderHLSL = -"struct VS_IN {\n" -" float3 a_position : POSITION;\n" -" float2 a_texcoord0 : TEXCOORD0;\n" -"};\n" -"struct VS_OUT {\n" -" float4 Position : POSITION;\n" -" float2 Texcoord : TEXCOORD0;\n" -"};\n" -"VS_OUT main(VS_IN input) {\n" -" VS_OUT output;\n" -" output.Texcoord = input.a_texcoord0;\n" -" output.Position = float4(input.a_position, 1.0);\n" -" return output;\n" -"}\n"; +static const char *depalVShaderHLSL = R"( +struct VS_IN { + float3 a_position : POSITION; + float2 a_texcoord0 : TEXCOORD0; +}; +struct VS_OUT { + float4 Position : POSITION; + float2 Texcoord : TEXCOORD0; +}; +VS_OUT main(VS_IN input) { + VS_OUT output; + output.Texcoord = input.a_texcoord0; + output.Position = float4(input.a_position, 1.0); + return output; +}; +)"; DepalShaderCacheDX9::DepalShaderCacheDX9(Draw::DrawContext *draw) : vertexShader_(nullptr) { device_ = (LPDIRECT3DDEVICE9)draw->GetNativeObject(Draw::NativeObject::DEVICE); diff --git a/GPU/Directx9/StencilBufferDX9.cpp b/GPU/Directx9/StencilBufferDX9.cpp index c6823cba63..927e052a3e 100644 --- a/GPU/Directx9/StencilBufferDX9.cpp +++ b/GPU/Directx9/StencilBufferDX9.cpp @@ -33,36 +33,38 @@ namespace DX9 { #define STR_HELPER(x) #x #define STR(x) STR_HELPER(x) -static const char *stencil_ps = -"sampler tex: register(s0);\n" +static const char *stencil_ps = R"( +sampler tex: register(s0); // TODO: Don't use fixed registers? Or don't overlap? -"float4 u_stencilValue : register(c" STR(CONST_PS_STENCILVALUE) ");\n" -"struct PS_IN {\n" -" float2 v_texcoord0 : TEXCOORD0;\n" -"};\n" -"float roundAndScaleTo255f(in float x) { return floor(x * 255.99); }\n" -"float4 main(PS_IN In) : COLOR {\n" -" float4 index = tex2D(tex, In.v_texcoord0);\n" -" float shifted = roundAndScaleTo255f(index.a) / roundAndScaleTo255f(u_stencilValue.x);\n" -" clip(fmod(floor(shifted), 2.0) - 0.99);\n" -" return index.aaaa;\n" -"}\n"; +float4 u_stencilValue : register(c" STR(CONST_PS_STENCILVALUE) "); +struct PS_IN { + float2 v_texcoord0 : TEXCOORD0; +}; +float roundAndScaleTo255f(in float x) { return floor(x * 255.99); } +float4 main(PS_IN In) : COLOR { + float4 index = tex2D(tex, In.v_texcoord0); + float shifted = roundAndScaleTo255f(index.a) / roundAndScaleTo255f(u_stencilValue.x); + clip(fmod(floor(shifted), 2.0) - 0.99); + return index.aaaa; +} +)"; -static const char *stencil_vs = -"struct VS_IN {\n" -" float4 a_position : POSITION;\n" -" float2 a_texcoord0 : TEXCOORD0;\n" -"};\n" -"struct VS_OUT {\n" -" float4 position : POSITION;\n" -" float2 v_texcoord0 : TEXCOORD0;\n" -"};\n" -"VS_OUT main(VS_IN In) {\n" -" VS_OUT Out;\n" -" Out.position = In.a_position;\n" -" Out.v_texcoord0 = In.a_texcoord0;\n" -" return Out;\n" -"}\n"; +static const char *stencil_vs = R"( +struct VS_IN { + float4 a_position : POSITION; + float2 a_texcoord0 : TEXCOORD0; +}; +struct VS_OUT { + float4 position : POSITION; + float2 v_texcoord0 : TEXCOORD0; +}; +VS_OUT main(VS_IN In) { + VS_OUT Out; + Out.position = In.a_position; + Out.v_texcoord0 = In.a_texcoord0; + return Out; +} +)"; bool FramebufferManagerDX9::NotifyStencilUpload(u32 addr, int size, bool skipZero) { addr &= 0x3FFFFFFF; diff --git a/GPU/GLES/DepalettizeShaderGLES.cpp b/GPU/GLES/DepalettizeShaderGLES.cpp index 5886df27ee..8d5780ac62 100644 --- a/GPU/GLES/DepalettizeShaderGLES.cpp +++ b/GPU/GLES/DepalettizeShaderGLES.cpp @@ -25,29 +25,31 @@ #include "GPU/GLES/TextureCacheGLES.h" #include "GPU/Common/DepalettizeShaderCommon.h" -static const char *depalVShader100 = -"#ifdef GL_ES\n" -"precision highp float;\n" -"#endif\n" -"attribute vec4 a_position;\n" -"attribute vec2 a_texcoord0;\n" -"varying vec2 v_texcoord0;\n" -"void main() {\n" -" v_texcoord0 = a_texcoord0;\n" -" gl_Position = a_position;\n" -"}\n"; +static const char *depalVShader100 = R"( +#ifdef GL_ES +precision highp float; +#endif +attribute vec4 a_position; +attribute vec2 a_texcoord0; +varying vec2 v_texcoord0; +void main() { + v_texcoord0 = a_texcoord0; + gl_Position = a_position; +}; +)"; -static const char *depalVShader300 = -"#ifdef GL_ES\n" -"precision highp float;\n" -"#endif\n" -"in vec4 a_position;\n" -"in vec2 a_texcoord0;\n" -"out vec2 v_texcoord0;\n" -"void main() {\n" -" v_texcoord0 = a_texcoord0;\n" -" gl_Position = a_position;\n" -"}\n"; +static const char *depalVShader300 = R"( +#ifdef GL_ES +precision highp float; +#endif +in vec4 a_position; +in vec2 a_texcoord0; +out vec2 v_texcoord0; +void main() { + v_texcoord0 = a_texcoord0; + gl_Position = a_position; +}; +)"; DepalShaderCacheGLES::DepalShaderCacheGLES(Draw::DrawContext *draw) { _assert_(draw); diff --git a/GPU/GLES/StencilBufferGLES.cpp b/GPU/GLES/StencilBufferGLES.cpp index 17d7469dfa..31a98bb9e3 100644 --- a/GPU/GLES/StencilBufferGLES.cpp +++ b/GPU/GLES/StencilBufferGLES.cpp @@ -24,42 +24,44 @@ #include "GPU/GLES/ShaderManagerGLES.h" #include "GPU/GLES/TextureCacheGLES.h" -static const char *stencil_fs = -"#ifdef GL_ES\n" -"precision highp float;\n" -"#endif\n" -"#if __VERSION__ >= 130\n" -"#define varying in\n" -"#define texture2D texture\n" -"#define gl_FragColor fragColor0\n" -"out vec4 fragColor0;\n" -"#endif\n" -"varying vec2 v_texcoord0;\n" -"uniform float u_stencilValue;\n" -"uniform sampler2D tex;\n" -"float roundAndScaleTo255f(in float x) { return floor(x * 255.99); }\n" -"void main() {\n" -" vec4 index = texture2D(tex, v_texcoord0);\n" -" gl_FragColor = vec4(index.a);\n" -" float shifted = roundAndScaleTo255f(index.a) / roundAndScaleTo255f(u_stencilValue);\n" -" if (mod(floor(shifted), 2.0) < 0.99) discard;\n" -"}\n"; +static const char *stencil_fs = R"( +#ifdef GL_ES +precision highp float; +#endif +#if __VERSION__ >= 130 +#define varying in +#define texture2D texture +#define gl_FragColor fragColor0 +out vec4 fragColor0; +#endif +varying vec2 v_texcoord0; +uniform float u_stencilValue; +uniform sampler2D tex; +float roundAndScaleTo255f(in float x) { return floor(x * 255.99); } +void main() { + vec4 index = texture2D(tex, v_texcoord0); + gl_FragColor = vec4(index.a); + float shifted = roundAndScaleTo255f(index.a) / roundAndScaleTo255f(u_stencilValue); + if (mod(floor(shifted), 2.0) < 0.99) discard; +} +)"; -static const char *stencil_vs = -"#ifdef GL_ES\n" -"precision highp float;\n" -"#endif\n" -"#if __VERSION__ >= 130\n" -"#define attribute in\n" -"#define varying out\n" -"#endif\n" -"attribute vec4 a_position;\n" -"attribute vec2 a_texcoord0;\n" -"varying vec2 v_texcoord0;\n" -"void main() {\n" -" v_texcoord0 = a_texcoord0;\n" -" gl_Position = a_position;\n" -"}\n"; +static const char *stencil_vs = R"( +#ifdef GL_ES +precision highp float; +#endif +#if __VERSION__ >= 130 +#define attribute in +#define varying out +#endif +attribute vec4 a_position; +attribute vec2 a_texcoord0; +varying vec2 v_texcoord0; +void main() { + v_texcoord0 = a_texcoord0; + gl_Position = a_position; +} +)"; bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZero) { addr &= 0x3FFFFFFF; From 637b6ce79a62981f47ab13d88370898a20483b7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 18 Dec 2018 10:34:26 +0100 Subject: [PATCH 225/347] Remove unused and unfinished SPIRV disassembler --- CMakeLists.txt | 2 - Common/Common.vcxproj | 4 +- Common/Common.vcxproj.filters | 8 +- Common/Vulkan/SPIRVDisasm.cpp | 617 ---------------------------- Common/Vulkan/SPIRVDisasm.h | 10 - ext/native/thin3d/thin3d_vulkan.cpp | 1 - libretro/Makefile.common | 1 - 7 files changed, 2 insertions(+), 641 deletions(-) delete mode 100644 Common/Vulkan/SPIRVDisasm.cpp delete mode 100644 Common/Vulkan/SPIRVDisasm.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e27986c643..8b236c69e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -390,8 +390,6 @@ set(CommonWindows source_group(Windows FILES ${CommonWindows}) set(CommonVulkan ${CommonExtra} - Common/Vulkan/SPIRVDisasm.cpp - Common/Vulkan/SPIRVDisasm.h Common/Vulkan/VulkanContext.cpp Common/Vulkan/VulkanContext.h Common/Vulkan/VulkanDebug.cpp diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index cf033d00ea..5f4fa1688e 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -244,7 +244,6 @@ - @@ -316,7 +315,6 @@ - @@ -333,4 +331,4 @@ - \ No newline at end of file + diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters index b49c83fd1f..bad1776855 100644 --- a/Common/Common.vcxproj.filters +++ b/Common/Common.vcxproj.filters @@ -58,9 +58,6 @@ - - Vulkan - Vulkan @@ -119,9 +116,6 @@ GL\GLInterface - - Vulkan - Vulkan @@ -155,4 +149,4 @@ {c14d66ef-5f7c-4565-975a-72774e7ccfb9} - \ No newline at end of file + diff --git a/Common/Vulkan/SPIRVDisasm.cpp b/Common/Vulkan/SPIRVDisasm.cpp deleted file mode 100644 index 4d7a24c2cb..0000000000 --- a/Common/Vulkan/SPIRVDisasm.cpp +++ /dev/null @@ -1,617 +0,0 @@ -#include - -#include "Common/StringUtils.h" -#include "Common/Vulkan/SPIRVDisasm.h" -#include "ext/vulkan/spirv.hpp" - -#define WRITE p+=sprintf - -struct SpirvID { - std::string name; - int opcode; -}; - -struct OpInfo { - const char *name; - const char *extra; -}; - -static const char *executionModelNames[] = { - "Vertex", // 0, - "TessellationControl", // 1, - "TessellationEvaluation", // 2, - "Geometry", // 3, - "Fragment", // 4, - "GLCompute", // 5, - "Kernel", // 6, -}; - -static const char *storageClassNames[] = { - "UniformConstant", - "Input", - "Uniform", - "Output", - "Workgroup", - "CrossWorkgroup", - "Private", - "Function", - "Generic", - "PushConstant", - "AtomicCounter", - "Image", -}; - -static const char *decorationNames[] = { - "RelaxedPrecision", // 0, - "SpecId", // 1, - "Block", // 2, - "BufferBlock", // 3, - "RowMajor", // 4, - "ColMajor", // 5, - "ArrayStride", // 6, - "MatrixStride", // 7, - "GLSLShared", // 8, - "GLSLPacked", // 9, - "CPacked", // 10, - "BuiltIn", // 11, - nullptr, // 12 - "NoPerspective", // 13, - "Flat", // 14, - "Patch", // 15, - "Centroid", // 16, - "Sample", // 17, - "Invariant", // 18, - "Restrict", // 19, - "Aliased", // 20, - "Volatile", // 21, - "Constant", // 22, - "Coherent", // 23, - "NonWritable", // 24, - "NonReadable", // 25, - "Uniform", // 26, - nullptr, // 27 - "SaturatedConversion", // 28, - "Stream", // 29, - "Location", // 30, - "Component", // 31, - "Index", // 32, - "Binding", // 33, - "DescriptorSet", // 34, - "Offset", // 35, - "XfbBuffer", // 36, - "XfbStride", // 37, - "FuncParamAttr", // 38, - "FPRoundingMode", // 39, - "FPFastMathMode", // 40, - "LinkageAttributes", // 41, - "NoContraction", // 42, - "InputAttachmentIndex", // 43, - "Alignment", // 44, -}; - -static const OpInfo opInfo[] = { - {"Nop"}, // 0, - {"Undef"}, // 1, - {"SourceContinued"}, // 2, - {"Source"}, // 3, - {"SourceExtension"}, // 4, - {"Name"}, // 5, - {"MemberName"}, // 6, - {"String"}, // 7, - {"Line"}, // 8, - {nullptr}, // 9 - {"Extension"}, // 10, - {"ExtInstImport"}, // 11, - {"ExtInst"}, // 12, - {nullptr}, // 13 - {"MemoryModel"}, // 14, - {"EntryPoint"}, // 15, - {"ExecutionMode"}, // 16, - {"Capability"}, // 17, - {nullptr}, // 18 - {"TypeVoid"}, // 19, - {"TypeBool"}, // 20, - {"TypeInt"}, // 21, - {"TypeFloat"}, // 22, - {"TypeVector"}, // 23, - {"TypeMatrix"}, // 24, - {"TypeImage"}, // 25, - {"TypeSampler"}, // 26, - {"TypeSampledImage"}, // 27, - {"TypeArray"}, // 28, - {"TypeRuntimeArray"}, // 29, - {"TypeStruct"}, // 30, - {"TypeOpaque"}, // 31, - {"TypePointer"}, // 32, - {"TypeFunction"}, // 33, - {"TypeEvent"}, // 34, - {"TypeDeviceEvent"}, // 35, - {"TypeReserveId"}, // 36, - {"TypeQueue"}, // 37, - {"TypePipe"}, // 38, - {"TypeForwardPointer"}, // 39, - {nullptr}, // 40 - {"ConstantTrue"}, // 41, - {"ConstantFalse"}, // 42, - {"Constant"}, // 43, - {"ConstantComposite"}, // 44, - {"ConstantSampler"}, // 45, - {"ConstantNull"}, // 46, - {nullptr}, // 47 - {"SpecConstantTrue"}, // 48, - {"SpecConstantFalse"}, // 49, - {"SpecConstant"}, // 50, - {"SpecConstantComposite"}, // 51, - {"SpecConstantOp"}, // 52, - {nullptr}, // 53 - {"Function"}, // 54, - {"FunctionParameter"}, // 55, - {"FunctionEnd"}, // 56, - {"FunctionCall"}, // 57, - {nullptr}, // 58 - {"Variable"}, // 59, - {"ImageTexelPointer"}, // 60, - {"Load"}, // 61, - {"Store"}, // 62, - {"CopyMemory"}, // 63, - {"CopyMemorySized"}, // 64, - {"AccessChain"}, // 65, - {"InBoundsAccessChain"}, // 66, - {"PtrAccessChain"}, // 67, - {"ArrayLength"}, // 68, - {"GenericPtrMemSemantics"}, // 69, - {"InBoundsPtrAccessChain"}, // 70, - {"Decorate"}, // 71, - {"MemberDecorate"}, // 72, - {"DecorationGroup"}, // 73, - {"GroupDecorate"}, // 74, - {"GroupMemberDecorate"}, // 75, - {nullptr}, // 76 - {"VectorExtractDynamic"}, // 77, - {"VectorInsertDynamic"}, // 78, - {"VectorShuffle"}, // 79, - {"CompositeConstruct"}, // 80, - {"CompositeExtract"}, // 81, - {"CompositeInsert"}, // 82, - {"CopyObject"}, // 83, - {"Transpose"}, // 84, - {nullptr}, // 85 - {"SampledImage"}, // 86, - {"ImageSampleImplicitLod"}, // 87, - {"ImageSampleExplicitLod"}, // 88, - {"ImageSampleDrefImplicitLod"}, // 89, - {"ImageSampleDrefExplicitLod"}, // 90, - {"ImageSampleProjImplicitLod"}, // 91, - {"ImageSampleProjExplicitLod"}, // 92, - {"ImageSampleProjDrefImplicitLod"}, // 93, - {"ImageSampleProjDrefExplicitLod"}, // 94, - {"ImageFetch"}, // 95, - {"ImageGather"}, // 96, - {"ImageDrefGather"}, // 97, - {"ImageRead"}, // 98, - {"ImageWrite"}, // 99, - {"Image"}, // 100, - {"ImageQueryFormat"}, // 101, - {"ImageQueryOrder"}, // 102, - {"ImageQuerySizeLod"}, // 103, - {"ImageQuerySize"}, // 104, - {"ImageQueryLod"}, // 105, - {"ImageQueryLevels"}, // 106, - {"ImageQuerySamples"}, // 107, - {nullptr}, // 108 - {"ConvertFToU"}, // 109, - {"ConvertFToS"}, // 110, - {"ConvertSToF"}, // 111, - {"ConvertUToF"}, // 112, - {"UConvert"}, // 113, - {"SConvert"}, // 114, - {"FConvert"}, // 115, - {"QuantizeToF16"}, // 116, - {"ConvertPtrToU"}, // 117, - {"SatConvertSToU"}, // 118, - {"SatConvertUToS"}, // 119, - {"ConvertUToPtr"}, // 120, - {"PtrCastToGeneric"}, // 121, - {"GenericCastToPtr"}, // 122, - {"GenericCastToPtrExplicit"}, // 123, - {"Bitcast"}, // 124, - {nullptr}, // 125 - {"SNegate"}, // 126, - {"FNegate"}, // 127, - {"IAdd"}, // 128, - {"FAdd", "+"}, // 129, - {"ISub"}, // 130, - {"FSub", "-"}, // 131, - {"IMul"}, // 132, - {"FMul", "*"}, // 133, - {"UDiv"}, // 134, - {"SDiv"}, // 135, - {"FDiv", "/"}, // 136, - {"UMod"}, // 137, - {"SRem"}, // 138, - {"SMod"}, // 139, - {"FRem"}, // 140, - {"FMod", "%"}, // 141, - {"VectorTimesScalar"}, // 142, - {"MatrixTimesScalar"}, // 143, - {"VectorTimesMatrix"}, // 144, - {"MatrixTimesVector"}, // 145, - {"MatrixTimesMatrix"}, // 146, - {"OuterProduct"}, // 147, - {"Dot", " dot "}, // 148, - {"IAddCarry"}, // 149, - {"ISubBorrow"}, // 150, - {"UMulExtended"}, // 151, - {"SMulExtended"}, // 152, - {nullptr}, // 153 - {"Any"}, // 154, - {"All"}, // 155, - {"IsNan"}, // 156, - {"IsInf"}, // 157, - {"IsFinite"}, // 158, - {"IsNormal"}, // 159, - {"SignBitSet"}, // 160, - {"LessOrGreater"}, // 161, - {"Ordered"}, // 162, - {"Unordered"}, // 163, - {"LogicalEqual"}, // 164, - {"LogicalNotEqual"}, // 165, - {"LogicalOr"}, // 166, - {"LogicalAnd"}, // 167, - {"LogicalNot"}, // 168, - {"Select"}, // 169, - {"IEqual"}, // 170, - {"INotEqual"}, // 171, - {"UGreaterThan"}, // 172, - {"SGreaterThan"}, // 173, - {"UGreaterThanEqual"}, // 174, - {"SGreaterThanEqual"}, // 175, - {"ULessThan"}, // 176, - {"SLessThan"}, // 177, - {"ULessThanEqual"}, // 178, - {"SLessThanEqual"}, // 179, - {"FOrdEqual", "=="}, // 180, - {"FUnordEqual", "=="}, // 181, - {"FOrdNotEqual", "!="}, // 182, - {"FUnordNotEqual", "!="}, // 183, - {"FOrdLessThan"}, // 184, - {"FUnordLessThan"}, // 185, - {"FOrdGreaterThan"}, // 186, - {"FUnordGreaterThan"}, // 187, - {"FOrdLessThanEqual"}, // 188, - {"FUnordLessThanEqual"}, // 189, - {"FOrdGreaterThanEqual"}, // 190, - {"FUnordGreaterThanEqual"}, // 191, - { nullptr }, // 192 - { nullptr }, // 193 - {"ShiftRightLogical"}, // 194, - {"ShiftRightArithmetic"}, // 195, - {"ShiftLeftLogical"}, // 196, - {"BitwiseOr", "|"}, // 197, - {"BitwiseXor", "^"}, // 198, - {"BitwiseAnd", "&"}, // 199, - {"Not", "~"}, // 200, - {"BitFieldInsert"}, // 201, - {"BitFieldSExtract"}, // 202, - {"BitFieldUExtract"}, // 203, - {"BitReverse"}, // 204, - {"BitCount"}, // 205, - {nullptr}, - {"DPdx"}, // 207, - {"DPdy"}, // 208, - {"Fwidth"}, // 209, - {"DPdxFine"}, // 210, - {"DPdyFine"}, // 211, - {"FwidthFine"}, // 212, - {"DPdxCoarse"}, // 213, - {"DPdyCoarse"}, // 214, - {"FwidthCoarse"}, // 215, - {nullptr}, // 216 - {nullptr}, // 217 - {"EmitVertex"}, // 218, - {"EndPrimitive"}, // 219, - {"EmitStreamVertex"}, // 220, - {"EndStreamPrimitive"}, // 221, - {nullptr}, // 222 - {nullptr}, // 223 - {"ControlBarrier"}, // 224, - {"MemoryBarrier"}, // 225, - {nullptr}, // 226 - {"AtomicLoad"}, // 227, - {"AtomicStore"}, // 228, - {"AtomicExchange"}, // 229, - {"AtomicCompareExchange"}, // 230, - {"AtomicCompareExchangeWeak"}, // 231, - {"AtomicIIncrement"}, // 232, - {"AtomicIDecrement"}, // 233, - {"AtomicIAdd"}, // 234, - {"AtomicISub"}, // 235, - {"AtomicSMin"}, // 236, - {"AtomicUMin"}, // 237, - {"AtomicSMax"}, // 238, - {"AtomicUMax"}, // 239, - {"AtomicAnd"}, // 240, - {"AtomicOr"}, // 241, - {"AtomicXor"}, // 242, - { nullptr }, // 243, - { nullptr }, // 244, - {"Phi"}, // 245, - {"LoopMerge"}, // 246, - {"SelectionMerge"}, // 247, - {"Label"}, // 248, - {"Branch"}, // 249, - {"BranchConditional"}, // 250, - {"Switch"}, // 251, - {"Kill"}, // 252, - {"Return"}, // 253, - {"ReturnValue"}, // 254, - {"Unreachable"}, // 255, - {"LifetimeStart"}, // 256, - {"LifetimeStop"}, // 257, - { nullptr }, - {"GroupAsyncCopy"}, // 259, - {"GroupWaitEvents"}, // 260, - {"GroupAll"}, // 261, - {"GroupAny"}, // 262, - {"GroupBroadcast"}, // 263, - {"GroupIAdd"}, // 264, - {"GroupFAdd"}, // 265, - {"GroupFMin"}, // 266, - {"GroupUMin"}, // 267, - {"GroupSMin"}, // 268, - {"GroupFMax"}, // 269, - {"GroupUMax"}, // 270, - {"GroupSMax"}, // 271, - {nullptr}, // 272 - {nullptr}, // 273 - {"ReadPipe"}, // 274, - {"WritePipe"}, // 275, - {"ReservedReadPipe"}, // 276, - {"ReservedWritePipe"}, // 277, - {"ReserveReadPipePackets"}, // 278, - {"ReserveWritePipePackets"}, // 279, - {"CommitReadPipe"}, // 280, - {"CommitWritePipe"}, // 281, - {"IsValidReserveId"}, // 282, - {"GetNumPipePackets"}, // 283, - {"GetMaxPipePackets"}, // 284, - {"GroupReserveReadPipePackets"}, // 285, - {"GroupReserveWritePipePackets"}, // 286, - {"GroupCommitReadPipe"}, // 287, - {"GroupCommitWritePipe"}, // 288, - { nullptr }, // 289 - { nullptr }, // 290 - {"EnqueueMarker"}, // 291, - {"EnqueueKernel"}, // 292, - {"GetKernelNDrangeSubGroupCount"}, // 293, - {"GetKernelNDrangeMaxSubGroupSize"}, // 294, - {"GetKernelWorkGroupSize"}, // 295, - {"GetKernelPreferredWorkGroupSizeMultiple"}, // 296, - {"RetainEvent"}, // 297, - {"ReleaseEvent"}, // 298, - {"CreateUserEvent"}, // 299, - {"IsValidEvent"}, // 300, - {"SetUserEventStatus"}, // 301, - {"CaptureEventProfilingInfo"}, // 302, - {"GetDefaultQueue"}, // 303, - {"BuildNDRange"}, // 304, - {"ImageSparseSampleImplicitLod"}, // 305, - {"ImageSparseSampleExplicitLod"}, // 306, - {"ImageSparseSampleDrefImplicitLod"}, // 307, - {"ImageSparseSampleDrefExplicitLod"}, // 308, - {"ImageSparseSampleProjImplicitLod"}, // 309, - {"ImageSparseSampleProjExplicitLod"}, // 310, - {"ImageSparseSampleProjDrefImplicitLod"}, // 311, - {"ImageSparseSampleProjDrefExplicitLod"}, // 312, - {"ImageSparseFetch"}, // 313, - {"ImageSparseGather"}, // 314, - {"ImageSparseDrefGather"}, // 315, - {"ImageSparseTexelsResident"}, // 316, - {"NoLine"}, // 317, - {"AtomicFlagTestAndSet"}, // 318, - {"AtomicFlagClear"}, // 319, -}; - -static std::string ReadSpirvString(const std::vector &spirv, int offset, int *outOffset = nullptr) { - bool done = false; - std::string temp; - while (!done) { - uint32_t data = spirv[offset++]; - for (int i = 0; i < 4; i++) { - char c = (char)(data & 0xff); - if (!c) { - done = true; - break; - } - temp.push_back(data); - data >>= 8; - } - if (offset == (int)spirv.size()) - break; - } - if (outOffset) - *outOffset = offset; - return temp; -} - -bool DisassembleSPIRV(std::vector spirv, std::string *output) { - if (spirv.size() < 10) { - *output = "Too small"; - return false; - } - uint32_t magic = spirv[0]; - uint32_t version = spirv[1]; - uint32_t generator = spirv[2]; - - int bound = (int)spirv[3]; // Max ID used in file. - // spirv[4] is reserved for schema. - std::vector ids; - ids.resize(bound); - for (int i = 0; i < bound; i++) { - ids[i].name = StringFromFormat("%%%d", i); - } - - if (magic != 0x07230203) { - *output = "Not SPIRV"; - return false; - } - - int indent = 0; - - char *buffer = new char[1024 * 1024]; - char *p = buffer; - - WRITE(p, "// ======= SPIR-V version %08x =======\n// Max ID: %d\n", version, bound); // GLSL ES - - int i = 5; - while (i < (int)spirv.size()) { - uint32_t d = spirv[i]; - int wordCount = d >> 16; - int opcode = d & 0xFFFF; - // Force to a valid index in the array. - const OpInfo &op = opInfo[opcode >= (int)ARRAY_SIZE(opInfo) ? 0 : opcode]; - int target = (i < (int)spirv.size() - 1) ? spirv[(i + 1)] : 0; // Not always, but used often enough that we get it here. - int source, source2, resType; - std::string name; - switch (opcode) { - case spv::OpTypeVoid: - case spv::OpTypeBool: - case spv::OpTypeInt: - case spv::OpTypeFloat: - case spv::OpTypeMatrix: - case spv::OpTypeImage: - case spv::OpTypeSampler: - case spv::OpTypeSampledImage: - case spv::OpTypeRuntimeArray: - case spv::OpTypeOpaque: - case spv::OpTypePointer: - case spv::OpTypeFunction: - case spv::OpTypeEvent: - case spv::OpTypeDeviceEvent: - case spv::OpTypeReserveId: - case spv::OpTypeQueue: - case spv::OpTypePipe: - case spv::OpTypeForwardPointer: - ids[target].name = op.name + 4; // Remove "Type" - ids[target].opcode = opcode; - break; - case spv::OpTypeVector: - source = spirv[i + 2]; - source2 = spirv[i + 3]; - ids[target].name = ids[source].name + StringFromFormat("%d", source2); - break; - case spv::OpTypeArray: - source = spirv[i + 2]; - source2 = spirv[i + 3]; - ids[target].name = ids[source].name + "[" + ids[source2].name + "]"; - break; - case spv::OpTypeStruct: - { - ids[target].name = "struct" + ids[target].name; - WRITE(p, "struct {\n"); - if (wordCount == 3) { - source = spirv[i + 2]; - WRITE(p, " %s\n", ids[source].name.c_str()); - } else { - int numMembers = (wordCount - 2) / 2; - for (int m = 0; m < numMembers; m++) { - int id = spirv[i + 2 + m]; - int type = spirv[i + 2 + m + numMembers]; - WRITE(p, " %s %s;\n", ids[type].name.c_str(), ids[id].name.c_str()); - } - } - WRITE(p, "};\n"); - } - break; - case spv::OpVariable: - resType = spirv[i + 1]; - target = spirv[i + 2]; - source = spirv[i + 3]; - source2 = spirv[i + 4]; - ids[target].name = storageClassNames[source]; - break; - case spv::OpDecorate: - source = spirv[i + 2]; - ids[target].name += std::string("[") + decorationNames[source] + "]"; - break; - case spv::OpName: - ids[target].name = ReadSpirvString(spirv, i + 2); - // WRITE(p, "Name %d: '%s'\n", target, ids[target].name.c_str()); - break; - case spv::OpMemberName: - break; - case spv::OpStore: - source = spirv[i + 2]; - WRITE(p, "Store(%s, %s)\n", ids[target].name.c_str(), ids[source].name.c_str()); - break; - case spv::OpLoad: - resType = spirv[i + 1]; - target = spirv[i + 2]; - source = spirv[i + 3]; - WRITE(p, "%s (%s) := Load(%s)\n", ids[target].name.c_str(), ids[resType].name.c_str(), ids[source].name.c_str()); - break; - case spv::OpFAdd: - case spv::OpFMul: - case spv::OpFDiv: - case spv::OpFSub: - resType = spirv[i + 2]; - source = spirv[i + 3]; - source2 = spirv[i + 4]; - WRITE(p, "%s (%s) := %s %s %s\n", ids[target].name.c_str(), ids[resType].name.c_str(), ids[source].name.c_str(), op.extra, ids[source2].name.c_str()); - break; - - case spv::OpCapability: - case spv::OpMemoryModel: - case spv::OpExtInstImport: - case spv::OpExecutionMode: - case spv::OpGroupAsyncCopy: - case spv::OpSource: - case spv::OpExtension: - // hide these for now - break; - - case spv::OpEntryPoint: - source = spirv[i + 1]; - source2 = spirv[i + 2]; - name = ReadSpirvString(spirv, i + 3); - WRITE(p, "EntryPoint %s: '%s' %s : %s\n", executionModelNames[target], ids[source].name.c_str(), ids[source2].name.c_str(), name.c_str()); - break; - - case spv::OpFunction: - resType = spirv[i + 1]; - target = spirv[i + 2]; - source = spirv[i + 3]; - ids[target].name = ids[resType].name + "()"; - WRITE(p, "Function %s {\n", ids[target].name.c_str()); - break; - - case spv::OpLabel: - WRITE(p, "label %s:\n", ids[target].name.c_str()); - break; - - case spv::OpReturnValue: - WRITE(p, "return %s\n", ids[target].name.c_str()); - break; - - case spv::OpReturn: - WRITE(p, "return\n"); - break; - - case spv::OpFunctionEnd: - WRITE(p, "}\n"); - break; - - case spv::OpSourceExtension: - break; - - default: - WRITE(p, "%s (%d data words)\n", op.name, wordCount - 1); - break; - } - i += wordCount; - } - - *output = buffer; - delete[] buffer; - return true; -} diff --git a/Common/Vulkan/SPIRVDisasm.h b/Common/Vulkan/SPIRVDisasm.h deleted file mode 100644 index d5d036fbb4..0000000000 --- a/Common/Vulkan/SPIRVDisasm.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include -#include -#include - -// Mostly just a toy to understand SPIR-V better. Not an accurate SPIR-V disassembler, -// and the result will not reassemble. - -bool DisassembleSPIRV(std::vector spirv, std::string *output); \ No newline at end of file diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 41c94444b3..393ddb806e 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -21,7 +21,6 @@ #include #include -#include "Common/Vulkan/SPIRVDisasm.h" #include "Core/Config.h" #include "base/logging.h" diff --git a/libretro/Makefile.common b/libretro/Makefile.common index f127fab167..7baa2c897b 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -584,7 +584,6 @@ SOURCES_C += $(EXTDIR)/udis86/decode.c \ SOURCES_CXX += \ - $(COMMONDIR)/Vulkan/SPIRVDisasm.cpp \ $(COMMONDIR)/Vulkan/VulkanContext.cpp \ $(COMMONDIR)/Vulkan/VulkanDebug.cpp \ $(COMMONDIR)/Vulkan/VulkanImage.cpp \ From a2cc2b39cad9808a08265001e23b170729a1b05f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 18 Dec 2018 10:42:29 +0100 Subject: [PATCH 226/347] Additional raw string shaders --- GPU/Directx9/FramebufferDX9.cpp | 53 ++++++++++++++------------- GPU/GLES/FramebufferManagerGLES.cpp | 56 +++++++++++++++-------------- 2 files changed, 55 insertions(+), 54 deletions(-) diff --git a/GPU/Directx9/FramebufferDX9.cpp b/GPU/Directx9/FramebufferDX9.cpp index 9bcbec3427..8631e7b5db 100644 --- a/GPU/Directx9/FramebufferDX9.cpp +++ b/GPU/Directx9/FramebufferDX9.cpp @@ -47,34 +47,33 @@ namespace DX9 { -static const char * vscode = - "struct VS_IN {\n" - " float4 ObjPos : POSITION;\n" - " float2 Uv : TEXCOORD0;\n" - "};" - "struct VS_OUT {\n" - " float4 ProjPos : POSITION;\n" - " float2 Uv : TEXCOORD0;\n" - "};\n" - "VS_OUT main( VS_IN In ) {\n" - " VS_OUT Out;\n" - " Out.ProjPos = In.ObjPos;\n" - " Out.Uv = In.Uv;\n" - " return Out;\n" - "}\n"; +static const char *vscode = R"( +struct VS_IN { + float4 ObjPos : POSITION; + float2 Uv : TEXCOORD0; +};" +struct VS_OUT { + float4 ProjPos : POSITION; + float2 Uv : TEXCOORD0; +}; +VS_OUT main( VS_IN In ) { + VS_OUT Out; + Out.ProjPos = In.ObjPos; + Out.Uv = In.Uv; + return Out; +}; +)"; -//-------------------------------------------------------------------------------------- -// Pixel shader -//-------------------------------------------------------------------------------------- -static const char * pscode = - "sampler s: register(s0);\n" - "struct PS_IN {\n" - " float2 Uv : TEXCOORD0;\n" - "};\n" - "float4 main( PS_IN In ) : COLOR {\n" - " float4 c = tex2D(s, In.Uv);\n" - " return c;\n" - "}\n"; +static const char *pscode = R"( +sampler s: register(s0); +struct PS_IN { + float2 Uv : TEXCOORD0; +}; +float4 main( PS_IN In ) : COLOR { + float4 c = tex2D(s, In.Uv); + return c; +}; +)"; static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 780735da13..46f69b6050 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -48,34 +48,36 @@ #include "GPU/GLES/DrawEngineGLES.h" #include "GPU/GLES/ShaderManagerGLES.h" -static const char tex_fs[] = - "#if __VERSION__ >= 130\n" - "#define varying in\n" - "#define texture2D texture\n" - "#define gl_FragColor fragColor0\n" - "out vec4 fragColor0;\n" - "#endif\n" - "#ifdef GL_ES\n" - "precision mediump float;\n" - "#endif\n" - "uniform sampler2D sampler0;\n" - "varying vec2 v_texcoord0;\n" - "void main() {\n" - " gl_FragColor = texture2D(sampler0, v_texcoord0);\n" - "}\n"; +static const char tex_fs[] = R"( +#if __VERSION__ >= 130 +#define varying in +#define texture2D texture +#define gl_FragColor fragColor0 +out vec4 fragColor0; +#endif +#ifdef GL_ES +precision mediump float; +#endif +uniform sampler2D sampler0; +varying vec2 v_texcoord0; +void main() { + gl_FragColor = texture2D(sampler0, v_texcoord0); +} +)"; -static const char basic_vs[] = - "#if __VERSION__ >= 130\n" - "#define attribute in\n" - "#define varying out\n" - "#endif\n" - "attribute vec4 a_position;\n" - "attribute vec2 a_texcoord0;\n" - "varying vec2 v_texcoord0;\n" - "void main() {\n" - " v_texcoord0 = a_texcoord0;\n" - " gl_Position = a_position;\n" - "}\n"; +static const char basic_vs[] = R"( +#if __VERSION__ >= 130 +#define attribute in +#define varying out +#endif +attribute vec4 a_position; +attribute vec2 a_texcoord0; +varying vec2 v_texcoord0; +void main() { + v_texcoord0 = a_texcoord0; + gl_Position = a_position; +} +)"; void FramebufferManagerGLES::CompileDraw2DProgram() { if (!draw2dprogram_) { From 956af61ff52b3ca48a5e3c8e148dfb6340e26fa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 16 Dec 2018 23:06:01 +0100 Subject: [PATCH 227/347] Fix ridiculous bug in thin3d.h. Only worked by accidental matchup between shader IDs.. --- ext/native/thin3d/thin3d.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 63be93ce68..e80fac4884 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -547,8 +547,8 @@ public: virtual InputLayout *CreateInputLayout(const InputLayoutDesc &desc) = 0; // Note that these DO NOT AddRef so you must not ->Release presets unless you manually AddRef them. - ShaderModule *GetVshaderPreset(VertexShaderPreset preset) { return fsPresets_[preset]; } - ShaderModule *GetFshaderPreset(FragmentShaderPreset preset) { return vsPresets_[preset]; } + ShaderModule *GetVshaderPreset(VertexShaderPreset preset) { return vsPresets_[preset]; } + ShaderModule *GetFshaderPreset(FragmentShaderPreset preset) { return fsPresets_[preset]; } // Resources virtual Buffer *CreateBuffer(size_t size, uint32_t usageFlags) = 0; From a135dc15472673d3aa8fada1e5312634b4887dca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 16 Dec 2018 20:18:40 +0100 Subject: [PATCH 228/347] thin3d: Remove unused shader language support --- ext/native/thin3d/thin3d.h | 5 - ext/native/thin3d/thin3d_d3d11.cpp | 136 +++++++++++++--------------- ext/native/thin3d/thin3d_d3d9.cpp | 2 +- ext/native/thin3d/thin3d_vulkan.cpp | 2 +- 4 files changed, 64 insertions(+), 81 deletions(-) diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index e80fac4884..4d77dc69fa 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -204,13 +204,8 @@ enum class ShaderLanguage { GLSL_ES_300 = 2, GLSL_410 = 4, GLSL_VULKAN = 8, - SPIRV_VULKAN = 16, HLSL_D3D9 = 32, HLSL_D3D11 = 64, - HLSL_D3D9_BYTECODE = 128, - HLSL_D3D11_BYTECODE = 256, - METAL = 512, - METAL_BYTECODE = 1024, }; enum FormatSupport { diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index b8618ccfe1..69205d05e4 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -48,7 +48,7 @@ public: return deviceList_; } uint32_t GetSupportedShaderLanguages() const override { - return (uint32_t)ShaderLanguage::HLSL_D3D11 | (uint32_t)ShaderLanguage::HLSL_D3D11_BYTECODE; + return (uint32_t)ShaderLanguage::HLSL_D3D11; } uint32_t GetDataFormatSupport(DataFormat fmt) const override; @@ -806,11 +806,7 @@ public: }; ShaderModule *D3D11DrawContext::CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize) { - switch (language) { - case ShaderLanguage::HLSL_D3D11: - case ShaderLanguage::HLSL_D3D11_BYTECODE: - break; - default: + if (language != ShaderLanguage::HLSL_D3D11) { ELOG("Unsupported shader language"); return nullptr; } @@ -826,77 +822,69 @@ ShaderModule *D3D11DrawContext::CreateShaderModule(ShaderStage stage, ShaderLang std::string compiled; std::string errors; - if (language == ShaderLanguage::HLSL_D3D11) { - const char *target = nullptr; - switch (stage) { - case ShaderStage::FRAGMENT: target = fragmentModel; break; - case ShaderStage::VERTEX: target = vertexModel; break; - case ShaderStage::GEOMETRY: - if (!geometryModel) - return nullptr; - target = geometryModel; - break; - case ShaderStage::COMPUTE: - case ShaderStage::CONTROL: - case ShaderStage::EVALUATION: - default: - Crash(); - break; - } - if (!target) { + const char *target = nullptr; + switch (stage) { + case ShaderStage::FRAGMENT: target = fragmentModel; break; + case ShaderStage::VERTEX: target = vertexModel; break; + case ShaderStage::GEOMETRY: + if (!geometryModel) return nullptr; - } - - ID3DBlob *compiledCode = nullptr; - ID3DBlob *errorMsgs = nullptr; - HRESULT result = ptr_D3DCompile(data, dataSize, nullptr, nullptr, nullptr, "main", target, 0, 0, &compiledCode, &errorMsgs); - if (compiledCode) { - compiled = std::string((const char *)compiledCode->GetBufferPointer(), compiledCode->GetBufferSize()); - compiledCode->Release(); - } - if (errorMsgs) { - errors = std::string((const char *)errorMsgs->GetBufferPointer(), errorMsgs->GetBufferSize()); - ELOG("Failed compiling:\n%s\n%s", data, errors.c_str()); - errorMsgs->Release(); - } - - if (result != S_OK) { - return nullptr; - } - - // OK, we can now proceed - language = ShaderLanguage::HLSL_D3D11_BYTECODE; - data = (const uint8_t *)compiled.c_str(); - dataSize = compiled.size(); + target = geometryModel; + break; + case ShaderStage::COMPUTE: + case ShaderStage::CONTROL: + case ShaderStage::EVALUATION: + default: + Crash(); + break; + } + if (!target) { + return nullptr; } - if (language == ShaderLanguage::HLSL_D3D11_BYTECODE) { - // Easy! - D3D11ShaderModule *module = new D3D11ShaderModule(); - module->stage = stage; - module->byteCode_ = std::vector(data, data + dataSize); - HRESULT result = S_OK; - switch (stage) { - case ShaderStage::VERTEX: - result = device_->CreateVertexShader(data, dataSize, nullptr, &module->vs); - break; - case ShaderStage::FRAGMENT: - result = device_->CreatePixelShader(data, dataSize, nullptr, &module->ps); - break; - case ShaderStage::GEOMETRY: - result = device_->CreateGeometryShader(data, dataSize, nullptr, &module->gs); - break; - default: - ELOG("Unsupported shader stage"); - result = S_FALSE; - break; - } - if (result == S_OK) { - return module; - } else { - delete module; - return nullptr; - } + ID3DBlob *compiledCode = nullptr; + ID3DBlob *errorMsgs = nullptr; + HRESULT result = ptr_D3DCompile(data, dataSize, nullptr, nullptr, nullptr, "main", target, 0, 0, &compiledCode, &errorMsgs); + if (compiledCode) { + compiled = std::string((const char *)compiledCode->GetBufferPointer(), compiledCode->GetBufferSize()); + compiledCode->Release(); + } + if (errorMsgs) { + errors = std::string((const char *)errorMsgs->GetBufferPointer(), errorMsgs->GetBufferSize()); + ELOG("Failed compiling:\n%s\n%s", data, errors.c_str()); + errorMsgs->Release(); + } + + if (result != S_OK) { + return nullptr; + } + + // OK, we can now proceed + data = (const uint8_t *)compiled.c_str(); + dataSize = compiled.size(); + D3D11ShaderModule *module = new D3D11ShaderModule(); + module->stage = stage; + module->byteCode_ = std::vector(data, data + dataSize); + switch (stage) { + case ShaderStage::VERTEX: + result = device_->CreateVertexShader(data, dataSize, nullptr, &module->vs); + break; + case ShaderStage::FRAGMENT: + result = device_->CreatePixelShader(data, dataSize, nullptr, &module->ps); + break; + case ShaderStage::GEOMETRY: + result = device_->CreateGeometryShader(data, dataSize, nullptr, &module->gs); + break; + default: + ELOG("Unsupported shader stage"); + result = S_FALSE; + break; + } + if (result == S_OK) { + return module; + } else { + delete module; + return nullptr; } return nullptr; } diff --git a/ext/native/thin3d/thin3d_d3d9.cpp b/ext/native/thin3d/thin3d_d3d9.cpp index 8f8396798b..c6c22b37b7 100644 --- a/ext/native/thin3d/thin3d_d3d9.cpp +++ b/ext/native/thin3d/thin3d_d3d9.cpp @@ -465,7 +465,7 @@ public: return caps_; } uint32_t GetSupportedShaderLanguages() const override { - return (uint32_t)ShaderLanguage::HLSL_D3D9 | (uint32_t)ShaderLanguage::HLSL_D3D9_BYTECODE; + return (uint32_t)ShaderLanguage::HLSL_D3D9; } uint32_t GetDataFormatSupport(DataFormat fmt) const override; diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 393ddb806e..8e0fd5a238 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -353,7 +353,7 @@ public: return list; } uint32_t GetSupportedShaderLanguages() const override { - return (uint32_t)ShaderLanguage::GLSL_VULKAN | (uint32_t)ShaderLanguage::SPIRV_VULKAN; + return (uint32_t)ShaderLanguage::GLSL_VULKAN; } uint32_t GetDataFormatSupport(DataFormat fmt) const override; From a73c569bf60f0e8cf413ca1c586b81b8cb345748 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 18 Dec 2018 14:30:05 +0100 Subject: [PATCH 229/347] Add check for GL_FRAGMENT_PRECISION_HIGH for GLES in stencil code. --- GPU/GLES/StencilBufferGLES.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/GPU/GLES/StencilBufferGLES.cpp b/GPU/GLES/StencilBufferGLES.cpp index 31a98bb9e3..f512b5bffa 100644 --- a/GPU/GLES/StencilBufferGLES.cpp +++ b/GPU/GLES/StencilBufferGLES.cpp @@ -26,7 +26,11 @@ static const char *stencil_fs = R"( #ifdef GL_ES +#if GL_FRAGMENT_PRECISION_HIGH precision highp float; +#else +precision mediump float; // just hope it's enough.. +#endif #endif #if __VERSION__ >= 130 #define varying in From 9fd8d3b91162a598a1521c5f14f4ad6ee83cb467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 18 Dec 2018 17:00:13 +0100 Subject: [PATCH 230/347] Fix bug in #11681 --- GPU/Directx9/StencilBufferDX9.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Directx9/StencilBufferDX9.cpp b/GPU/Directx9/StencilBufferDX9.cpp index 927e052a3e..49c73c2821 100644 --- a/GPU/Directx9/StencilBufferDX9.cpp +++ b/GPU/Directx9/StencilBufferDX9.cpp @@ -36,7 +36,7 @@ namespace DX9 { static const char *stencil_ps = R"( sampler tex: register(s0); // TODO: Don't use fixed registers? Or don't overlap? -float4 u_stencilValue : register(c" STR(CONST_PS_STENCILVALUE) "); +float4 u_stencilValue : register(c)" STR(CONST_PS_STENCILVALUE) R"(); struct PS_IN { float2 v_texcoord0 : TEXCOORD0; }; From 08d71cef50ac6365c36128d754209e1f3c802264 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 18 Dec 2018 21:47:21 -0800 Subject: [PATCH 231/347] GLES: Simplify depth download shader. Fixes it on Adreno, no need to do the constant math in the shader. --- GPU/GLES/DepthBufferGLES.cpp | 33 ++++++++++++++++++++++--------- GPU/GLES/FramebufferManagerGLES.h | 2 ++ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/GPU/GLES/DepthBufferGLES.cpp b/GPU/GLES/DepthBufferGLES.cpp index 16bd8568a7..3f9c6cde18 100644 --- a/GPU/GLES/DepthBufferGLES.cpp +++ b/GPU/GLES/DepthBufferGLES.cpp @@ -27,7 +27,11 @@ static const char *depth_dl_fs = R"( #ifdef GL_ES +#if GL_FRAGMENT_PRECISION_HIGH precision highp float; +#else +precision mediump float; +#endif #endif #if __VERSION__ >= 130 #define varying in @@ -36,17 +40,18 @@ precision highp float; out vec4 fragColor0; #endif varying vec2 v_texcoord0; -uniform float u_depthScaleFactor; +uniform vec2 u_depthFactor; +uniform vec4 u_depthShift; +uniform vec4 u_depthTo8; uniform sampler2D tex; void main() { float depth = texture2D(tex, v_texcoord0).r; - float offset = 0.5 * (u_depthScaleFactor - 1.0) * (1.0 / u_depthScaleFactor); // At this point, clamped maps [0, 1] to [0, 65535]. - float clamped = clamp((depth - offset) * u_depthScaleFactor, 0.0, 1.0); + float clamped = clamp((depth + u_depthFactor.x) * u_depthFactor.y, 0.0, 1.0); - vec4 enc = vec4(16777215.0, 16777215.0 / 256.0, 16777215.0 / 65536.0, 16777215.0 / 16777216.0) * clamped; - enc = floor(mod(enc, 256.0)); - enc = enc * vec4(1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0); + vec4 enc = u_depthShift * clamped; + enc = floor(mod(enc, 256.0)) * u_depthTo8; + enc = enc * u_depthTo8; // Let's ignore the bits outside 16 bit precision. gl_FragColor = enc.yzww; } @@ -106,7 +111,9 @@ void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int semantics.push_back({ 1, "a_texcoord0" }); std::vector queries; queries.push_back({ &u_depthDownloadTex, "tex" }); - queries.push_back({ &u_depthDownloadFactor, "u_depthScaleFactor" }); + queries.push_back({ &u_depthDownloadFactor, "u_depthFactor" }); + queries.push_back({ &u_depthDownloadShift, "u_depthShift" }); + queries.push_back({ &u_depthDownloadTo8, "u_depthTo8" }); std::vector inits; inits.push_back({ &u_depthDownloadTex, 0, TEX_SLOT_PSP_TEXTURE }); depthDownloadProgram_ = render_->CreateProgram(shaders, semantics, queries, inits, false); @@ -131,10 +138,18 @@ void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int render_->BindProgram(depthDownloadProgram_); if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { - render_->SetUniformF1(&u_depthDownloadFactor, 1.0f); + float factors[] = { 0.0f, 1.0f }; + render_->SetUniformF(&u_depthDownloadFactor, 2, factors); } else { - render_->SetUniformF1(&u_depthDownloadFactor, DepthSliceFactor()); + const float factor = DepthSliceFactor(); + float factors[] = { -0.5f * (factor - 1.0f) * (1.0f / factor), factor }; + render_->SetUniformF(&u_depthDownloadFactor, 2, factors); } + float shifts[] = { 16777215.0f, 16777215.0f / 256.0f, 16777215.0f / 65536.0f, 16777215.0f / 16777216.0f }; + render_->SetUniformF(&u_depthDownloadShift, 4, shifts); + float to8[] = { 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f }; + render_->SetUniformF(&u_depthDownloadTo8, 4, to8); + draw_->BindFramebufferAsTexture(vfb->fbo, TEX_SLOT_PSP_TEXTURE, Draw::FB_DEPTH_BIT, 0); float u1 = 1.0f; float v1 = 1.0f; diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index db10d01583..aa6486c822 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -107,6 +107,8 @@ private: GLRProgram *depthDownloadProgram_ = nullptr; int u_depthDownloadTex = -1; int u_depthDownloadFactor = -1; + int u_depthDownloadShift = -1; + int u_depthDownloadTo8 = -1; // Cached uniform locs int u_draw2d_tex = -1; From 86869601800eb65737a809b6289afb9031554294 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 17 Dec 2018 23:30:56 +0100 Subject: [PATCH 232/347] Delete some unused DNS code, just because. --- ext/native/net/resolve.cpp | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/ext/native/net/resolve.cpp b/ext/native/net/resolve.cpp index ec7d17f1d1..60182e4d64 100644 --- a/ext/native/net/resolve.cpp +++ b/ext/native/net/resolve.cpp @@ -43,40 +43,6 @@ void Shutdown() #endif } -char *DNSResolveTry(const char *host, const char **err) -{ - struct hostent *hent; - if((hent = gethostbyname(host)) == NULL) - { - *err = "Can't get IP"; - return NULL; - } - int iplen = 15; //XXX.XXX.XXX.XXX - char *ip = (char *)malloc(iplen+1); - memset(ip, 0, iplen+1); - char *iptoa = inet_ntoa(*(in_addr *)hent->h_addr_list[0]); - if (iptoa == NULL) - { - *err = "Can't resolve host"; - free(ip); - return NULL; - } - strncpy(ip, iptoa, iplen); - return ip; -} - -char *DNSResolve(const char *host) -{ - const char *err; - char *ip = DNSResolveTry(host, &err); - if (ip == NULL) - { - perror(err); - exit(1); - } - return ip; -} - bool DNSResolve(const std::string &host, const std::string &service, addrinfo **res, std::string &error, DNSType type) { addrinfo hints = {0}; From df98721e73af9a5352f917d463fb5b1b0b6ac7a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 16 Dec 2018 21:48:35 +0100 Subject: [PATCH 233/347] Write rough framework for GPU discard test screen --- UI/DevScreens.cpp | 2 - UI/GPUDriverTestScreen.cpp | 178 +++++++++++++++++++++++++++++ UI/GPUDriverTestScreen.h | 29 +++++ UI/GameSettingsScreen.cpp | 24 +++- UI/GameSettingsScreen.h | 1 + UI/NativeApp.cpp | 1 + UI/UI.vcxproj | 2 + UI/UI.vcxproj.filters | 6 + ext/native/gfx_es2/draw_buffer.cpp | 1 + ext/native/gfx_es2/draw_buffer.h | 8 +- ext/native/thin3d/thin3d.cpp | 8 +- ext/native/thin3d/thin3d.h | 9 ++ ext/native/ui/ui.cpp | 6 +- ext/native/ui/ui_context.cpp | 11 ++ ext/native/ui/ui_context.h | 2 + 15 files changed, 271 insertions(+), 17 deletions(-) create mode 100644 UI/GPUDriverTestScreen.cpp create mode 100644 UI/GPUDriverTestScreen.h diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index a81bc8c60b..5bb95172d3 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -127,8 +127,6 @@ UI::EventReturn DevMenu::OnShaderView(UI::EventParams &e) { return UI::EVENT_DONE; } - - UI::EventReturn DevMenu::OnFreezeFrame(UI::EventParams &e) { if (PSP_CoreParameter().frozen) { PSP_CoreParameter().frozen = false; diff --git a/UI/GPUDriverTestScreen.cpp b/UI/GPUDriverTestScreen.cpp new file mode 100644 index 0000000000..0d46e8a59d --- /dev/null +++ b/UI/GPUDriverTestScreen.cpp @@ -0,0 +1,178 @@ +#include "GPUDriverTestScreen.h" +#include "i18n/i18n.h" +#include "ui/view.h" + +static const std::vector fsDiscard = { + {Draw::ShaderLanguage::GLSL_ES_200, + R"(varying vec4 oColor0; + varying vec2 oTexCoord0; + uniform sampler2D Sampler0; + void main() { + vec4 color = texture2D(Sampler0, oTexCoord0) * oColor0; + if (color.a <= 0.0) + discard; + gl_FragColor = color; + })" + }, + {Draw::ShaderLanguage::GLSL_VULKAN, + R"(layout(location = 0) in vec4 oColor0; + layout(location = 1) in vec2 oTexCoord0; + layout(location = 0) out vec4 fragColor0; + layout(set = 0, binding = 1) uniform sampler2D Sampler0; + void main() { + vec4 color = texture(Sampler0, oTexCoord0) * oColor0; + if (color.a <= 0.0) + discard; + fragColor0 = color; + })" + }, +}; + +GPUDriverTestScreen::GPUDriverTestScreen() { + using namespace Draw; +} + +GPUDriverTestScreen::~GPUDriverTestScreen() { + if (discardWriteStencil_) + discardWriteStencil_->Release(); + if (drawTestStencil_) + drawTestStencil_->Release(); + if (drawTestDepth_) + drawTestDepth_->Release(); + if (discard_) + discard_->Release(); + if (samplerNearest_) + samplerNearest_->Release(); +} + +void GPUDriverTestScreen::CreateViews() { + // Don't bother with views for now. + using namespace UI; + I18NCategory *di = GetI18NCategory("Dialog"); + I18NCategory *cr = GetI18NCategory("PSPCredits"); + + auto tabs = new TabHolder(UI::ORIENT_HORIZONTAL, 30.0f); + root_ = tabs; + tabs->AddTab("Discard", new LinearLayout(UI::ORIENT_VERTICAL)); +} + +void GPUDriverTestScreen::render() { + using namespace Draw; + UIScreen::render(); + + if (!discardWriteStencil_) { + DrawContext *draw = screenManager()->getDrawContext(); + + // Create the special shader module. + + discard_ = CreateShader(draw, Draw::ShaderStage::FRAGMENT, fsDiscard); + + InputLayout *inputLayout = ui_draw2d.CreateInputLayout(draw); + BlendState *blendOff = draw->CreateBlendState({false, 0xF}); + + // Write depth, write stencil. + DepthStencilStateDesc dsDesc{}; + dsDesc.depthTestEnabled = true; + dsDesc.depthWriteEnabled = true; + dsDesc.depthCompare = Comparison::ALWAYS; + dsDesc.stencilEnabled = true; + dsDesc.front.compareMask = 0xFF; + dsDesc.front.compareOp = Comparison::ALWAYS; + dsDesc.front.passOp = StencilOp::REPLACE; + dsDesc.front.failOp = StencilOp::ZERO; + dsDesc.front.depthFailOp = StencilOp::ZERO; + dsDesc.front.reference = 0xFF; + dsDesc.front.writeMask = 0xFF; + dsDesc.back = dsDesc.front; + DepthStencilState *depthStencilWrite = draw->CreateDepthStencilState(dsDesc); + + dsDesc.depthCompare = Comparison::ALWAYS; + dsDesc.front.compareOp = Comparison::EQUAL; + DepthStencilState *stencilTestEqual = draw->CreateDepthStencilState(dsDesc); + + dsDesc.depthCompare = Comparison::LESS_EQUAL; + dsDesc.front.compareOp = Comparison::ALWAYS; + DepthStencilState *depthTestEqual = draw->CreateDepthStencilState(dsDesc); + + RasterState *rasterNoCull = draw->CreateRasterState({}); + + PipelineDesc discardDesc{ + Primitive::TRIANGLE_LIST, + { draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), discard_ }, + inputLayout, depthStencilWrite, blendOff, rasterNoCull, &vsColBufDesc, + }; + discardWriteStencil_ = draw->CreateGraphicsPipeline(discardDesc); + + PipelineDesc testStencilDesc{ + Primitive::TRIANGLE_LIST, + { draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D) }, + inputLayout, stencilTestEqual, blendOff, rasterNoCull, &vsColBufDesc, + }; + drawTestStencil_ = draw->CreateGraphicsPipeline(testStencilDesc); + + PipelineDesc testDepthDesc{ + Primitive::TRIANGLE_LIST, + {draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D)}, + inputLayout, stencilTestEqual, blendOff, rasterNoCull, &vsColBufDesc, + }; + drawTestDepth_ = draw->CreateGraphicsPipeline(testDepthDesc); + + inputLayout->Release(); + blendOff->Release(); + depthStencilWrite->Release(); + stencilTestEqual->Release(); + depthTestEqual->Release(); + rasterNoCull->Release(); + + SamplerStateDesc nearestDesc{}; + samplerNearest_ = draw->CreateSamplerState(nearestDesc); + } + + UIContext &dc = *screenManager()->getUIContext(); + const Bounds &bounds = dc.GetBounds(); + + const char *testNames[] = {"Normal", "Z test", "Stencil test"}; + + const int numTests = ARRAY_SIZE(testNames); + + uint32_t textColorOK = 0xFF30FF30; + uint32_t textColorBAD = 0xFF3030FF; + uint32_t bgColorOK = 0xFF106010; + uint32_t bgColorBAD = 0xFF101060; + + // Don't want any fancy font texture stuff going on here, so use FLAG_DYNAMIC_ASCII everywhere! + + float testW = 200.f; + float padding = 20.0f; + UI::Style style = dc.theme->itemStyle; + + float y = 100; + float x = dc.GetBounds().centerX() - ((float)numTests * testW + (float)(numTests - 1) * padding) / 2.0f; + for (int i = 0; i < 3; i++) { + dc.Begin(); + dc.SetFontScale(1.0f, 1.0f); + Bounds bounds = {x - testW / 2, y + 40, testW, 70}; + dc.DrawText(testNames[i], bounds.x, y, style.fgColor, FLAG_DYNAMIC_ASCII); + + dc.FillRect(UI::Drawable(bgColorOK), bounds); + // test bounds + dc.Flush(); + + dc.BeginPipeline(discardWriteStencil_, samplerNearest_); + + dc.DrawTextRect("TEST OK", bounds, textColorBAD, ALIGN_HCENTER | ALIGN_VCENTER); + dc.Flush(); + + dc.BeginPipeline(drawTestStencil_, samplerNearest_); + dc.FillRect(UI::Drawable(textColorOK), bounds); + dc.Flush(); + + // Methodology: + // 1. Draw text in red, writing to stencil. + // 2. Use stencil test equality to make it green. + + x += testW + padding; + } + dc.SetFontScale(1.0f, 1.0f); + dc.Flush(); +} diff --git a/UI/GPUDriverTestScreen.h b/UI/GPUDriverTestScreen.h new file mode 100644 index 0000000000..3d987b97f1 --- /dev/null +++ b/UI/GPUDriverTestScreen.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "base/display.h" +#include "ui/ui_context.h" +#include "ui/view.h" +#include "ui/viewgroup.h" +#include "ui/ui.h" + +#include "Common/LogManager.h" +#include "UI/MiscScreens.h" +#include "thin3d/thin3d.h" + +class GPUDriverTestScreen : public UIDialogScreenWithBackground { +public: + GPUDriverTestScreen(); + ~GPUDriverTestScreen(); + + void CreateViews() override; + void render() override; + +private: + Draw::ShaderModule *discard_ = nullptr; + Draw::Pipeline *discardWriteStencil_ = nullptr; + Draw::Pipeline *drawTestStencil_ = nullptr; + Draw::Pipeline *drawTestDepth_ = nullptr; + Draw::SamplerState *samplerNearest_ = nullptr; +}; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 1d2e83fe68..579df2fb29 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -44,6 +44,7 @@ #include "UI/TiltAnalogSettingsScreen.h" #include "UI/TiltEventProcessor.h" #include "UI/ComboKeyMappingScreen.h" +#include "UI/GPUDriverTestScreen.h" #include "Common/KeyMap.h" #include "Common/FileUtil.h" @@ -1211,8 +1212,8 @@ UI::EventReturn GameSettingsScreen::OnPostProcShaderChange(UI::EventParams &e) { } UI::EventReturn GameSettingsScreen::OnDeveloperTools(UI::EventParams &e) { - screenManager()->push(new DeveloperToolsScreen()); - return UI::EVENT_DONE; +screenManager()->push(new DeveloperToolsScreen()); +return UI::EVENT_DONE; } UI::EventReturn GameSettingsScreen::OnRemoteISO(UI::EventParams &e) { @@ -1232,12 +1233,12 @@ UI::EventReturn GameSettingsScreen::OnTouchControlLayout(UI::EventParams &e) { //when the tilt event type is modified, we need to reset all tilt settings. //refer to the ResetTiltEvents() function for a detailed explanation. -UI::EventReturn GameSettingsScreen::OnTiltTypeChange(UI::EventParams &e){ +UI::EventReturn GameSettingsScreen::OnTiltTypeChange(UI::EventParams &e) { TiltEventProcessor::ResetTiltEvents(); return UI::EVENT_DONE; }; -UI::EventReturn GameSettingsScreen::OnTiltCustomize(UI::EventParams &e){ +UI::EventReturn GameSettingsScreen::OnTiltCustomize(UI::EventParams &e) { screenManager()->push(new TiltAnalogSettingsScreen()); return UI::EVENT_DONE; }; @@ -1276,7 +1277,7 @@ void DeveloperToolsScreen::CreateViews() { // iOS can now use JIT on all modes, apparently. // The bool may come in handy for future non-jit platforms though (UWP XB1?) - static const char *cpuCores[] = { "Interpreter", "Dynarec (JIT)", "IR Interpreter" }; + static const char *cpuCores[] = {"Interpreter", "Dynarec (JIT)", "IR Interpreter"}; PopupMultiChoice *core = list->Add(new PopupMultiChoice(&g_Config.iCpuCore, gr->T("CPU Core"), cpuCores, 0, ARRAY_SIZE(cpuCores), sy->GetName(), screenManager())); core->OnChoice.Handle(this, &DeveloperToolsScreen::OnJitAffectingSetting); if (!canUseJit) { @@ -1308,6 +1309,14 @@ void DeveloperToolsScreen::CreateViews() { list->Add(new ItemHeader(dev->T("Texture Replacement"))); list->Add(new CheckBox(&g_Config.bSaveNewTextures, dev->T("Save new textures"))); list->Add(new CheckBox(&g_Config.bReplaceTextures, dev->T("Replace textures"))); + + // For now, we only implement GPU driver tests for Vulkan and OpenGL. This is simply + // because the D3D drivers are generally solid enough to not need this type of investigation. + if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN || g_Config.iGPUBackend == (int)GPUBackend::OPENGL) { + list->Add(new ItemHeader(dev->T("Hardware Tests"))); + list->Add(new Choice(dev->T("GPU Driver Test")))->OnClick.Handle(this, &DeveloperToolsScreen::OnGPUDriverTest); + } + #if !defined(MOBILE_DEVICE) Choice *createTextureIni = list->Add(new Choice(dev->T("Create/Open textures.ini file for current game"))); createTextureIni->OnClick.Handle(this, &DeveloperToolsScreen::OnOpenTexturesIniFile); @@ -1382,6 +1391,11 @@ UI::EventReturn DeveloperToolsScreen::OnLogConfig(UI::EventParams &e) { return UI::EVENT_DONE; } +UI::EventReturn DeveloperToolsScreen::OnGPUDriverTest(UI::EventParams &e) { + screenManager()->push(new GPUDriverTestScreen()); + return UI::EVENT_DONE; +} + UI::EventReturn DeveloperToolsScreen::OnJitAffectingSetting(UI::EventParams &e) { NativeMessageReceived("clear jit", ""); return UI::EVENT_DONE; diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index 2fd3bcc463..915a524a20 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -158,6 +158,7 @@ private: UI::EventReturn OnLogConfig(UI::EventParams &e); UI::EventReturn OnJitAffectingSetting(UI::EventParams &e); UI::EventReturn OnRemoteDebugger(UI::EventParams &e); + UI::EventReturn OnGPUDriverTest(UI::EventParams &e); bool allowDebugger_ = false; bool canAllowDebugger_ = true; diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index d4ad6b19ad..9267fe291f 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -96,6 +96,7 @@ #include "UI/BackgroundAudio.h" #include "UI/TextureUtil.h" #include "UI/DiscordIntegration.h" +#include "UI/GPUDriverTestScreen.h" #if !defined(MOBILE_DEVICE) #include "Common/KeyMap.h" diff --git a/UI/UI.vcxproj b/UI/UI.vcxproj index f0bec7d79b..935362f6b6 100644 --- a/UI/UI.vcxproj +++ b/UI/UI.vcxproj @@ -32,6 +32,7 @@ + @@ -64,6 +65,7 @@ + diff --git a/UI/UI.vcxproj.filters b/UI/UI.vcxproj.filters index 0b5c2dd240..1b79119b4e 100644 --- a/UI/UI.vcxproj.filters +++ b/UI/UI.vcxproj.filters @@ -71,6 +71,9 @@ + + Screens + @@ -143,6 +146,9 @@ + + Screens + diff --git a/ext/native/gfx_es2/draw_buffer.cpp b/ext/native/gfx_es2/draw_buffer.cpp index 603d49ee8e..93b4fec587 100644 --- a/ext/native/gfx_es2/draw_buffer.cpp +++ b/ext/native/gfx_es2/draw_buffer.cpp @@ -78,6 +78,7 @@ void DrawBuffer::Shutdown() { void DrawBuffer::Begin(Draw::Pipeline *program) { pipeline_ = program; count_ = 0; + curZ_ = 0.0f; } void DrawBuffer::Flush(bool set_blend_state) { diff --git a/ext/native/gfx_es2/draw_buffer.h b/ext/native/gfx_es2/draw_buffer.h index 4b504dfcb8..788e4a125f 100644 --- a/ext/native/gfx_es2/draw_buffer.h +++ b/ext/native/gfx_es2/draw_buffer.h @@ -97,7 +97,7 @@ public: void V(float x, float y, float z, uint32_t color, float u, float v); void V(float x, float y, uint32_t color, float u, float v) { - V(x, y, 0.0f, color, u, v); + V(x, y, curZ_, color, u, v); } void Circle(float x, float y, float radius, float thickness, int segments, float startAngle, uint32_t color, float u_mul); @@ -166,6 +166,10 @@ public: alphaStack_.pop_back(); } + void SetCurZ(float curZ) { + curZ_ = curZ; + } + private: struct Vertex { float x, y, z; @@ -191,5 +195,7 @@ private: bool inited_; float fontscalex; float fontscaley; + + float curZ_ = 0.0f; }; diff --git a/ext/native/thin3d/thin3d.cpp b/ext/native/thin3d/thin3d.cpp index ddc70e2c7e..e8ace0d6a4 100644 --- a/ext/native/thin3d/thin3d.cpp +++ b/ext/native/thin3d/thin3d.cpp @@ -101,11 +101,6 @@ bool RefCountedObject::ReleaseAssertLast() { // The Vulkan ones can be re-used with modern GL later if desired, as they're just GLSL. -struct ShaderSource { - ShaderLanguage lang; - const char *src; -}; - static const std::vector fsTexCol = { {ShaderLanguage::GLSL_ES_200, "#ifdef GL_ES\n" @@ -196,6 +191,7 @@ static const std::vector vsCol = { "attribute vec3 Position;\n" "attribute vec4 Color0;\n" "varying vec4 oColor0;\n" + "uniform mat4 WorldViewProj;\n" "void main() {\n" " gl_Position = WorldViewProj * vec4(Position, 1.0);\n" @@ -317,7 +313,7 @@ const UniformBufferDesc vsTexColBufDesc{ sizeof(VsTexColUB),{ { "WorldViewProj", 0, -1, UniformType::MATRIX4X4, 0 } } }; -static ShaderModule *CreateShader(DrawContext *draw, ShaderStage stage, const std::vector &sources) { +ShaderModule *CreateShader(DrawContext *draw, ShaderStage stage, const std::vector &sources) { uint32_t supported = draw->GetSupportedShaderLanguages(); for (auto iter : sources) { if ((uint32_t)iter.lang & supported) { diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 4d77dc69fa..81eddb8f40 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -662,4 +662,13 @@ struct VsColUB { }; extern const UniformBufferDesc vsColBufDesc; +// Useful utility for specifying a shader in multiple languages. + +struct ShaderSource { + ShaderLanguage lang; + const char *src; +}; + +ShaderModule *CreateShader(DrawContext *draw, ShaderStage stage, const std::vector &sources); + } // namespace Draw diff --git a/ext/native/ui/ui.cpp b/ext/native/ui/ui.cpp index c0bfb3fad7..f8ea4f574a 100644 --- a/ext/native/ui/ui.cpp +++ b/ext/native/ui/ui.cpp @@ -15,9 +15,9 @@ DrawBuffer ui_draw2d; DrawBuffer ui_draw2d_front; -void UIBegin(Draw::Pipeline *shaderSet) { - ui_draw2d.Begin(shaderSet); - ui_draw2d_front.Begin(shaderSet); +void UIBegin(Draw::Pipeline *pipeline) { + ui_draw2d.Begin(pipeline); + ui_draw2d_front.Begin(pipeline); } void UIFlush() { diff --git a/ext/native/ui/ui_context.cpp b/ext/native/ui/ui_context.cpp index 914c849931..1c214d2820 100644 --- a/ext/native/ui/ui_context.cpp +++ b/ext/native/ui/ui_context.cpp @@ -52,6 +52,12 @@ void UIContext::BeginNoTex() { UIBegin(ui_pipeline_notex_); } +void UIContext::BeginPipeline(Draw::Pipeline *pipeline, Draw::SamplerState *samplerState) { + draw_->BindSamplerStates(0, 1, &sampler_); + draw_->BindTexture(0, uitexture_->GetTexture()); + UIBegin(pipeline); +} + void UIContext::RebindTexture() const { draw_->BindTexture(0, uitexture_->GetTexture()); } @@ -65,6 +71,11 @@ void UIContext::Flush() { } } +void UIContext::SetCurZ(float curZ) { + ui_draw2d.SetCurZ(curZ); + ui_draw2d_front.SetCurZ(curZ); +} + // TODO: Support transformed bounds using stencil instead. void UIContext::PushScissor(const Bounds &bounds) { Flush(); diff --git a/ext/native/ui/ui_context.h b/ext/native/ui/ui_context.h index 8d9d1c1f65..d48b5b1dbf 100644 --- a/ext/native/ui/ui_context.h +++ b/ext/native/ui/ui_context.h @@ -51,6 +51,7 @@ public: void Begin(); void BeginNoTex(); + void BeginPipeline(Draw::Pipeline *pipeline, Draw::SamplerState *samplerState); void Flush(); void RebindTexture() const; @@ -85,6 +86,7 @@ public: void SetBounds(const Bounds &b) { bounds_ = b; } const Bounds &GetBounds() const { return bounds_; } Draw::DrawContext *GetDrawContext() { return draw_; } + void SetCurZ(float curZ); void PushTransform(const UITransform &transform); void PopTransform(); From c2319cd6d16343a4de88e4f1eafb32198b5d54d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 18 Dec 2018 09:35:53 +0100 Subject: [PATCH 234/347] thin3d: Make the stencil ref value dynamic state (all APIs support this directly). --- UI/GPUDriverTestScreen.cpp | 38 +++++++++++++++++--------- UI/NativeApp.cpp | 2 ++ ext/native/thin3d/thin3d.h | 2 +- ext/native/thin3d/thin3d_d3d11.cpp | 9 ++++--- ext/native/thin3d/thin3d_d3d9.cpp | 8 +++--- ext/native/thin3d/thin3d_gl.cpp | 19 +++++++++---- ext/native/thin3d/thin3d_vulkan.cpp | 42 +++++++++++++++++++++++------ 7 files changed, 88 insertions(+), 32 deletions(-) diff --git a/UI/GPUDriverTestScreen.cpp b/UI/GPUDriverTestScreen.cpp index 0d46e8a59d..95d0984aee 100644 --- a/UI/GPUDriverTestScreen.cpp +++ b/UI/GPUDriverTestScreen.cpp @@ -4,27 +4,39 @@ static const std::vector fsDiscard = { {Draw::ShaderLanguage::GLSL_ES_200, - R"(varying vec4 oColor0; + R"( + #ifdef GL_ES + precision lowp float; + #endif + #if __VERSION__ >= 130 + #define varying in + #define gl_FragColor fragColor0 + out vec4 fragColor0; + #endif + varying vec4 oColor0; varying vec2 oTexCoord0; uniform sampler2D Sampler0; void main() { - vec4 color = texture2D(Sampler0, oTexCoord0) * oColor0; - if (color.a <= 0.0) - discard; - gl_FragColor = color; + vec4 color = texture2D(Sampler0, oTexCoord0) * oColor0; + if (color.a <= 0.0) + discard; + gl_FragColor = color; })" }, {Draw::ShaderLanguage::GLSL_VULKAN, - R"(layout(location = 0) in vec4 oColor0; + R"(#version 140 + #extension GL_ARB_separate_shader_objects : enable + #extension GL_ARB_shading_language_420pack : enable + layout(location = 0) in vec4 oColor0; layout(location = 1) in vec2 oTexCoord0; layout(location = 0) out vec4 fragColor0; layout(set = 0, binding = 1) uniform sampler2D Sampler0; void main() { - vec4 color = texture(Sampler0, oTexCoord0) * oColor0; - if (color.a <= 0.0) - discard; - fragColor0 = color; - })" + vec4 color = texture(Sampler0, oTexCoord0) * oColor0; + if (color.a <= 0.0) + discard; + fragColor0 = color; + })" }, }; @@ -81,7 +93,6 @@ void GPUDriverTestScreen::render() { dsDesc.front.passOp = StencilOp::REPLACE; dsDesc.front.failOp = StencilOp::ZERO; dsDesc.front.depthFailOp = StencilOp::ZERO; - dsDesc.front.reference = 0xFF; dsDesc.front.writeMask = 0xFF; dsDesc.back = dsDesc.front; DepthStencilState *depthStencilWrite = draw->CreateDepthStencilState(dsDesc); @@ -129,9 +140,11 @@ void GPUDriverTestScreen::render() { } UIContext &dc = *screenManager()->getUIContext(); + Draw::DrawContext *draw = dc.GetDrawContext(); const Bounds &bounds = dc.GetBounds(); const char *testNames[] = {"Normal", "Z test", "Stencil test"}; + Pipeline *testPipelines[] = { drawTestStencil_, drawTestDepth_, drawTestStencil_ }; const int numTests = ARRAY_SIZE(testNames); @@ -152,6 +165,7 @@ void GPUDriverTestScreen::render() { dc.Begin(); dc.SetFontScale(1.0f, 1.0f); Bounds bounds = {x - testW / 2, y + 40, testW, 70}; + draw->SetStencilRef(0x0); dc.DrawText(testNames[i], bounds.x, y, style.fgColor, FLAG_DYNAMIC_ASCII); dc.FillRect(UI::Drawable(bgColorOK), bounds); diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 9267fe291f..7f59a2472b 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -679,6 +679,8 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch screenManager->switchScreen(new LogoScreen()); } + screenManager->push(new GPUDriverTestScreen()); + if (g_Config.bRemoteShareOnStartup && g_Config.bRemoteDebuggerOnStartup) StartWebServer(WebServerFlags::ALL); else if (g_Config.bRemoteShareOnStartup) diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 81eddb8f40..8baa8cc5e2 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -416,7 +416,6 @@ struct StencilSide { Comparison compareOp; uint8_t compareMask; uint8_t writeMask; - uint8_t reference; }; struct DepthStencilStateDesc { @@ -588,6 +587,7 @@ public: virtual void SetScissorRect(int left, int top, int width, int height) = 0; virtual void SetViewports(int count, Viewport *viewports) = 0; virtual void SetBlendFactor(float color[4]) = 0; + virtual void SetStencilRef(uint8_t ref) = 0; virtual void BindSamplerStates(int start, int count, SamplerState **state) = 0; virtual void BindTextures(int start, int count, Texture **textures) = 0; diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index 69205d05e4..e93abb4c7e 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -95,6 +95,10 @@ public: blendFactorDirty_ = true; } } + void SetStencilRef(uint8_t ref) override { + stencilRef_ = ref; + stencilRefDirty_ = true; + } void Draw(int vertexCount, int offset) override; void DrawIndexed(int vertexCount, int offset) override; @@ -204,8 +208,8 @@ private: // Dynamic state float blendFactor_[4]{}; bool blendFactorDirty_ = false; - uint8_t stencilRef_; - bool stencilRefDirty_; + uint8_t stencilRef_ = 0; + bool stencilRefDirty_ = true; // Temporaries ID3D11Texture2D *packTexture_ = nullptr; @@ -975,7 +979,6 @@ void D3D11DrawContext::BindPipeline(Pipeline *pipeline) { curPipeline_ = dPipeline; } -// Gonna need dirtyflags soon.. void D3D11DrawContext::ApplyCurrentState() { if (curBlend_ != curPipeline_->blend || blendFactorDirty_) { context_->OMSetBlendState(curPipeline_->blend->bs, blendFactor_, 0xFFFFFFFF); diff --git a/ext/native/thin3d/thin3d_d3d9.cpp b/ext/native/thin3d/thin3d_d3d9.cpp index c6c22b37b7..8273446d48 100644 --- a/ext/native/thin3d/thin3d_d3d9.cpp +++ b/ext/native/thin3d/thin3d_d3d9.cpp @@ -154,7 +154,6 @@ public: D3DSTENCILOP stencilZFail; D3DSTENCILOP stencilPass; D3DCMPFUNC stencilCompareOp; - uint8_t stencilReference; uint8_t stencilCompareMask; uint8_t stencilWriteMask; void Apply(LPDIRECT3DDEVICE9 device) { @@ -170,7 +169,6 @@ public: device->SetRenderState(D3DRS_STENCILPASS, stencilPass); device->SetRenderState(D3DRS_STENCILFUNC, stencilCompareOp); device->SetRenderState(D3DRS_STENCILMASK, stencilCompareMask); - device->SetRenderState(D3DRS_STENCILREF, stencilReference); device->SetRenderState(D3DRS_STENCILWRITEMASK, stencilWriteMask); } } @@ -523,6 +521,7 @@ public: void SetScissorRect(int left, int top, int width, int height) override; void SetViewports(int count, Viewport *viewports) override; void SetBlendFactor(float color[4]) override; + void SetStencilRef(uint8_t ref) override; void Draw(int vertexCount, int offset) override; void DrawIndexed(int vertexCount, int offset) override; @@ -684,7 +683,6 @@ DepthStencilState *D3D9Context::CreateDepthStencilState(const DepthStencilStateD ds->stencilFail = stencilOpToD3D9[(int)desc.front.failOp]; ds->stencilZFail = stencilOpToD3D9[(int)desc.front.depthFailOp]; ds->stencilWriteMask = desc.front.writeMask; - ds->stencilReference = desc.front.reference; ds->stencilCompareMask = desc.front.compareMask; return ds; } @@ -966,6 +964,10 @@ void D3D9Context::SetBlendFactor(float color[4]) { device_->SetRenderState(D3DRS_BLENDFACTOR, r | (g << 8) | (b << 16) | (a << 24)); } +void D3D9Context::SetStencilRef(uint8_t ref) { + device_->SetRenderState(D3DRS_STENCILREF, (DWORD)ref); +} + bool D3D9ShaderModule::Compile(LPDIRECT3DDEVICE9 device, const uint8_t *data, size_t size) { LPD3DXMACRO defines = nullptr; LPD3DXINCLUDE includes = nullptr; diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index aae54b3879..19d3cea8ff 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -192,13 +192,12 @@ public: GLuint stencilZFail; GLuint stencilPass; GLuint stencilCompareOp; - uint8_t stencilReference; uint8_t stencilCompareMask; uint8_t stencilWriteMask; - void Apply(GLRenderManager *render) { + void Apply(GLRenderManager *render, uint8_t stencilRef) { render->SetDepth(depthTestEnabled, depthWriteEnabled, depthComp); - render->SetStencilFunc(stencilEnabled, stencilCompareOp, stencilReference, stencilCompareMask); + render->SetStencilFunc(stencilEnabled, stencilCompareOp, stencilRef, stencilCompareMask); render->SetStencilOp(stencilWriteMask, stencilFail, stencilZFail, stencilPass); } }; @@ -404,6 +403,15 @@ public: renderManager_.SetBlendFactor(color); } + void SetStencilRef(uint8_t ref) override { + stencilRef_ = ref; + renderManager_.SetStencilFunc( + curPipeline_->depthStencil->stencilEnabled, + curPipeline_->depthStencil->stencilCompareOp, + ref, + curPipeline_->depthStencil->stencilCompareMask); + } + void BindTextures(int start, int count, Texture **textures) override; void BindPipeline(Pipeline *pipeline) override; void BindVertexBuffers(int start, int count, Buffer **buffers, int *offsets) override { @@ -485,6 +493,8 @@ private: OpenGLBuffer *curIBuffer_ = nullptr; int curIBufferOffset_ = 0; + uint8_t stencilRef_ = 0; + // Frames in flight is not such a strict concept as with Vulkan until we start using glBufferStorage and fences. // But might as well have the structure ready, and can't hurt to rotate buffers. struct FrameData { @@ -750,7 +760,6 @@ DepthStencilState *OpenGLContext::CreateDepthStencilState(const DepthStencilStat ds->stencilFail = stencilOpToGL[(int)desc.front.failOp]; ds->stencilZFail = stencilOpToGL[(int)desc.front.depthFailOp]; ds->stencilWriteMask = desc.front.writeMask; - ds->stencilReference = desc.front.reference; ds->stencilCompareMask = desc.front.compareMask; return ds; } @@ -959,7 +968,7 @@ bool OpenGLPipeline::LinkShaders() { void OpenGLContext::BindPipeline(Pipeline *pipeline) { curPipeline_ = (OpenGLPipeline *)pipeline; curPipeline_->blend->Apply(&renderManager_); - curPipeline_->depthStencil->Apply(&renderManager_); + curPipeline_->depthStencil->Apply(&renderManager_, stencilRef_); curPipeline_->raster->Apply(&renderManager_); renderManager_.BindProgram(curPipeline_->program_); } diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 8e0fd5a238..7f8d36afac 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -275,6 +275,10 @@ public: int stride[4]{}; int dynamicUniformSize = 0; + bool usesStencil = false; + uint8_t stencilWriteMask = 0xFF; + uint8_t stencilTestMask = 0xFF; + private: VulkanContext *vulkan_; uint8_t *ubo_; @@ -388,6 +392,7 @@ public: void SetScissorRect(int left, int top, int width, int height) override; void SetViewports(int count, Viewport *viewports) override; void SetBlendFactor(float color[4]) override; + void SetStencilRef(uint8_t stencilRef) override; void BindSamplerStates(int start, int count, SamplerState **state) override; void BindTextures(int start, int count, Texture **textures) override; @@ -414,6 +419,8 @@ public: void DrawIndexed(int vertexCount, int offset) override; void DrawUP(const void *vdata, int vertexCount) override; + void ApplyDynamicState(); + void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) override; void BeginFrame() override; @@ -541,6 +548,8 @@ private: VulkanPushBuffer *push_ = nullptr; DeviceCaps caps_{}; + + uint8_t stencilRef_ = 0; }; static int GetBpp(VkFormat format) { @@ -979,9 +988,10 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) { inputAssembly.topology = primToVK[(int)desc.prim]; inputAssembly.primitiveRestartEnable = false; - VkDynamicState dynamics[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; + // We treat the three stencil states as a unit in other places, so let's do that here too. + VkDynamicState dynamics[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, VK_DYNAMIC_STATE_STENCIL_REFERENCE, VK_DYNAMIC_STATE_STENCIL_WRITE_MASK }; VkPipelineDynamicStateCreateInfo dynamicInfo = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO }; - dynamicInfo.dynamicStateCount = ARRAY_SIZE(dynamics); + dynamicInfo.dynamicStateCount = depth->info.stencilTestEnable ? ARRAY_SIZE(dynamics) : 2; dynamicInfo.pDynamicStates = dynamics; VkPipelineMultisampleStateCreateInfo ms = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO }; @@ -1027,7 +1037,11 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) { if (desc.uniformDesc) { pipeline->dynamicUniformSize = (int)desc.uniformDesc->uniformBufferSize; } - + if (depth->info.stencilTestEnable) { + pipeline->usesStencil = true; + pipeline->stencilTestMask = depth->info.front.compareMask; + pipeline->stencilWriteMask = depth->info.front.writeMask; + } return pipeline; } @@ -1053,6 +1067,12 @@ void VKContext::SetBlendFactor(float color[4]) { renderManager_.SetBlendFactor(color); } +void VKContext::SetStencilRef(uint8_t stencilRef) { + if (curPipeline_->usesStencil) + renderManager_.SetStencilParams(curPipeline_->stencilWriteMask, curPipeline_->stencilTestMask, stencilRef); + stencilRef_ = stencilRef; +} + InputLayout *VKContext::CreateInputLayout(const InputLayoutDesc &desc) { VKInputLayout *vl = new VKInputLayout(); vl->visc = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO }; @@ -1096,7 +1116,6 @@ Texture *VKContext::CreateTexture(const TextureDesc &desc) { static inline void CopySide(VkStencilOpState &dest, const StencilSide &src) { dest.compareMask = src.compareMask; - dest.reference = src.reference; dest.writeMask = src.writeMask; dest.compareOp = compToVK[(int)src.compareOp]; dest.failOp = stencilOpToVK[(int)src.failOp]; @@ -1109,7 +1128,7 @@ DepthStencilState *VKContext::CreateDepthStencilState(const DepthStencilStateDes ds->info.depthCompareOp = compToVK[(int)desc.depthCompare]; ds->info.depthTestEnable = desc.depthTestEnabled; ds->info.depthWriteEnable = desc.depthWriteEnabled; - ds->info.stencilTestEnable = false; + ds->info.stencilTestEnable = desc.stencilEnabled; ds->info.depthBoundsTestEnable = false; if (ds->info.stencilTestEnable) { CopySide(ds->info.front, desc.front); @@ -1197,6 +1216,13 @@ void VKContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) { curPipeline_->SetDynamicUniformData(ub, size); } +void VKContext::ApplyDynamicState() { + // TODO: blend constants, stencil, viewports should be here, after bindpipeline.. + if (curPipeline_->usesStencil) { + renderManager_.SetStencilParams(curPipeline_->stencilWriteMask, curPipeline_->stencilTestMask, stencilRef_); + } +} + void VKContext::Draw(int vertexCount, int offset) { VKBuffer *vbuf = curVBuffers_[0]; @@ -1208,7 +1234,7 @@ void VKContext::Draw(int vertexCount, int offset) { VkDescriptorSet descSet = GetOrCreateDescriptorSet(vulkanUBObuf); renderManager_.BindPipeline(curPipeline_->vkpipeline); - // TODO: blend constants, stencil, viewports should be here, after bindpipeline.. + ApplyDynamicState(); renderManager_.Draw(pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset, vertexCount); } @@ -1224,7 +1250,7 @@ void VKContext::DrawIndexed(int vertexCount, int offset) { VkDescriptorSet descSet = GetOrCreateDescriptorSet(vulkanUBObuf); renderManager_.BindPipeline(curPipeline_->vkpipeline); - // TODO: blend constants, stencil, viewports should be here, after bindpipeline.. + ApplyDynamicState(); renderManager_.DrawIndexed(pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset, vulkanIbuf, (int)ibBindOffset, vertexCount, 1, VK_INDEX_TYPE_UINT32); } @@ -1236,7 +1262,7 @@ void VKContext::DrawUP(const void *vdata, int vertexCount) { VkDescriptorSet descSet = GetOrCreateDescriptorSet(vulkanUBObuf); renderManager_.BindPipeline(curPipeline_->vkpipeline); - // TODO: blend constants, stencil, viewports should be here, after bindpipeline.. + ApplyDynamicState(); renderManager_.Draw(pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset, vertexCount); } From 2c83574377111d329321a00aa592a57a68dff64d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 18 Dec 2018 23:56:36 +0100 Subject: [PATCH 235/347] Finish up the test --- UI/GPUDriverTestScreen.cpp | 128 ++++++++++++++++++++--------- UI/GPUDriverTestScreen.h | 11 ++- UI/GameSettingsScreen.cpp | 12 ++- UI/NativeApp.cpp | 3 +- ext/native/gfx_es2/draw_buffer.cpp | 1 - ext/native/ui/ui_context.cpp | 2 + 6 files changed, 106 insertions(+), 51 deletions(-) diff --git a/UI/GPUDriverTestScreen.cpp b/UI/GPUDriverTestScreen.cpp index 95d0984aee..820d0ce8f5 100644 --- a/UI/GPUDriverTestScreen.cpp +++ b/UI/GPUDriverTestScreen.cpp @@ -45,12 +45,16 @@ GPUDriverTestScreen::GPUDriverTestScreen() { } GPUDriverTestScreen::~GPUDriverTestScreen() { - if (discardWriteStencil_) - discardWriteStencil_->Release(); - if (drawTestStencil_) - drawTestStencil_->Release(); - if (drawTestDepth_) - drawTestDepth_->Release(); + if (discardWriteDepthStencil_) + discardWriteDepthStencil_->Release(); + if (drawTestStencilEqual_) + drawTestStencilEqual_->Release(); + if (drawTestStencilNotEqual_) + drawTestStencilNotEqual_->Release(); + if (drawTestDepthLessEqual_) + drawTestDepthLessEqual_->Release(); + if (drawTestDepthGreater_) + drawTestDepthGreater_->Release(); if (discard_) discard_->Release(); if (samplerNearest_) @@ -63,16 +67,22 @@ void GPUDriverTestScreen::CreateViews() { I18NCategory *di = GetI18NCategory("Dialog"); I18NCategory *cr = GetI18NCategory("PSPCredits"); - auto tabs = new TabHolder(UI::ORIENT_HORIZONTAL, 30.0f); - root_ = tabs; - tabs->AddTab("Discard", new LinearLayout(UI::ORIENT_VERTICAL)); + AnchorLayout *anchor = new AnchorLayout(); + root_ = anchor; + + tabHolder_ = new TabHolder(ORIENT_HORIZONTAL, 30.0f, new AnchorLayoutParams(FILL_PARENT, FILL_PARENT, false)); + anchor->Add(tabHolder_); + tabHolder_->AddTab("Discard", new LinearLayout(ORIENT_VERTICAL)); + + Choice *back = new Choice(di->T("Back"), "", false, new AnchorLayoutParams(100, WRAP_CONTENT, 10, NONE, NONE, 10)); + back->OnClick.Handle(this, &UIScreen::OnBack); + anchor->Add(back); } -void GPUDriverTestScreen::render() { +void GPUDriverTestScreen::DiscardTest() { + using namespace UI; using namespace Draw; - UIScreen::render(); - - if (!discardWriteStencil_) { + if (!discardWriteDepthStencil_) { DrawContext *draw = screenManager()->getDrawContext(); // Create the special shader module. @@ -80,7 +90,7 @@ void GPUDriverTestScreen::render() { discard_ = CreateShader(draw, Draw::ShaderStage::FRAGMENT, fsDiscard); InputLayout *inputLayout = ui_draw2d.CreateInputLayout(draw); - BlendState *blendOff = draw->CreateBlendState({false, 0xF}); + BlendState *blendOff = draw->CreateBlendState({ false, 0xF }); // Write depth, write stencil. DepthStencilStateDesc dsDesc{}; @@ -99,11 +109,20 @@ void GPUDriverTestScreen::render() { dsDesc.depthCompare = Comparison::ALWAYS; dsDesc.front.compareOp = Comparison::EQUAL; + dsDesc.back = dsDesc.front; DepthStencilState *stencilTestEqual = draw->CreateDepthStencilState(dsDesc); + dsDesc.depthCompare = Comparison::ALWAYS; + dsDesc.front.compareOp = Comparison::NOT_EQUAL; + dsDesc.back = dsDesc.front; + DepthStencilState *stencilTestNotEqual = draw->CreateDepthStencilState(dsDesc); + dsDesc.depthCompare = Comparison::LESS_EQUAL; dsDesc.front.compareOp = Comparison::ALWAYS; - DepthStencilState *depthTestEqual = draw->CreateDepthStencilState(dsDesc); + dsDesc.back = dsDesc.front; + DepthStencilState *depthTestLessEqual = draw->CreateDepthStencilState(dsDesc); + dsDesc.depthCompare = Comparison::GREATER; + DepthStencilState *depthTestGreater = draw->CreateDepthStencilState(dsDesc); RasterState *rasterNoCull = draw->CreateRasterState({}); @@ -112,27 +131,31 @@ void GPUDriverTestScreen::render() { { draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), discard_ }, inputLayout, depthStencilWrite, blendOff, rasterNoCull, &vsColBufDesc, }; - discardWriteStencil_ = draw->CreateGraphicsPipeline(discardDesc); + discardWriteDepthStencil_ = draw->CreateGraphicsPipeline(discardDesc); - PipelineDesc testStencilDesc{ + PipelineDesc testDesc{ Primitive::TRIANGLE_LIST, { draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D) }, inputLayout, stencilTestEqual, blendOff, rasterNoCull, &vsColBufDesc, }; - drawTestStencil_ = draw->CreateGraphicsPipeline(testStencilDesc); + drawTestStencilEqual_ = draw->CreateGraphicsPipeline(testDesc); - PipelineDesc testDepthDesc{ - Primitive::TRIANGLE_LIST, - {draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D)}, - inputLayout, stencilTestEqual, blendOff, rasterNoCull, &vsColBufDesc, - }; - drawTestDepth_ = draw->CreateGraphicsPipeline(testDepthDesc); + testDesc.depthStencil = stencilTestNotEqual; + drawTestStencilNotEqual_ = draw->CreateGraphicsPipeline(testDesc); + + testDesc.depthStencil = depthTestGreater; + drawTestDepthGreater_ = draw->CreateGraphicsPipeline(testDesc); + + testDesc.depthStencil = depthTestLessEqual; + drawTestDepthLessEqual_ = draw->CreateGraphicsPipeline(testDesc); inputLayout->Release(); blendOff->Release(); depthStencilWrite->Release(); stencilTestEqual->Release(); - depthTestEqual->Release(); + stencilTestNotEqual->Release(); + depthTestLessEqual->Release(); + depthTestGreater->Release(); rasterNoCull->Release(); SamplerStateDesc nearestDesc{}; @@ -143,8 +166,9 @@ void GPUDriverTestScreen::render() { Draw::DrawContext *draw = dc.GetDrawContext(); const Bounds &bounds = dc.GetBounds(); - const char *testNames[] = {"Normal", "Z test", "Stencil test"}; - Pipeline *testPipelines[] = { drawTestStencil_, drawTestDepth_, drawTestStencil_ }; + const char *testNames[] = { "Stencil test", "Depth test" }; + Pipeline *testPipeline1[] = { drawTestStencilEqual_, drawTestDepthLessEqual_ }; + Pipeline *testPipeline2[] = { drawTestStencilNotEqual_, drawTestDepthGreater_ }; const int numTests = ARRAY_SIZE(testNames); @@ -155,38 +179,64 @@ void GPUDriverTestScreen::render() { // Don't want any fancy font texture stuff going on here, so use FLAG_DYNAMIC_ASCII everywhere! + // We draw the background at Z=0.5 and the text at Z=0.9. + + // Then we draw a rectangle with a depth test or stencil test that should mask out the text. + // Plus a second rectangle with the opposite test. + + // If everything is OK, both the background and the text should be OK. + float testW = 200.f; float padding = 20.0f; UI::Style style = dc.theme->itemStyle; float y = 100; - float x = dc.GetBounds().centerX() - ((float)numTests * testW + (float)(numTests - 1) * padding) / 2.0f; - for (int i = 0; i < 3; i++) { + float x = (dc.GetBounds().w - (float)numTests * testW - (float)(numTests - 1) * padding) / 2.0f; + for (int i = 0; i < numTests; i++) { dc.Begin(); dc.SetFontScale(1.0f, 1.0f); - Bounds bounds = {x - testW / 2, y + 40, testW, 70}; - draw->SetStencilRef(0x0); + Bounds bounds = { x, y + 40, testW, 70 }; dc.DrawText(testNames[i], bounds.x, y, style.fgColor, FLAG_DYNAMIC_ASCII); + dc.Flush(); - dc.FillRect(UI::Drawable(bgColorOK), bounds); + dc.BeginPipeline(discardWriteDepthStencil_, samplerNearest_); + // Draw the rectangle with stencil value 0, depth 0.1f and the text with stencil 0xFF, depth 0.9. Then leave 0xFF as the stencil value and draw the rectangles at depth 0.5. + draw->SetStencilRef(0x0); + dc.SetCurZ(0.1f); + dc.FillRect(UI::Drawable(bgColorBAD), bounds); // test bounds dc.Flush(); - dc.BeginPipeline(discardWriteStencil_, samplerNearest_); - - dc.DrawTextRect("TEST OK", bounds, textColorBAD, ALIGN_HCENTER | ALIGN_VCENTER); + draw->SetStencilRef(0xff); + dc.SetCurZ(0.9f); + dc.DrawTextRect("TEST OK", bounds, textColorBAD, ALIGN_HCENTER | ALIGN_VCENTER | FLAG_DYNAMIC_ASCII); dc.Flush(); - dc.BeginPipeline(drawTestStencil_, samplerNearest_); + // Draw rectangle that should result in the text + dc.BeginPipeline(testPipeline1[i], samplerNearest_); + draw->SetStencilRef(0xff); + dc.SetCurZ(0.5f); dc.FillRect(UI::Drawable(textColorOK), bounds); dc.Flush(); - // Methodology: - // 1. Draw text in red, writing to stencil. - // 2. Use stencil test equality to make it green. + // Draw rectangle that should result in the bg + dc.BeginPipeline(testPipeline2[i], samplerNearest_); + draw->SetStencilRef(0xff); + dc.SetCurZ(0.5f); + dc.FillRect(UI::Drawable(bgColorOK), bounds); + dc.Flush(); x += testW + padding; } dc.SetFontScale(1.0f, 1.0f); dc.Flush(); } + +void GPUDriverTestScreen::render() { + using namespace Draw; + UIScreen::render(); + + if (tabHolder_->GetCurrentTab() == 0) { + DiscardTest(); + } +} diff --git a/UI/GPUDriverTestScreen.h b/UI/GPUDriverTestScreen.h index 3d987b97f1..9c8cc73590 100644 --- a/UI/GPUDriverTestScreen.h +++ b/UI/GPUDriverTestScreen.h @@ -21,9 +21,14 @@ public: void render() override; private: + void DiscardTest(); + Draw::ShaderModule *discard_ = nullptr; - Draw::Pipeline *discardWriteStencil_ = nullptr; - Draw::Pipeline *drawTestStencil_ = nullptr; - Draw::Pipeline *drawTestDepth_ = nullptr; + Draw::Pipeline *discardWriteDepthStencil_ = nullptr; + Draw::Pipeline *drawTestStencilEqual_ = nullptr; + Draw::Pipeline *drawTestStencilNotEqual_ = nullptr; + Draw::Pipeline *drawTestDepthLessEqual_ = nullptr; + Draw::Pipeline *drawTestDepthGreater_ = nullptr; Draw::SamplerState *samplerNearest_ = nullptr; + UI::TabHolder *tabHolder_ = nullptr; }; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 579df2fb29..37f5451f2f 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1293,6 +1293,11 @@ void DeveloperToolsScreen::CreateViews() { cpuTests->SetEnabled(TestsAvailable()); #endif + // For now, we only implement GPU driver tests for Vulkan and OpenGL. This is simply + // because the D3D drivers are generally solid enough to not need this type of investigation. + if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN || g_Config.iGPUBackend == (int)GPUBackend::OPENGL) { + list->Add(new Choice(dev->T("GPU Driver Test")))->OnClick.Handle(this, &DeveloperToolsScreen::OnGPUDriverTest); + } allowDebugger_ = !WebServerStopped(WebServerFlags::DEBUGGER); canAllowDebugger_ = !WebServerStopping(WebServerFlags::DEBUGGER); @@ -1310,13 +1315,6 @@ void DeveloperToolsScreen::CreateViews() { list->Add(new CheckBox(&g_Config.bSaveNewTextures, dev->T("Save new textures"))); list->Add(new CheckBox(&g_Config.bReplaceTextures, dev->T("Replace textures"))); - // For now, we only implement GPU driver tests for Vulkan and OpenGL. This is simply - // because the D3D drivers are generally solid enough to not need this type of investigation. - if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN || g_Config.iGPUBackend == (int)GPUBackend::OPENGL) { - list->Add(new ItemHeader(dev->T("Hardware Tests"))); - list->Add(new Choice(dev->T("GPU Driver Test")))->OnClick.Handle(this, &DeveloperToolsScreen::OnGPUDriverTest); - } - #if !defined(MOBILE_DEVICE) Choice *createTextureIni = list->Add(new Choice(dev->T("Create/Open textures.ini file for current game"))); createTextureIni->OnClick.Handle(this, &DeveloperToolsScreen::OnOpenTexturesIniFile); diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 7f59a2472b..55d4c3b955 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -679,7 +679,8 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch screenManager->switchScreen(new LogoScreen()); } - screenManager->push(new GPUDriverTestScreen()); + // Easy testing + // screenManager->push(new GPUDriverTestScreen()); if (g_Config.bRemoteShareOnStartup && g_Config.bRemoteDebuggerOnStartup) StartWebServer(WebServerFlags::ALL); diff --git a/ext/native/gfx_es2/draw_buffer.cpp b/ext/native/gfx_es2/draw_buffer.cpp index 93b4fec587..603d49ee8e 100644 --- a/ext/native/gfx_es2/draw_buffer.cpp +++ b/ext/native/gfx_es2/draw_buffer.cpp @@ -78,7 +78,6 @@ void DrawBuffer::Shutdown() { void DrawBuffer::Begin(Draw::Pipeline *program) { pipeline_ = program; count_ = 0; - curZ_ = 0.0f; } void DrawBuffer::Flush(bool set_blend_state) { diff --git a/ext/native/ui/ui_context.cpp b/ext/native/ui/ui_context.cpp index 1c214d2820..0106888ec4 100644 --- a/ext/native/ui/ui_context.cpp +++ b/ext/native/ui/ui_context.cpp @@ -38,6 +38,8 @@ void UIContext::BeginFrame() { FLOG("Failed to load ui_atlas.zim"); } } + uidrawbufferTop_->SetCurZ(0.0f); + uidrawbuffer_->SetCurZ(0.0f); ActivateTopScissor(); } From 04646fe678b4862dc2c72b87213d27294b27506a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 19 Dec 2018 14:01:19 +0100 Subject: [PATCH 236/347] Build system updates --- CMakeLists.txt | 1 + UWP/UI_UWP/UI_UWP.vcxproj | 4 +++- UWP/UI_UWP/UI_UWP.vcxproj.filters | 2 ++ android/jni/Android.mk | 1 + 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e65121389..65d7a330e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -850,6 +850,7 @@ list(APPEND NativeAppSource UI/PauseScreen.cpp UI/GameScreen.cpp UI/GameSettingsScreen.cpp + UI/GPUDriverTestScreen.cpp UI/TiltAnalogSettingsScreen.cpp UI/TiltEventProcessor.cpp UI/TouchControlLayoutScreen.cpp diff --git a/UWP/UI_UWP/UI_UWP.vcxproj b/UWP/UI_UWP/UI_UWP.vcxproj index a73d6f94a5..a71aff31d9 100644 --- a/UWP/UI_UWP/UI_UWP.vcxproj +++ b/UWP/UI_UWP/UI_UWP.vcxproj @@ -312,6 +312,7 @@ + @@ -346,6 +347,7 @@ + @@ -378,4 +380,4 @@ - \ No newline at end of file + diff --git a/UWP/UI_UWP/UI_UWP.vcxproj.filters b/UWP/UI_UWP/UI_UWP.vcxproj.filters index b3ee44e3c8..89c1fdc6d8 100644 --- a/UWP/UI_UWP/UI_UWP.vcxproj.filters +++ b/UWP/UI_UWP/UI_UWP.vcxproj.filters @@ -15,6 +15,7 @@ + @@ -49,6 +50,7 @@ + diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 7e5d2829d6..a266947e42 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -506,6 +506,7 @@ LOCAL_SRC_FILES := \ $(SRC)/UI/GameScreen.cpp \ $(SRC)/UI/ControlMappingScreen.cpp \ $(SRC)/UI/GameSettingsScreen.cpp \ + $(SRC)/UI/GPUDriverTestScreen.cpp \ $(SRC)/UI/TiltAnalogSettingsScreen.cpp \ $(SRC)/UI/TiltEventProcessor.cpp \ $(SRC)/UI/TouchControlLayoutScreen.cpp \ From a8ff94e30b289ec3b0d17303ef728c32a3339e80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 19 Dec 2018 14:41:07 +0100 Subject: [PATCH 237/347] Display some important information on GPU test screen to make screenshots more useful --- UI/GPUDriverTestScreen.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/UI/GPUDriverTestScreen.cpp b/UI/GPUDriverTestScreen.cpp index 820d0ce8f5..d468b5cdb4 100644 --- a/UI/GPUDriverTestScreen.cpp +++ b/UI/GPUDriverTestScreen.cpp @@ -186,11 +186,20 @@ void GPUDriverTestScreen::DiscardTest() { // If everything is OK, both the background and the text should be OK. + dc.Begin(); + std::string apiName = screenManager()->getDrawContext()->GetInfoString(InfoField::APINAME); + std::string vendor = screenManager()->getDrawContext()->GetInfoString(InfoField::VENDORSTRING); + std::string driver = screenManager()->getDrawContext()->GetInfoString(InfoField::DRIVER); + dc.DrawText(apiName.c_str(), bounds.centerX(), 20, 0xFFFFFFFF, ALIGN_CENTER); + dc.DrawText(vendor.c_str(), bounds.centerX(), 60, 0xFFFFFFFF, ALIGN_CENTER); + dc.DrawText(driver.c_str(), bounds.centerX(), 100, 0xFFFFFFFF, ALIGN_CENTER); + dc.Flush(); + float testW = 200.f; float padding = 20.0f; UI::Style style = dc.theme->itemStyle; - float y = 100; + float y = 150; float x = (dc.GetBounds().w - (float)numTests * testW - (float)(numTests - 1) * padding) / 2.0f; for (int i = 0; i < numTests; i++) { dc.Begin(); From 352bafde7cc9a69e56c924abbaccf6e00bd2f950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 19 Dec 2018 20:21:07 +0100 Subject: [PATCH 238/347] GPU driver test: Add a third test with depth completely disabled, and rename the others to match. --- UI/GPUDriverTestScreen.cpp | 33 +++++++++++++++++++++++++++++---- UI/GPUDriverTestScreen.h | 2 ++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/UI/GPUDriverTestScreen.cpp b/UI/GPUDriverTestScreen.cpp index d468b5cdb4..e1762d04e0 100644 --- a/UI/GPUDriverTestScreen.cpp +++ b/UI/GPUDriverTestScreen.cpp @@ -47,6 +47,10 @@ GPUDriverTestScreen::GPUDriverTestScreen() { GPUDriverTestScreen::~GPUDriverTestScreen() { if (discardWriteDepthStencil_) discardWriteDepthStencil_->Release(); + if (drawTestStencilEqualDepthAlways_) + drawTestStencilEqualDepthAlways_->Release(); + if (drawTestStencilNotEqualDepthAlways_) + drawTestStencilNotEqualDepthAlways_->Release(); if (drawTestStencilEqual_) drawTestStencilEqual_->Release(); if (drawTestStencilNotEqual_) @@ -107,16 +111,29 @@ void GPUDriverTestScreen::DiscardTest() { dsDesc.back = dsDesc.front; DepthStencilState *depthStencilWrite = draw->CreateDepthStencilState(dsDesc); + dsDesc.depthTestEnabled = true; dsDesc.depthCompare = Comparison::ALWAYS; dsDesc.front.compareOp = Comparison::EQUAL; dsDesc.back = dsDesc.front; + DepthStencilState *stencilTestEqualDepthAlways = draw->CreateDepthStencilState(dsDesc); + + dsDesc.depthTestEnabled = false; + dsDesc.front.compareOp = Comparison::EQUAL; + dsDesc.back = dsDesc.front; DepthStencilState *stencilTestEqual = draw->CreateDepthStencilState(dsDesc); + dsDesc.depthTestEnabled = true; dsDesc.depthCompare = Comparison::ALWAYS; dsDesc.front.compareOp = Comparison::NOT_EQUAL; dsDesc.back = dsDesc.front; + DepthStencilState *stencilTestNotEqualDepthAlways = draw->CreateDepthStencilState(dsDesc); + + dsDesc.depthTestEnabled = false; + dsDesc.front.compareOp = Comparison::NOT_EQUAL; + dsDesc.back = dsDesc.front; DepthStencilState *stencilTestNotEqual = draw->CreateDepthStencilState(dsDesc); + dsDesc.depthTestEnabled = true; dsDesc.depthCompare = Comparison::LESS_EQUAL; dsDesc.front.compareOp = Comparison::ALWAYS; dsDesc.back = dsDesc.front; @@ -140,9 +157,15 @@ void GPUDriverTestScreen::DiscardTest() { }; drawTestStencilEqual_ = draw->CreateGraphicsPipeline(testDesc); + testDesc.depthStencil = stencilTestEqualDepthAlways; + drawTestStencilEqualDepthAlways_ = draw->CreateGraphicsPipeline(testDesc); + testDesc.depthStencil = stencilTestNotEqual; drawTestStencilNotEqual_ = draw->CreateGraphicsPipeline(testDesc); + testDesc.depthStencil = stencilTestNotEqualDepthAlways; + drawTestStencilNotEqualDepthAlways_ = draw->CreateGraphicsPipeline(testDesc); + testDesc.depthStencil = depthTestGreater; drawTestDepthGreater_ = draw->CreateGraphicsPipeline(testDesc); @@ -154,6 +177,8 @@ void GPUDriverTestScreen::DiscardTest() { depthStencilWrite->Release(); stencilTestEqual->Release(); stencilTestNotEqual->Release(); + stencilTestEqualDepthAlways->Release(); + stencilTestNotEqualDepthAlways->Release(); depthTestLessEqual->Release(); depthTestGreater->Release(); rasterNoCull->Release(); @@ -166,9 +191,9 @@ void GPUDriverTestScreen::DiscardTest() { Draw::DrawContext *draw = dc.GetDrawContext(); const Bounds &bounds = dc.GetBounds(); - const char *testNames[] = { "Stencil test", "Depth test" }; - Pipeline *testPipeline1[] = { drawTestStencilEqual_, drawTestDepthLessEqual_ }; - Pipeline *testPipeline2[] = { drawTestStencilNotEqual_, drawTestDepthGreater_ }; + const char *testNames[] = { "Stencil", "Stencil+DepthA", "StencilA+Depth" }; + Pipeline *testPipeline1[] = { drawTestStencilEqual_, drawTestStencilEqualDepthAlways_, drawTestDepthLessEqual_ }; + Pipeline *testPipeline2[] = { drawTestStencilNotEqual_, drawTestStencilNotEqualDepthAlways_, drawTestDepthGreater_ }; const int numTests = ARRAY_SIZE(testNames); @@ -195,7 +220,7 @@ void GPUDriverTestScreen::DiscardTest() { dc.DrawText(driver.c_str(), bounds.centerX(), 100, 0xFFFFFFFF, ALIGN_CENTER); dc.Flush(); - float testW = 200.f; + float testW = 220.f; float padding = 20.0f; UI::Style style = dc.theme->itemStyle; diff --git a/UI/GPUDriverTestScreen.h b/UI/GPUDriverTestScreen.h index 9c8cc73590..892d1bb13a 100644 --- a/UI/GPUDriverTestScreen.h +++ b/UI/GPUDriverTestScreen.h @@ -27,6 +27,8 @@ private: Draw::Pipeline *discardWriteDepthStencil_ = nullptr; Draw::Pipeline *drawTestStencilEqual_ = nullptr; Draw::Pipeline *drawTestStencilNotEqual_ = nullptr; + Draw::Pipeline *drawTestStencilEqualDepthAlways_ = nullptr; + Draw::Pipeline *drawTestStencilNotEqualDepthAlways_ = nullptr; Draw::Pipeline *drawTestDepthLessEqual_ = nullptr; Draw::Pipeline *drawTestDepthGreater_ = nullptr; Draw::SamplerState *samplerNearest_ = nullptr; From c8f86def97e1c772d2e06bcabb490d0042a2defa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 19 Dec 2018 22:39:37 +0100 Subject: [PATCH 239/347] Android EGL: Add logging of depth and stencil bits --- .../src/org/ppsspp/ppsspp/NativeRenderer.java | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/android/src/org/ppsspp/ppsspp/NativeRenderer.java b/android/src/org/ppsspp/ppsspp/NativeRenderer.java index 2433b2b637..31df096943 100644 --- a/android/src/org/ppsspp/ppsspp/NativeRenderer.java +++ b/android/src/org/ppsspp/ppsspp/NativeRenderer.java @@ -2,7 +2,11 @@ package org.ppsspp.ppsspp; import android.opengl.GLSurfaceView; import android.util.Log; + +import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLContext; +import javax.microedition.khronos.egl.EGLDisplay; import javax.microedition.khronos.opengles.GL10; public class NativeRenderer implements GLSurfaceView.Renderer { @@ -24,8 +28,25 @@ public class NativeRenderer implements GLSurfaceView.Renderer { inFrame = false; } - public void onSurfaceCreated(GL10 unused, EGLConfig config) { + public void onSurfaceCreated(GL10 gl, EGLConfig config) { Log.i(TAG, "NativeRenderer: onSurfaceCreated"); + + EGL10 egl = (EGL10)EGLContext.getEGL(); + if (egl != null) { + EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + if (dpy != null) { + int[] val = new int[1]; + egl.eglGetConfigAttrib(dpy, config, EGL10.EGL_DEPTH_SIZE, val); + int depthBits = val[0]; + egl.eglGetConfigAttrib(dpy, config, EGL10.EGL_STENCIL_SIZE, val); + int stencilBits = val[0]; + Log.i(TAG, "EGL reports " + depthBits + " bits of depth and " + stencilBits + " bits of stencil."); + } else { + Log.e(TAG, "dpy == null"); + } + } else { + Log.e(TAG, "egl == null"); + } // Log.i(TAG, "onSurfaceCreated - EGL context is new or was lost"); // Actually, it seems that it is here we should recreate lost GL objects. displayInit(); From 015c314fb18fe002b74a161a75c3e71e296117e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 19 Dec 2018 23:05:24 +0100 Subject: [PATCH 240/347] Android EGL config: Always require 8888, stencil if version >= ICS --- android/src/org/ppsspp/ppsspp/NativeActivity.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java index da7278c71d..2e1815bfe5 100644 --- a/android/src/org/ppsspp/ppsspp/NativeActivity.java +++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java @@ -517,8 +517,13 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C if (Build.MANUFACTURER == "OUYA") { mGLSurfaceView.getHolder().setFormat(PixelFormat.RGBX_8888); mGLSurfaceView.setEGLConfigChooser(new NativeEGLConfigChooser()); + } else { + // Tried to mess around with config choosers (NativeEGLConfigChooser) here but fail completely on Xperia Play. + // On the other hand, I think from ICS we should be safe to at least require 8888 and stencil... + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + mGLSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 8); + } } - // Tried to mess around with config choosers here but fail completely on Xperia Play. mGLSurfaceView.setRenderer(nativeRenderer); setContentView(mGLSurfaceView); } else { From d047955686dab5929b20eecd4432c55d9c9c9370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 20 Dec 2018 11:00:15 +0100 Subject: [PATCH 241/347] This should finally repro one of the Adreno bugs --- UI/GPUDriverTestScreen.cpp | 153 +++++++++++++++++++++----------- UI/GPUDriverTestScreen.h | 9 ++ ext/native/thin3d/thin3d_gl.cpp | 2 +- 3 files changed, 111 insertions(+), 53 deletions(-) diff --git a/UI/GPUDriverTestScreen.cpp b/UI/GPUDriverTestScreen.cpp index e1762d04e0..393cbe9db8 100644 --- a/UI/GPUDriverTestScreen.cpp +++ b/UI/GPUDriverTestScreen.cpp @@ -47,6 +47,10 @@ GPUDriverTestScreen::GPUDriverTestScreen() { GPUDriverTestScreen::~GPUDriverTestScreen() { if (discardWriteDepthStencil_) discardWriteDepthStencil_->Release(); + if (discardWriteDepth_) + discardWriteDepth_->Release(); + if (discardWriteStencil_) + discardWriteStencil_->Release(); if (drawTestStencilEqualDepthAlways_) drawTestStencilEqualDepthAlways_->Release(); if (drawTestStencilNotEqualDepthAlways_) @@ -55,10 +59,10 @@ GPUDriverTestScreen::~GPUDriverTestScreen() { drawTestStencilEqual_->Release(); if (drawTestStencilNotEqual_) drawTestStencilNotEqual_->Release(); - if (drawTestDepthLessEqual_) - drawTestDepthLessEqual_->Release(); - if (drawTestDepthGreater_) - drawTestDepthGreater_->Release(); + if (drawTestStencilAlwaysDepthLessEqual_) + drawTestStencilAlwaysDepthLessEqual_->Release(); + if (drawTestStencilAlwaysDepthGreater_) + drawTestStencilAlwaysDepthGreater_->Release(); if (discard_) discard_->Release(); if (samplerNearest_) @@ -111,32 +115,52 @@ void GPUDriverTestScreen::DiscardTest() { dsDesc.back = dsDesc.front; DepthStencilState *depthStencilWrite = draw->CreateDepthStencilState(dsDesc); + // Write only depth. + dsDesc.stencilEnabled = false; + DepthStencilState *depthWrite = draw->CreateDepthStencilState(dsDesc); + + // Write only stencil. + dsDesc.stencilEnabled = true; + dsDesc.depthTestEnabled = false; + DepthStencilState *stencilWrite = draw->CreateDepthStencilState(dsDesc); + + // Now for the shaders that read depth and/or stencil. + dsDesc.depthTestEnabled = true; + dsDesc.stencilEnabled = true; dsDesc.depthCompare = Comparison::ALWAYS; dsDesc.front.compareOp = Comparison::EQUAL; dsDesc.back = dsDesc.front; - DepthStencilState *stencilTestEqualDepthAlways = draw->CreateDepthStencilState(dsDesc); + DepthStencilState *stencilEqualDepthAlways = draw->CreateDepthStencilState(dsDesc); dsDesc.depthTestEnabled = false; dsDesc.front.compareOp = Comparison::EQUAL; dsDesc.back = dsDesc.front; - DepthStencilState *stencilTestEqual = draw->CreateDepthStencilState(dsDesc); + DepthStencilState *stencilEqual = draw->CreateDepthStencilState(dsDesc); dsDesc.depthTestEnabled = true; dsDesc.depthCompare = Comparison::ALWAYS; dsDesc.front.compareOp = Comparison::NOT_EQUAL; dsDesc.back = dsDesc.front; - DepthStencilState *stencilTestNotEqualDepthAlways = draw->CreateDepthStencilState(dsDesc); + DepthStencilState *stenciNotEqualDepthAlways = draw->CreateDepthStencilState(dsDesc); dsDesc.depthTestEnabled = false; dsDesc.front.compareOp = Comparison::NOT_EQUAL; dsDesc.back = dsDesc.front; - DepthStencilState *stencilTestNotEqual = draw->CreateDepthStencilState(dsDesc); + DepthStencilState *stencilNotEqual = draw->CreateDepthStencilState(dsDesc); + dsDesc.stencilEnabled = true; dsDesc.depthTestEnabled = true; - dsDesc.depthCompare = Comparison::LESS_EQUAL; dsDesc.front.compareOp = Comparison::ALWAYS; dsDesc.back = dsDesc.front; + dsDesc.depthCompare = Comparison::LESS_EQUAL; + DepthStencilState *stencilAlwaysDepthTestLessEqual = draw->CreateDepthStencilState(dsDesc); + dsDesc.depthCompare = Comparison::GREATER; + DepthStencilState *stencilAlwaysDepthTestGreater = draw->CreateDepthStencilState(dsDesc); + + dsDesc.stencilEnabled = false; + dsDesc.depthTestEnabled = true; + dsDesc.depthCompare = Comparison::LESS_EQUAL; DepthStencilState *depthTestLessEqual = draw->CreateDepthStencilState(dsDesc); dsDesc.depthCompare = Comparison::GREATER; DepthStencilState *depthTestGreater = draw->CreateDepthStencilState(dsDesc); @@ -149,23 +173,33 @@ void GPUDriverTestScreen::DiscardTest() { inputLayout, depthStencilWrite, blendOff, rasterNoCull, &vsColBufDesc, }; discardWriteDepthStencil_ = draw->CreateGraphicsPipeline(discardDesc); + discardDesc.depthStencil = depthWrite; + discardWriteDepth_ = draw->CreateGraphicsPipeline(discardDesc); + discardDesc.depthStencil = stencilWrite; + discardWriteStencil_ = draw->CreateGraphicsPipeline(discardDesc); PipelineDesc testDesc{ Primitive::TRIANGLE_LIST, { draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D) }, - inputLayout, stencilTestEqual, blendOff, rasterNoCull, &vsColBufDesc, + inputLayout, stencilEqual, blendOff, rasterNoCull, &vsColBufDesc, }; drawTestStencilEqual_ = draw->CreateGraphicsPipeline(testDesc); - testDesc.depthStencil = stencilTestEqualDepthAlways; + testDesc.depthStencil = stencilEqualDepthAlways; drawTestStencilEqualDepthAlways_ = draw->CreateGraphicsPipeline(testDesc); - testDesc.depthStencil = stencilTestNotEqual; + testDesc.depthStencil = stencilNotEqual; drawTestStencilNotEqual_ = draw->CreateGraphicsPipeline(testDesc); - testDesc.depthStencil = stencilTestNotEqualDepthAlways; + testDesc.depthStencil = stenciNotEqualDepthAlways; drawTestStencilNotEqualDepthAlways_ = draw->CreateGraphicsPipeline(testDesc); + testDesc.depthStencil = stencilAlwaysDepthTestGreater; + drawTestStencilAlwaysDepthGreater_ = draw->CreateGraphicsPipeline(testDesc); + + testDesc.depthStencil = stencilAlwaysDepthTestLessEqual; + drawTestStencilAlwaysDepthLessEqual_ = draw->CreateGraphicsPipeline(testDesc); + testDesc.depthStencil = depthTestGreater; drawTestDepthGreater_ = draw->CreateGraphicsPipeline(testDesc); @@ -175,10 +209,12 @@ void GPUDriverTestScreen::DiscardTest() { inputLayout->Release(); blendOff->Release(); depthStencilWrite->Release(); - stencilTestEqual->Release(); - stencilTestNotEqual->Release(); - stencilTestEqualDepthAlways->Release(); - stencilTestNotEqualDepthAlways->Release(); + stencilEqual->Release(); + stencilNotEqual->Release(); + stencilEqualDepthAlways->Release(); + stenciNotEqualDepthAlways->Release(); + stencilAlwaysDepthTestLessEqual->Release(); + stencilAlwaysDepthTestGreater->Release(); depthTestLessEqual->Release(); depthTestGreater->Release(); rasterNoCull->Release(); @@ -191,12 +227,21 @@ void GPUDriverTestScreen::DiscardTest() { Draw::DrawContext *draw = dc.GetDrawContext(); const Bounds &bounds = dc.GetBounds(); - const char *testNames[] = { "Stencil", "Stencil+DepthA", "StencilA+Depth" }; - Pipeline *testPipeline1[] = { drawTestStencilEqual_, drawTestStencilEqualDepthAlways_, drawTestDepthLessEqual_ }; - Pipeline *testPipeline2[] = { drawTestStencilNotEqual_, drawTestStencilNotEqualDepthAlways_, drawTestDepthGreater_ }; + static const char * const writeModeNames[] = { "Stencil+Depth", "Stencil", "Depth" }; + Pipeline *writePipelines[] = { discardWriteDepthStencil_, discardWriteStencil_, discardWriteDepth_ }; + const int numWriteModes = ARRAY_SIZE(writeModeNames); + static const char * const testNames[] = { "Stenc", "Stenc+DepthA", "Depth", "StencA+Depth" }; + Pipeline *testPipeline1[] = { drawTestStencilEqual_, drawTestStencilEqualDepthAlways_, drawTestDepthLessEqual_, drawTestStencilAlwaysDepthLessEqual_ }; + Pipeline *testPipeline2[] = { drawTestStencilNotEqual_, drawTestStencilNotEqualDepthAlways_, drawTestDepthGreater_, drawTestStencilAlwaysDepthGreater_ }; const int numTests = ARRAY_SIZE(testNames); + static const bool validCombinations[numWriteModes][numTests] = { + {true, true, true, true}, + {true, true, false, false}, + {false, false, true, true}, + }; + uint32_t textColorOK = 0xFF30FF30; uint32_t textColorBAD = 0xFF3030FF; uint32_t bgColorOK = 0xFF106010; @@ -212,6 +257,7 @@ void GPUDriverTestScreen::DiscardTest() { // If everything is OK, both the background and the text should be OK. dc.Begin(); + dc.SetFontScale(1.0f, 1.0f); std::string apiName = screenManager()->getDrawContext()->GetInfoString(InfoField::APINAME); std::string vendor = screenManager()->getDrawContext()->GetInfoString(InfoField::VENDORSTRING); std::string driver = screenManager()->getDrawContext()->GetInfoString(InfoField::DRIVER); @@ -220,49 +266,52 @@ void GPUDriverTestScreen::DiscardTest() { dc.DrawText(driver.c_str(), bounds.centerX(), 100, 0xFFFFFFFF, ALIGN_CENTER); dc.Flush(); - float testW = 220.f; + float testW = 170.f; float padding = 20.0f; UI::Style style = dc.theme->itemStyle; float y = 150; - float x = (dc.GetBounds().w - (float)numTests * testW - (float)(numTests - 1) * padding) / 2.0f; - for (int i = 0; i < numTests; i++) { + for (int j = 0; j < numWriteModes; j++, y += 120.f + padding) { + float x = (dc.GetBounds().w - (float)numTests * testW - (float)(numTests - 1) * padding) / 2.0f; dc.Begin(); - dc.SetFontScale(1.0f, 1.0f); - Bounds bounds = { x, y + 40, testW, 70 }; - dc.DrawText(testNames[i], bounds.x, y, style.fgColor, FLAG_DYNAMIC_ASCII); + dc.DrawText(writeModeNames[j], padding, y + 40, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII); dc.Flush(); + for (int i = 0; i < numTests; i++, x += testW + padding) { + if (!validCombinations[j][i]) + continue; + dc.Begin(); + Bounds bounds = { x, y + 40, testW, 70 }; + dc.DrawText(testNames[i], bounds.x, y, style.fgColor, FLAG_DYNAMIC_ASCII); + dc.Flush(); - dc.BeginPipeline(discardWriteDepthStencil_, samplerNearest_); - // Draw the rectangle with stencil value 0, depth 0.1f and the text with stencil 0xFF, depth 0.9. Then leave 0xFF as the stencil value and draw the rectangles at depth 0.5. - draw->SetStencilRef(0x0); - dc.SetCurZ(0.1f); - dc.FillRect(UI::Drawable(bgColorBAD), bounds); - // test bounds - dc.Flush(); + dc.BeginPipeline(writePipelines[j], samplerNearest_); + // Draw the rectangle with stencil value 0, depth 0.1f and the text with stencil 0xFF, depth 0.9. Then leave 0xFF as the stencil value and draw the rectangles at depth 0.5. + draw->SetStencilRef(0x0); + dc.SetCurZ(0.1f); + dc.FillRect(UI::Drawable(bgColorBAD), bounds); + // test bounds + dc.Flush(); - draw->SetStencilRef(0xff); - dc.SetCurZ(0.9f); - dc.DrawTextRect("TEST OK", bounds, textColorBAD, ALIGN_HCENTER | ALIGN_VCENTER | FLAG_DYNAMIC_ASCII); - dc.Flush(); + draw->SetStencilRef(0xff); + dc.SetCurZ(0.9f); + dc.DrawTextRect("TEST OK", bounds, textColorBAD, ALIGN_HCENTER | ALIGN_VCENTER | FLAG_DYNAMIC_ASCII); + dc.Flush(); - // Draw rectangle that should result in the text - dc.BeginPipeline(testPipeline1[i], samplerNearest_); - draw->SetStencilRef(0xff); - dc.SetCurZ(0.5f); - dc.FillRect(UI::Drawable(textColorOK), bounds); - dc.Flush(); + // Draw rectangle that should result in the text + dc.BeginPipeline(testPipeline1[i], samplerNearest_); + draw->SetStencilRef(0xff); + dc.SetCurZ(0.5f); + dc.FillRect(UI::Drawable(textColorOK), bounds); + dc.Flush(); - // Draw rectangle that should result in the bg - dc.BeginPipeline(testPipeline2[i], samplerNearest_); - draw->SetStencilRef(0xff); - dc.SetCurZ(0.5f); - dc.FillRect(UI::Drawable(bgColorOK), bounds); - dc.Flush(); - - x += testW + padding; + // Draw rectangle that should result in the bg + dc.BeginPipeline(testPipeline2[i], samplerNearest_); + draw->SetStencilRef(0xff); + dc.SetCurZ(0.5f); + dc.FillRect(UI::Drawable(bgColorOK), bounds); + dc.Flush(); + } } - dc.SetFontScale(1.0f, 1.0f); dc.Flush(); } diff --git a/UI/GPUDriverTestScreen.h b/UI/GPUDriverTestScreen.h index 892d1bb13a..d76cacc56e 100644 --- a/UI/GPUDriverTestScreen.h +++ b/UI/GPUDriverTestScreen.h @@ -25,12 +25,21 @@ private: Draw::ShaderModule *discard_ = nullptr; Draw::Pipeline *discardWriteDepthStencil_ = nullptr; + Draw::Pipeline *discardWriteDepth_ = nullptr; + Draw::Pipeline *discardWriteStencil_ = nullptr; + + // Stencil test, with and without DepthAlways Draw::Pipeline *drawTestStencilEqual_ = nullptr; Draw::Pipeline *drawTestStencilNotEqual_ = nullptr; Draw::Pipeline *drawTestStencilEqualDepthAlways_ = nullptr; Draw::Pipeline *drawTestStencilNotEqualDepthAlways_ = nullptr; + + // Depth tests with and without StencilAlways + Draw::Pipeline *drawTestStencilAlwaysDepthLessEqual_ = nullptr; + Draw::Pipeline *drawTestStencilAlwaysDepthGreater_ = nullptr; Draw::Pipeline *drawTestDepthLessEqual_ = nullptr; Draw::Pipeline *drawTestDepthGreater_ = nullptr; + Draw::SamplerState *samplerNearest_ = nullptr; UI::TabHolder *tabHolder_ = nullptr; }; diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index 19d3cea8ff..114253db78 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -186,7 +186,7 @@ public: bool depthTestEnabled; bool depthWriteEnabled; GLuint depthComp; - // TODO: Two-sided + // TODO: Two-sided. Although in practice, do we care? bool stencilEnabled; GLuint stencilFail; GLuint stencilZFail; From 0f28b66a70365579b71cf95fb4560364179b7439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 20 Dec 2018 11:14:50 +0100 Subject: [PATCH 242/347] Don't leak the new pipelines --- UI/GPUDriverTestScreen.cpp | 14 ++++++++++---- UI/GPUDriverTestScreen.h | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/UI/GPUDriverTestScreen.cpp b/UI/GPUDriverTestScreen.cpp index 393cbe9db8..1a737b0325 100644 --- a/UI/GPUDriverTestScreen.cpp +++ b/UI/GPUDriverTestScreen.cpp @@ -51,6 +51,7 @@ GPUDriverTestScreen::~GPUDriverTestScreen() { discardWriteDepth_->Release(); if (discardWriteStencil_) discardWriteStencil_->Release(); + if (drawTestStencilEqualDepthAlways_) drawTestStencilEqualDepthAlways_->Release(); if (drawTestStencilNotEqualDepthAlways_) @@ -63,8 +64,13 @@ GPUDriverTestScreen::~GPUDriverTestScreen() { drawTestStencilAlwaysDepthLessEqual_->Release(); if (drawTestStencilAlwaysDepthGreater_) drawTestStencilAlwaysDepthGreater_->Release(); - if (discard_) - discard_->Release(); + if (drawTestDepthLessEqual_) + drawTestDepthLessEqual_->Release(); + if (drawTestDepthGreater_) + drawTestDepthGreater_->Release(); + + if (discardFragShader_) + discardFragShader_->Release(); if (samplerNearest_) samplerNearest_->Release(); } @@ -95,7 +101,7 @@ void GPUDriverTestScreen::DiscardTest() { // Create the special shader module. - discard_ = CreateShader(draw, Draw::ShaderStage::FRAGMENT, fsDiscard); + discardFragShader_ = CreateShader(draw, Draw::ShaderStage::FRAGMENT, fsDiscard); InputLayout *inputLayout = ui_draw2d.CreateInputLayout(draw); BlendState *blendOff = draw->CreateBlendState({ false, 0xF }); @@ -169,7 +175,7 @@ void GPUDriverTestScreen::DiscardTest() { PipelineDesc discardDesc{ Primitive::TRIANGLE_LIST, - { draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), discard_ }, + { draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), discardFragShader_ }, inputLayout, depthStencilWrite, blendOff, rasterNoCull, &vsColBufDesc, }; discardWriteDepthStencil_ = draw->CreateGraphicsPipeline(discardDesc); diff --git a/UI/GPUDriverTestScreen.h b/UI/GPUDriverTestScreen.h index d76cacc56e..bf5c56a02c 100644 --- a/UI/GPUDriverTestScreen.h +++ b/UI/GPUDriverTestScreen.h @@ -23,7 +23,7 @@ public: private: void DiscardTest(); - Draw::ShaderModule *discard_ = nullptr; + Draw::ShaderModule *discardFragShader_ = nullptr; Draw::Pipeline *discardWriteDepthStencil_ = nullptr; Draw::Pipeline *discardWriteDepth_ = nullptr; Draw::Pipeline *discardWriteStencil_ = nullptr; From fb3ba7007431bdb62b9e50dee1563de4b681d808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 20 Dec 2018 11:16:37 +0100 Subject: [PATCH 243/347] Update lang --- assets/lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/lang b/assets/lang index 67c189ca63..c4698e4f04 160000 --- a/assets/lang +++ b/assets/lang @@ -1 +1 @@ -Subproject commit 67c189ca63c68cba9e0146c98c89b2a8e9a10975 +Subproject commit c4698e4f04c61503d95de032fad8e28909b4d447 From 5f58caf4ddb188289e257befa04b652ac0146543 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 20 Dec 2018 13:13:09 +0100 Subject: [PATCH 244/347] Minor tweak to the test --- UI/GPUDriverTestScreen.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/UI/GPUDriverTestScreen.cpp b/UI/GPUDriverTestScreen.cpp index 1a737b0325..bd9f0aa7ab 100644 --- a/UI/GPUDriverTestScreen.cpp +++ b/UI/GPUDriverTestScreen.cpp @@ -128,6 +128,7 @@ void GPUDriverTestScreen::DiscardTest() { // Write only stencil. dsDesc.stencilEnabled = true; dsDesc.depthTestEnabled = false; + dsDesc.depthWriteEnabled = false; // Just in case the driver is crazy. when test is enabled, though, this should be ignored. DepthStencilState *stencilWrite = draw->CreateDepthStencilState(dsDesc); // Now for the shaders that read depth and/or stencil. From 99ed2e4722aef61bca52fc0856b310434ddf6b6a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 21 Dec 2018 22:31:47 -0800 Subject: [PATCH 245/347] http: Parse port in ipv6 addresses. --- ext/native/net/url.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/native/net/url.cpp b/ext/native/net/url.cpp index 522adc6709..a2735cf124 100644 --- a/ext/native/net/url.cpp +++ b/ext/native/net/url.cpp @@ -20,7 +20,7 @@ void Url::Split() { host_ = url_.substr(colonSlashSlash + 3, sep - colonSlashSlash - 3); resource_ = url_.substr(sep); // include the slash! - size_t portsep = host_.find(':'); + size_t portsep = host_.rfind(':'); if (portsep != host_.npos) { port_ = atoi(host_.substr(portsep + 1).c_str()); host_ = host_.substr(0, portsep); From 1428684d1d45566d4bef61a08f2541ad8b1d9835 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 21 Dec 2018 22:41:02 -0800 Subject: [PATCH 246/347] http: Check for available discs before connecting. This prevents trying to connect to a device serving only a debugger. --- UI/RemoteISOScreen.cpp | 60 +++++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/UI/RemoteISOScreen.cpp b/UI/RemoteISOScreen.cpp index 6f31533349..9ba9df4f7d 100644 --- a/UI/RemoteISOScreen.cpp +++ b/UI/RemoteISOScreen.cpp @@ -37,19 +37,59 @@ static const int REPORT_PORT = 80; static bool scanCancelled = false; static bool scanAborted = false; +static std::string RemoteSubdir() { + if (g_Config.bRemoteISOManual) { + std::string subdir = g_Config.sRemoteISOSubdir; + size_t offset = subdir.find_last_of("/"); + if (offset != subdir.length() - 1 && offset != subdir.npos) { + // Truncate everything after last / + subdir.erase(offset + 1); + } + return subdir; + } + + return "/"; +} + static bool FindServer(std::string &resultHost, int &resultPort) { http::Client http; Buffer result; int code = 500; + std::string subdir = RemoteSubdir(); + auto TryServer = [&](const std::string &host, int port) { // Don't wait as long for a connect - we need a good connection for smooth streaming anyway. // This way if it's down, we'll find the right one faster. if (http.Resolve(host.c_str(), port) && http.Connect(1, 10.0, &scanCancelled)) { + code = http.GET(subdir.c_str(), &result); http.Disconnect(); - resultHost = host; - resultPort = port; - return true; + + if (code != 200) { + return false; + } + + // Make sure this isn't just the debugger. If so, move on. + std::string listing; + std::vector items; + result.TakeAll(&listing); + SplitString(listing, '\n', items); + + bool supported = false; + for (const std::string &item : items) { + if (!RemoteISOFileSupported(item)) { + continue; + } + supported = true; + break; + } + + if (supported) { + resultHost = host; + resultPort = port; + NOTICE_LOG(HLE, "RemoteISO found: %s : %d", host.c_str(), port); + return true; + } } return false; @@ -94,7 +134,6 @@ static bool FindServer(std::string &resultHost, int &resultPort) { return false; } - std::vector servers; for (const auto pentry : entries) { JsonGet entry = pentry->value; if (scanCancelled) @@ -105,7 +144,6 @@ static bool FindServer(std::string &resultHost, int &resultPort) { char url[1024] = {}; snprintf(url, sizeof(url), "http://%s:%d", host, port); - servers.push_back(url); if (TryServer(host, port)) { return true; @@ -121,17 +159,7 @@ static bool LoadGameList(const std::string &host, int port, std::vector responseHeaders; - std::string subdir = "/"; - size_t offset; - - if (g_Config.bRemoteISOManual) { - subdir = g_Config.sRemoteISOSubdir; - offset=subdir.find_last_of("/"); - if (offset != subdir.length() - 1 && offset != subdir.npos) { - // Truncate everything after last / - subdir.erase(offset + 1); - } - } + std::string subdir = RemoteSubdir(); // Start by requesting the list of games from the server. if (http.Resolve(host.c_str(), port)) { From 79ef185d6ea65f6dcc37e3e1ffe7a8880685bfea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 22 Dec 2018 18:29:56 +0100 Subject: [PATCH 247/347] Vulkan/adreno: Apply workaround for Harvest Moon issue #10421 --- GPU/Vulkan/StateMappingVulkan.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/GPU/Vulkan/StateMappingVulkan.cpp b/GPU/Vulkan/StateMappingVulkan.cpp index ff6c141af5..2cc8f08229 100644 --- a/GPU/Vulkan/StateMappingVulkan.cpp +++ b/GPU/Vulkan/StateMappingVulkan.cpp @@ -235,6 +235,18 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag } key.colorWriteMask = (rmask ? VK_COLOR_COMPONENT_R_BIT : 0) | (gmask ? VK_COLOR_COMPONENT_G_BIT : 0) | (bmask ? VK_COLOR_COMPONENT_B_BIT : 0) | (amask ? VK_COLOR_COMPONENT_A_BIT : 0); + + // Workaround proposed in #10421 + if ((gstate.pmskc & 0x00FFFFFF) == 0x00FFFFFF && vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).vendorID == VULKAN_VENDOR_QUALCOMM) { + key.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + key.blendEnable = true; + key.blendOpColor = VK_BLEND_OP_ADD; + key.blendOpAlpha = VK_BLEND_OP_ADD; + key.srcColor = VK_BLEND_FACTOR_ZERO; + key.srcAlpha = VK_BLEND_FACTOR_ZERO; + key.destColor = VK_BLEND_FACTOR_ONE; + key.destAlpha = VK_BLEND_FACTOR_ONE; + } } } From 0037da55a183cf5ff285d59471a95e9d3c214ea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 23 Dec 2018 11:57:06 +0100 Subject: [PATCH 248/347] Avoid breaking any alpha-stencil emulation in Adreno bug workaround --- GPU/Vulkan/StateMappingVulkan.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/GPU/Vulkan/StateMappingVulkan.cpp b/GPU/Vulkan/StateMappingVulkan.cpp index 2cc8f08229..e72df78c35 100644 --- a/GPU/Vulkan/StateMappingVulkan.cpp +++ b/GPU/Vulkan/StateMappingVulkan.cpp @@ -236,16 +236,18 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag key.colorWriteMask = (rmask ? VK_COLOR_COMPONENT_R_BIT : 0) | (gmask ? VK_COLOR_COMPONENT_G_BIT : 0) | (bmask ? VK_COLOR_COMPONENT_B_BIT : 0) | (amask ? VK_COLOR_COMPONENT_A_BIT : 0); - // Workaround proposed in #10421 + // Workaround proposed in #10421, for bug where the color write mask is not applied correctly on Adreno. if ((gstate.pmskc & 0x00FFFFFF) == 0x00FFFFFF && vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).vendorID == VULKAN_VENDOR_QUALCOMM) { key.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - key.blendEnable = true; + if (!key.blendEnable) { + key.blendEnable = true; + key.blendOpAlpha = VK_BLEND_OP_ADD; + key.srcAlpha = VK_BLEND_FACTOR_ZERO; + key.destAlpha = VK_BLEND_FACTOR_ONE; + } key.blendOpColor = VK_BLEND_OP_ADD; - key.blendOpAlpha = VK_BLEND_OP_ADD; key.srcColor = VK_BLEND_FACTOR_ZERO; - key.srcAlpha = VK_BLEND_FACTOR_ZERO; key.destColor = VK_BLEND_FACTOR_ONE; - key.destAlpha = VK_BLEND_FACTOR_ONE; } } } From df4179fdb53fde5d49e8cbd9138a0af96cb0c915 Mon Sep 17 00:00:00 2001 From: xebra Date: Tue, 18 Dec 2018 19:56:55 +0900 Subject: [PATCH 249/347] [spline/bezier]Remove unused stuff. --- GPU/Common/DrawEngineCommon.h | 1 - 1 file changed, 1 deletion(-) diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 362a0ce712..ac735f90cf 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -131,7 +131,6 @@ protected: // Vertex collector buffers u8 *decoded = nullptr; u16 *decIndex = nullptr; - u8 *splineBuffer = nullptr; // Cached vertex decoders u32 lastVType_ = -1; From 4b2c18bb237dfc3daec31c8bfb2984f9edeeb36a Mon Sep 17 00:00:00 2001 From: xebra Date: Mon, 24 Dec 2018 04:23:03 +0900 Subject: [PATCH 250/347] GE Debugger: Minor fix step count dialog. --- Windows/GEDebugger/GEDebugger.h | 2 +- Windows/ppsspp.rc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Windows/GEDebugger/GEDebugger.h b/Windows/GEDebugger/GEDebugger.h index 271d20569e..f1e23f1f75 100644 --- a/Windows/GEDebugger/GEDebugger.h +++ b/Windows/GEDebugger/GEDebugger.h @@ -51,7 +51,7 @@ public: protected: BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); private: - void Jump(int value, bool relative); + void Jump(int count, bool relative); }; class CGEDebugger : public Dialog { diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index 144a50db06..2c6ec73d79 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -240,7 +240,7 @@ EXSTYLE WS_EX_TOOLWINDOW CAPTION "Step Count" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - COMBOBOX IDC_GEDBG_STEPCOUNT_COMBO,6,3,50,13,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP | ES_NUMBER + COMBOBOX IDC_GEDBG_STEPCOUNT_COMBO,6,3,50,13,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "-",IDC_GEDBG_STEPCOUNT_DEC,58,2,14,14 PUSHBUTTON "+",IDC_GEDBG_STEPCOUNT_INC,73,2,14,14 PUSHBUTTON "Jump",IDC_GEDBG_STEPCOUNT_JUMP,88,2,30,14 From 1f594f3fb54132799753f7ea47c5c29d40cedefd Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 23 Dec 2018 12:06:29 -0800 Subject: [PATCH 251/347] GPU: Track draw in shader manager. With device restore etc. everywhere. --- GPU/Common/ShaderCommon.h | 9 ++++++++- GPU/D3D11/GPU_D3D11.cpp | 2 +- GPU/D3D11/ShaderManagerD3D11.cpp | 5 +++-- GPU/D3D11/ShaderManagerD3D11.h | 2 +- GPU/Directx9/GPU_DX9.cpp | 2 +- GPU/Directx9/ShaderManagerDX9.cpp | 4 +++- GPU/Directx9/ShaderManagerDX9.h | 2 +- GPU/GLES/ShaderManagerGLES.cpp | 6 ++++-- GPU/Vulkan/GPU_Vulkan.cpp | 4 ++-- GPU/Vulkan/ShaderManagerVulkan.cpp | 8 +++++--- GPU/Vulkan/ShaderManagerVulkan.h | 4 ++-- 11 files changed, 31 insertions(+), 17 deletions(-) diff --git a/GPU/Common/ShaderCommon.h b/GPU/Common/ShaderCommon.h index 1ef4ba51e4..b8827dd03d 100644 --- a/GPU/Common/ShaderCommon.h +++ b/GPU/Common/ShaderCommon.h @@ -19,6 +19,10 @@ #include +namespace Draw { + class DrawContext; +} + enum ShaderLanguage { GLSL_140, GLSL_300, @@ -116,10 +120,13 @@ enum : uint64_t { class ShaderManagerCommon { public: - ShaderManagerCommon() {} + ShaderManagerCommon(Draw::DrawContext *draw) : draw_(draw) {} virtual ~ShaderManagerCommon() {} virtual void DirtyLastShader() = 0; + +protected: + Draw::DrawContext *draw_ = nullptr; }; struct TBuiltInResource; diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index e29f46e296..e0ee48ef05 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -77,7 +77,7 @@ GPU_D3D11::GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw) stockD3D11.Create(device_); - shaderManagerD3D11_ = new ShaderManagerD3D11(device_, context_, featureLevel); + shaderManagerD3D11_ = new ShaderManagerD3D11(draw, device_, context_, featureLevel); framebufferManagerD3D11_ = new FramebufferManagerD3D11(draw); framebufferManager_ = framebufferManagerD3D11_; textureCacheD3D11_ = new TextureCacheD3D11(draw); diff --git a/GPU/D3D11/ShaderManagerD3D11.cpp b/GPU/D3D11/ShaderManagerD3D11.cpp index c5c498f5f5..70471523da 100644 --- a/GPU/D3D11/ShaderManagerD3D11.cpp +++ b/GPU/D3D11/ShaderManagerD3D11.cpp @@ -26,6 +26,7 @@ #include "math/lin/matrix4x4.h" #include "math/math_util.h" #include "math/dataconv.h" +#include "thin3d/thin3d.h" #include "util/text/utf8.h" #include "Common/Common.h" #include "Core/Config.h" @@ -88,8 +89,8 @@ std::string D3D11VertexShader::GetShaderString(DebugShaderStringType type) const } } -ShaderManagerD3D11::ShaderManagerD3D11(ID3D11Device *device, ID3D11DeviceContext *context, D3D_FEATURE_LEVEL featureLevel) - : device_(device), context_(context), featureLevel_(featureLevel), lastVShader_(nullptr), lastFShader_(nullptr) { +ShaderManagerD3D11::ShaderManagerD3D11(Draw::DrawContext *draw, ID3D11Device *device, ID3D11DeviceContext *context, D3D_FEATURE_LEVEL featureLevel) + : ShaderManagerCommon(draw), device_(device), context_(context), featureLevel_(featureLevel), lastVShader_(nullptr), lastFShader_(nullptr) { codeBuffer_ = new char[16384]; memset(&ub_base, 0, sizeof(ub_base)); memset(&ub_lights, 0, sizeof(ub_lights)); diff --git a/GPU/D3D11/ShaderManagerD3D11.h b/GPU/D3D11/ShaderManagerD3D11.h index 23ff3be8a5..5fa74991fe 100644 --- a/GPU/D3D11/ShaderManagerD3D11.h +++ b/GPU/D3D11/ShaderManagerD3D11.h @@ -81,7 +81,7 @@ class D3D11PushBuffer; class ShaderManagerD3D11 : public ShaderManagerCommon { public: - ShaderManagerD3D11(ID3D11Device *device, ID3D11DeviceContext *context, D3D_FEATURE_LEVEL featureLevel); + ShaderManagerD3D11(Draw::DrawContext *draw, ID3D11Device *device, ID3D11DeviceContext *context, D3D_FEATURE_LEVEL featureLevel); ~ShaderManagerD3D11(); void GetShaders(int prim, u32 vertType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, bool useHWTransform); diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index 24d1f69671..e7501ca702 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -61,7 +61,7 @@ GPU_DX9::GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw) lastVsync_ = g_Config.bVSync ? 1 : 0; dxstate.SetVSyncInterval(g_Config.bVSync); - shaderManagerDX9_ = new ShaderManagerDX9(device_); + shaderManagerDX9_ = new ShaderManagerDX9(draw, device_); framebufferManagerDX9_ = new FramebufferManagerDX9(draw); framebufferManager_ = framebufferManagerDX9_; textureCacheDX9_ = new TextureCacheDX9(draw); diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index bdc7ce328f..a035c307d2 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -27,6 +27,7 @@ #include "math/lin/matrix4x4.h" #include "math/math_util.h" #include "math/dataconv.h" +#include "thin3d/thin3d.h" #include "util/text/utf8.h" #include "Common/Common.h" @@ -499,7 +500,8 @@ void ShaderManagerDX9::VSUpdateUniforms(u64 dirtyUniforms) { } } -ShaderManagerDX9::ShaderManagerDX9(LPDIRECT3DDEVICE9 device) : device_(device), lastVShader_(nullptr), lastPShader_(nullptr) { +ShaderManagerDX9::ShaderManagerDX9(Draw::DrawContext *draw, LPDIRECT3DDEVICE9 device) + : ShaderManagerCommon(draw), device_(device), lastVShader_(nullptr), lastPShader_(nullptr) { codeBuffer_ = new char[16384]; } diff --git a/GPU/Directx9/ShaderManagerDX9.h b/GPU/Directx9/ShaderManagerDX9.h index 68fefdccc6..b59efe0175 100644 --- a/GPU/Directx9/ShaderManagerDX9.h +++ b/GPU/Directx9/ShaderManagerDX9.h @@ -77,7 +77,7 @@ protected: class ShaderManagerDX9 : public ShaderManagerCommon { public: - ShaderManagerDX9(LPDIRECT3DDEVICE9 device); + ShaderManagerDX9(Draw::DrawContext *draw, LPDIRECT3DDEVICE9 device); ~ShaderManagerDX9(); void ClearCache(bool deleteThem); // TODO: deleteThem currently not respected diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 1c390a33b7..4c5e3d8f44 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -28,11 +28,12 @@ #include "base/timeutil.h" #include "gfx/gl_debug_log.h" #include "gfx_es2/gpu_features.h" -#include "thin3d/GLRenderManager.h" #include "i18n/i18n.h" #include "math/math_util.h" #include "math/lin/matrix4x4.h" #include "profiler/profiler.h" +#include "thin3d/thin3d.h" +#include "thin3d/GLRenderManager.h" #include "Common/FileUtil.h" #include "Core/Config.h" @@ -571,7 +572,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid) { } ShaderManagerGLES::ShaderManagerGLES(Draw::DrawContext *draw) - : lastShader_(nullptr), shaderSwitchDirtyUniforms_(0), diskCacheDirty_(false), fsCache_(16), vsCache_(16) { + : ShaderManagerCommon(draw), lastShader_(nullptr), shaderSwitchDirtyUniforms_(0), diskCacheDirty_(false), fsCache_(16), vsCache_(16) { render_ = (GLRenderManager *)draw->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); codeBuffer_ = new char[16384]; lastFSID_.set_invalid(); @@ -610,6 +611,7 @@ void ShaderManagerGLES::DeviceLost() { void ShaderManagerGLES::DeviceRestore(Draw::DrawContext *draw) { render_ = (GLRenderManager *)draw->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); + draw_ = draw; } void ShaderManagerGLES::DirtyShader() { diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index b41eff7888..48d287e571 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -59,7 +59,7 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw) UpdateVsyncInterval(true); CheckGPUFeatures(); - shaderManagerVulkan_ = new ShaderManagerVulkan(vulkan_); + shaderManagerVulkan_ = new ShaderManagerVulkan(draw, vulkan_); pipelineManager_ = new PipelineManagerVulkan(vulkan_); framebufferManagerVulkan_ = new FramebufferManagerVulkan(draw, vulkan_); framebufferManager_ = framebufferManagerVulkan_; @@ -535,7 +535,7 @@ void GPU_Vulkan::DeviceRestore() { drawEngine_.DeviceRestore(vulkan_, draw_); pipelineManager_->DeviceRestore(vulkan_); textureCacheVulkan_->DeviceRestore(vulkan_, draw_); - shaderManagerVulkan_->DeviceRestore(vulkan_); + shaderManagerVulkan_->DeviceRestore(vulkan_, draw_); depalShaderCache_.DeviceRestore(draw_, vulkan_); } diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 51a9f4a175..aa812c7de2 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -25,6 +25,7 @@ #include "math/math_util.h" #include "math/dataconv.h" #include "profiler/profiler.h" +#include "thin3d/thin3d.h" #include "util/text/utf8.h" #include "Common/Vulkan/VulkanContext.h" #include "Common/Vulkan/VulkanMemory.h" @@ -156,8 +157,8 @@ std::string VulkanVertexShader::GetShaderString(DebugShaderStringType type) cons } } -ShaderManagerVulkan::ShaderManagerVulkan(VulkanContext *vulkan) - : vulkan_(vulkan), lastVShader_(nullptr), lastFShader_(nullptr), fsCache_(16), vsCache_(16) { +ShaderManagerVulkan::ShaderManagerVulkan(Draw::DrawContext *draw, VulkanContext *vulkan) + : ShaderManagerCommon(draw), vulkan_(vulkan), lastVShader_(nullptr), lastFShader_(nullptr), fsCache_(16), vsCache_(16) { codeBuffer_ = new char[16384]; uboAlignment_ = vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).limits.minUniformBufferOffsetAlignment; memset(&ub_base, 0, sizeof(ub_base)); @@ -174,8 +175,9 @@ ShaderManagerVulkan::~ShaderManagerVulkan() { delete[] codeBuffer_; } -void ShaderManagerVulkan::DeviceRestore(VulkanContext *vulkan) { +void ShaderManagerVulkan::DeviceRestore(VulkanContext *vulkan, Draw::DrawContext *draw) { vulkan_ = vulkan; + draw_ = draw; uboAlignment_ = vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).limits.minUniformBufferOffsetAlignment; } diff --git a/GPU/Vulkan/ShaderManagerVulkan.h b/GPU/Vulkan/ShaderManagerVulkan.h index 2bcce9332b..e77d1725dc 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.h +++ b/GPU/Vulkan/ShaderManagerVulkan.h @@ -83,10 +83,10 @@ class VulkanPushBuffer; class ShaderManagerVulkan : public ShaderManagerCommon { public: - ShaderManagerVulkan(VulkanContext *vulkan); + ShaderManagerVulkan(Draw::DrawContext *draw, VulkanContext *vulkan); ~ShaderManagerVulkan(); - void DeviceRestore(VulkanContext *vulkan); + void DeviceRestore(VulkanContext *vulkan, Draw::DrawContext *draw); void GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, bool useHWTransform); void ClearShaders(); From f8ce9b08baee637e7e085e11c533da6ae2cdfaaa Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 23 Dec 2018 12:19:34 -0800 Subject: [PATCH 252/347] Vulkan: Limit stencil workaround to Adreno 5xx. --- GPU/Common/ShaderId.cpp | 12 +++++++---- GPU/Common/ShaderId.h | 9 +++++++-- GPU/D3D11/ShaderManagerD3D11.cpp | 2 +- GPU/Directx9/ShaderManagerDX9.cpp | 2 +- GPU/GLES/ShaderManagerGLES.cpp | 2 +- GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp | 10 +++------- GPU/Vulkan/ShaderManagerVulkan.cpp | 2 +- ext/native/thin3d/thin3d.h | 21 ++++++++++++++++++++ ext/native/thin3d/thin3d_vulkan.cpp | 11 +++++++++- 9 files changed, 53 insertions(+), 18 deletions(-) diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index bd5f36f1bb..f3a8e09228 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -1,6 +1,7 @@ #include #include +#include "thin3d/thin3d.h" #include "Common/StringUtils.h" #include "Core/Config.h" @@ -225,7 +226,7 @@ std::string FragmentShaderDesc(const ShaderID &id) { // Here we must take all the bits of the gstate that determine what the fragment shader will // look like, and concatenate them together into an ID. -void ComputeFragmentShaderID(ShaderID *id_out) { +void ComputeFragmentShaderID(ShaderID *id_out, const Draw::Bugs &bugs) { ShaderID id; if (gstate.isModeClear()) { // We only need one clear shader, so let's ignore the rest of the bits. @@ -292,9 +293,6 @@ void ComputeFragmentShaderID(ShaderID *id_out) { if (stencilToAlpha != REPLACE_ALPHA_NO) { // 4 bits id.SetBits(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE, 4, ReplaceAlphaWithStencilType()); - } else { - // Use those bits instead for whether stencil output is disabled. - id.SetBit(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE, IsStencilTestOutputDisabled()); } // 2 bits. @@ -312,6 +310,12 @@ void ComputeFragmentShaderID(ShaderID *id_out) { id.SetBit(FS_BIT_FLATSHADE, doFlatShading); id.SetBit(FS_BIT_SHADER_DEPAL, useShaderDepal); + + if (g_Config.bVendorBugChecksEnabled) { + if (bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL)) { + id.SetBit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL, !IsStencilTestOutputDisabled() && !gstate.isDepthWriteEnabled()); + } + } } *id_out = id; diff --git a/GPU/Common/ShaderId.h b/GPU/Common/ShaderId.h index df0efb36d5..ec57b0273f 100644 --- a/GPU/Common/ShaderId.h +++ b/GPU/Common/ShaderId.h @@ -87,7 +87,8 @@ enum { FS_BIT_FLATSHADE = 46, FS_BIT_BGRA_TEXTURE = 47, FS_BIT_TEST_DISCARD_TO_ZERO = 48, - // 49+ are free. + FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL = 49, + // 50+ are free. }; struct ShaderID { @@ -175,11 +176,15 @@ struct FShaderID : ShaderID { } }; +namespace Draw { +class Bugs; +} + void ComputeVertexShaderID(ShaderID *id, uint32_t vertexType, bool useHWTransform); // Generates a compact string that describes the shader. Useful in a list to get an overview // of the current flora of shaders. std::string VertexShaderDesc(const ShaderID &id); -void ComputeFragmentShaderID(ShaderID *id); +void ComputeFragmentShaderID(ShaderID *id, const Draw::Bugs &bugs); std::string FragmentShaderDesc(const ShaderID &id); diff --git a/GPU/D3D11/ShaderManagerD3D11.cpp b/GPU/D3D11/ShaderManagerD3D11.cpp index 70471523da..935c101e68 100644 --- a/GPU/D3D11/ShaderManagerD3D11.cpp +++ b/GPU/D3D11/ShaderManagerD3D11.cpp @@ -191,7 +191,7 @@ void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader ** if (gstate_c.IsDirty(DIRTY_FRAGMENTSHADER_STATE)) { gstate_c.Clean(DIRTY_FRAGMENTSHADER_STATE); - ComputeFragmentShaderID(&FSID); + ComputeFragmentShaderID(&FSID, draw_->GetBugs()); } else { FSID = lastFSID_; } diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index a035c307d2..0fd16f2b3d 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -556,7 +556,7 @@ VSShader *ShaderManagerDX9::ApplyShader(int prim, u32 vertType) { FShaderID FSID; if (gstate_c.IsDirty(DIRTY_FRAGMENTSHADER_STATE)) { gstate_c.Clean(DIRTY_FRAGMENTSHADER_STATE); - ComputeFragmentShaderID(&FSID); + ComputeFragmentShaderID(&FSID, draw_->GetBugs()); } else { FSID = lastFSID_; } diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 4c5e3d8f44..585a6cf459 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -703,7 +703,7 @@ LinkedShader *ShaderManagerGLES::ApplyFragmentShader(VShaderID VSID, Shader *vs, FShaderID FSID; if (gstate_c.IsDirty(DIRTY_FRAGMENTSHADER_STATE)) { gstate_c.Clean(DIRTY_FRAGMENTSHADER_STATE); - ComputeFragmentShaderID(&FSID); + ComputeFragmentShaderID(&FSID, draw_->GetBugs()); } else { FSID = lastFSID_; } diff --git a/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp b/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp index 92196f2a1e..361d38813c 100644 --- a/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp @@ -84,15 +84,11 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_ const char *shading = doFlatShading ? "flat" : ""; bool earlyFragmentTests = ((!enableAlphaTest && !enableColorTest) || testForceToZero) && !gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT); - bool hasStencilOutput = stencilToAlpha != REPLACE_ALPHA_NO || id.Bit(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE) == 0; - - // TODO: This is a bug affecting shader cache generality - we CANNOT check anything but the shader ID and (indirectly) the game ID in here really. - // Need to move this check somehow to the shader ID generator. That's tricky though because it's generic... - bool isAdreno = vulkanVendorId == VULKAN_VENDOR_QUALCOMM && g_Config.bVendorBugChecksEnabled; + bool useAdrenoBugWorkaround = id.Bit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL); if (earlyFragmentTests) { WRITE(p, "layout (early_fragment_tests) in;\n"); - } else if (isAdreno && hasStencilOutput && !gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) { + } else if (useAdrenoBugWorkaround && !gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) { WRITE(p, "layout (depth_unchanged) out float gl_FragDepth;\n"); } @@ -588,7 +584,7 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_ WRITE(p, " z = (1.0/65535.0) * floor(z * 65535.0);\n"); } WRITE(p, " gl_FragDepth = z;\n"); - } else if (!earlyFragmentTests && isAdreno && hasStencilOutput) { + } else if (!earlyFragmentTests && useAdrenoBugWorkaround) { // Adreno (and possibly MESA/others) apply early frag tests even with discard in the shader. // Writing depth prevents the bug, even with depth_unchanged specified. WRITE(p, " gl_FragDepth = gl_FragCoord.z;\n"); diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index aa812c7de2..10675fd5e1 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -240,7 +240,7 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader FShaderID FSID; if (gstate_c.IsDirty(DIRTY_FRAGMENTSHADER_STATE)) { gstate_c.Clean(DIRTY_FRAGMENTSHADER_STATE); - ComputeFragmentShaderID(&FSID); + ComputeFragmentShaderID(&FSID, draw_->GetBugs()); } else { FSID = lastFSID_; } diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 8baa8cc5e2..07b19c08e8 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -315,6 +315,23 @@ struct Viewport { float MaxDepth; }; +class Bugs { +public: + bool Has(uint32_t bug) const { + return (flags_ & (1 << bug)) != 0; + } + void Infest(uint32_t bug) { + flags_ |= (1 << bug); + } + + enum : uint32_t { + NO_DEPTH_CANNOT_DISCARD_STENCIL = 0, + }; + +protected: + uint32_t flags_ = 0; +}; + class RefCountedObject { public: RefCountedObject() : refcount_(1) {} @@ -524,6 +541,8 @@ public: bool CreatePresets(); void DestroyPresets(); + Bugs GetBugs() const { return bugs_; } + virtual const DeviceCaps &GetDeviceCaps() const = 0; virtual uint32_t GetDataFormatSupport(DataFormat fmt) const = 0; virtual std::vector GetFeatureList() const { return std::vector(); } @@ -647,6 +666,8 @@ protected: int targetWidth_; int targetHeight_; + + Bugs bugs_; }; extern const UniformBufferDesc UBPresetDesc; diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 7f8d36afac..1a6ba3e216 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -762,7 +762,8 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit) caps_.framebufferDepthCopySupported = true; // Will pretty much always be the case. caps_.preferredDepthBufferFormat = DataFormat::D24_S8; // TODO: Ask vulkan. - switch (vulkan->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).vendorID) { + auto deviceProps = vulkan->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()); + switch (deviceProps.vendorID) { case VULKAN_VENDOR_AMD: caps_.vendor = GPUVendor::VENDOR_AMD; break; case VULKAN_VENDOR_ARM: caps_.vendor = GPUVendor::VENDOR_ARM; break; case VULKAN_VENDOR_IMGTEC: caps_.vendor = GPUVendor::VENDOR_IMGTEC; break; @@ -773,6 +774,14 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit) caps_.vendor = GPUVendor::VENDOR_UNKNOWN; } + if (caps_.vendor == GPUVendor::VENDOR_QUALCOMM) { + // Adreno 5xx devices, all known driver versions, fail to discard stencil when depth write is off. + // See: https://github.com/hrydgard/ppsspp/pull/11684 + if (deviceProps.deviceID >= 0x05000000 && deviceProps.deviceID < 0x06000000) { + bugs_.Infest(Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL); + } + } + device_ = vulkan->GetDevice(); queue_ = vulkan->GetGraphicsQueue(); From 9a3de5cb1c5d2d7a6db83ad42fc107ddfff3c0a9 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 23 Dec 2018 12:31:19 -0800 Subject: [PATCH 253/347] GPU: Move dual source blending bug check to Draw. This also allows the ini setting to avoid it on Intel. --- GPU/GLES/GPU_GLES.cpp | 36 +---------------------------- GPU/Vulkan/GPU_Vulkan.cpp | 16 +------------ ext/native/thin3d/thin3d.h | 1 + ext/native/thin3d/thin3d_gl.cpp | 35 ++++++++++++++++++++++++++++ ext/native/thin3d/thin3d_vulkan.cpp | 8 +++++++ 5 files changed, 46 insertions(+), 50 deletions(-) diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index cde3291767..3a37ba24d8 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -142,26 +142,6 @@ GPU_GLES::~GPU_GLES() { delete textureCacheGL_; } -static constexpr int MakeIntelSimpleVer(int v1, int v2, int v3) { - return (v1 << 16) | (v2 << 8) | v3; -} - -static bool HasIntelDualSrcBug(int versions[4]) { - // Intel uses a confusing set of at least 3 version numbering schemes. This is the one given to OpenGL. - switch (MakeIntelSimpleVer(versions[0], versions[1], versions[2])) { - case MakeIntelSimpleVer(9, 17, 10): - case MakeIntelSimpleVer(9, 18, 10): - return false; - case MakeIntelSimpleVer(10, 18, 10): - return versions[3] < 4061; - case MakeIntelSimpleVer(10, 18, 14): - return versions[3] < 4080; - default: - // Older than above didn't support dual src anyway, newer should have the fix. - return false; - } -} - // Take the raw GL extension and versioning data and turn into feature flags. void GPU_GLES::CheckGPUFeatures() { u32 features = 0; @@ -170,21 +150,7 @@ void GPU_GLES::CheckGPUFeatures() { features |= GPU_SUPPORTS_VS_RANGE_CULLING; if (gl_extensions.ARB_blend_func_extended || gl_extensions.EXT_blend_func_extended) { - if (!gl_extensions.VersionGEThan(3, 0, 0)) { - // Don't use this extension on sub 3.0 OpenGL versions as it does not seem reliable - } else if (gl_extensions.gpuVendor == GPU_VENDOR_INTEL) { - // Also on Intel, see https://github.com/hrydgard/ppsspp/issues/10117 - // TODO: Remove entirely sometime reasonably far in driver years after 2015. - const std::string ver = draw_->GetInfoString(Draw::InfoField::APIVERSION); - int versions[4]{}; - if (sscanf(ver.c_str(), "Build %d.%d.%d.%d", &versions[0], &versions[1], &versions[2], &versions[3]) == 4) { - if (!HasIntelDualSrcBug(versions)) { - features |= GPU_SUPPORTS_DUALSOURCE_BLEND; - } - } else { - features |= GPU_SUPPORTS_DUALSOURCE_BLEND; - } - } else { + if (!g_Config.bVendorBugChecksEnabled || !draw_->GetBugs().Has(Draw::Bugs::DUAL_SOURCE_BLENDING_BROKEN)) { features |= GPU_SUPPORTS_DUALSOURCE_BLEND; } } diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 48d287e571..286195898b 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -224,23 +224,9 @@ void GPU_Vulkan::CheckGPUFeatures() { features |= GPU_SUPPORTS_DEPTH_CLAMP; } if (vulkan_->GetFeaturesEnabled().dualSrcBlend) { - switch (vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).vendorID) { - // We thought we had a bug here on nVidia but turns out we accidentally #ifdef-ed out crucial - // code on Android. - case VULKAN_VENDOR_INTEL: - // Workaround for Intel driver bug. TODO: Re-enable after some driver version - break; - case VULKAN_VENDOR_AMD: - // See issue #10074, and also #10065 (AMD) and #10109 for the choice of the driver version to check for - if (vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).driverVersion >= 0x00407000) - features |= GPU_SUPPORTS_DUALSOURCE_BLEND; - break; - default: + if (!g_Config.bVendorBugChecksEnabled || !draw_->GetBugs().Has(Draw::Bugs::DUAL_SOURCE_BLENDING_BROKEN)) { features |= GPU_SUPPORTS_DUALSOURCE_BLEND; - break; } - if (!g_Config.bVendorBugChecksEnabled) - features |= GPU_SUPPORTS_DUALSOURCE_BLEND; } if (vulkan_->GetFeaturesEnabled().logicOp) { features |= GPU_SUPPORTS_LOGIC_OP; diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 07b19c08e8..8e8f5eb81d 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -326,6 +326,7 @@ public: enum : uint32_t { NO_DEPTH_CANNOT_DISCARD_STENCIL = 0, + DUAL_SOURCE_BLENDING_BROKEN = 1, }; protected: diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index 114253db78..e3668b8b97 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -503,6 +503,26 @@ private: FrameData frameData_[GLRenderManager::MAX_INFLIGHT_FRAMES]; }; +static constexpr int MakeIntelSimpleVer(int v1, int v2, int v3) { + return (v1 << 16) | (v2 << 8) | v3; +} + +static bool HasIntelDualSrcBug(int versions[4]) { + // Intel uses a confusing set of at least 3 version numbering schemes. This is the one given to OpenGL. + switch (MakeIntelSimpleVer(versions[0], versions[1], versions[2])) { + case MakeIntelSimpleVer(9, 17, 10): + case MakeIntelSimpleVer(9, 18, 10): + return false; + case MakeIntelSimpleVer(10, 18, 10): + return versions[3] < 4061; + case MakeIntelSimpleVer(10, 18, 14): + return versions[3] < 4080; + default: + // Older than above didn't support dual src anyway, newer should have the fix. + return false; + } +} + OpenGLContext::OpenGLContext() { // TODO: Detect more caps if (gl_extensions.IsGLES) { @@ -533,6 +553,21 @@ OpenGLContext::OpenGLContext() { for (int i = 0; i < GLRenderManager::MAX_INFLIGHT_FRAMES; i++) { frameData_[i].push = renderManager_.CreatePushBuffer(i, GL_ARRAY_BUFFER, 64 * 1024); } + + if (!gl_extensions.VersionGEThan(3, 0, 0)) { + // Don't use this extension on sub 3.0 OpenGL versions as it does not seem reliable. + bugs_.Infest(Bugs::DUAL_SOURCE_BLENDING_BROKEN); + } else if (caps_.vendor == GPUVendor::VENDOR_INTEL) { + // Also on Intel, see https://github.com/hrydgard/ppsspp/issues/10117 + // TODO: Remove entirely sometime reasonably far in driver years after 2015. + const std::string ver = GetInfoString(Draw::InfoField::APIVERSION); + int versions[4]{}; + if (sscanf(ver.c_str(), "Build %d.%d.%d.%d", &versions[0], &versions[1], &versions[2], &versions[3]) == 4) { + if (HasIntelDualSrcBug(versions)) { + bugs_.Infest(Bugs::DUAL_SOURCE_BLENDING_BROKEN); + } + } + } } OpenGLContext::~OpenGLContext() { diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 1a6ba3e216..eaa6b0ad52 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -780,6 +780,14 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit) if (deviceProps.deviceID >= 0x05000000 && deviceProps.deviceID < 0x06000000) { bugs_.Infest(Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL); } + } else if (caps_.vendor == GPUVendor::VENDOR_AMD) { + // See issue #10074, and also #10065 (AMD) and #10109 for the choice of the driver version to check for. + if (deviceProps.driverVersion < 0x00407000) { + bugs_.Infest(Bugs::DUAL_SOURCE_BLENDING_BROKEN); + } + } else if (caps_.vendor == GPUVendor::VENDOR_INTEL) { + // Workaround for Intel driver bug. TODO: Re-enable after some driver version + bugs_.Infest(Bugs::DUAL_SOURCE_BLENDING_BROKEN); } device_ = vulkan->GetDevice(); From e46701dee66d4068ae458be921add06af7e71a7b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 23 Dec 2018 20:08:08 -0800 Subject: [PATCH 254/347] GLES: Specify glsl version precisely in depal. Should prevent more of #11588 on vertex shaders, and may help Apple devices some too. --- GPU/Common/DepalettizeShaderCommon.cpp | 2 +- GPU/GLES/DepalettizeShaderGLES.cpp | 5 +++-- ext/native/gfx_es2/gpu_features.cpp | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/GPU/Common/DepalettizeShaderCommon.cpp b/GPU/Common/DepalettizeShaderCommon.cpp index 3da0c04766..09615ed8b8 100644 --- a/GPU/Common/DepalettizeShaderCommon.cpp +++ b/GPU/Common/DepalettizeShaderCommon.cpp @@ -51,7 +51,7 @@ void GenerateDepalShader300(char *buffer, GEBufferFormat pixelFormat, ShaderLang WRITE(p, "precision mediump float;\n"); WRITE(p, "precision highp int;\n"); } else { - WRITE(p, "#version 330\n"); + WRITE(p, "#version %d\n", gl_extensions.GLSLVersion()); } WRITE(p, "in vec2 v_texcoord0;\n"); WRITE(p, "out vec4 fragColor0;\n"); diff --git a/GPU/GLES/DepalettizeShaderGLES.cpp b/GPU/GLES/DepalettizeShaderGLES.cpp index 8d5780ac62..a6686a5a91 100644 --- a/GPU/GLES/DepalettizeShaderGLES.cpp +++ b/GPU/GLES/DepalettizeShaderGLES.cpp @@ -75,8 +75,9 @@ bool DepalShaderCacheGLES::CreateVertexShader() { std::string prelude; if (gl_extensions.IsGLES) { prelude = useGL3_ ? "#version 300 es\n" : "#version 100\n"; - } else if (useGL3_) { - prelude = "#version 330\n"; + } else { + // We need to add a corresponding #version. Apple drivers fail without an exact match. + prelude = StringFromFormat("#version %d\n", gl_extensions.GLSLVersion()); } vertexShader_ = render_->CreateShader(GL_VERTEX_SHADER, prelude + src, "depal"); return true; diff --git a/ext/native/gfx_es2/gpu_features.cpp b/ext/native/gfx_es2/gpu_features.cpp index 35b1e421c9..3e5c6de3b4 100644 --- a/ext/native/gfx_es2/gpu_features.cpp +++ b/ext/native/gfx_es2/gpu_features.cpp @@ -579,7 +579,7 @@ std::string ApplyGLSLPrelude(const std::string &source, uint32_t stage) { std::string temp; std::string version = ""; if (!gl_extensions.IsGLES && gl_extensions.IsCoreContext) { - // We need to add a corresponding #version. Apple drives fail without an exact match. + // We need to add a corresponding #version. Apple drivers fail without an exact match. version = StringFromFormat("#version %d\n", gl_extensions.GLSLVersion()); } if (stage == GL_FRAGMENT_SHADER) { From 01809f809feaccf838dbda98ff1fa65e61e7eb52 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 23 Dec 2018 20:16:59 -0800 Subject: [PATCH 255/347] GLES: Correct fragment precision check. Was breaking on Mali-4xx for example, because not defined. --- GPU/GLES/DepthBufferGLES.cpp | 2 +- GPU/GLES/StencilBufferGLES.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/GLES/DepthBufferGLES.cpp b/GPU/GLES/DepthBufferGLES.cpp index 3f9c6cde18..cf399cff87 100644 --- a/GPU/GLES/DepthBufferGLES.cpp +++ b/GPU/GLES/DepthBufferGLES.cpp @@ -27,7 +27,7 @@ static const char *depth_dl_fs = R"( #ifdef GL_ES -#if GL_FRAGMENT_PRECISION_HIGH +#ifdef GL_FRAGMENT_PRECISION_HIGH precision highp float; #else precision mediump float; diff --git a/GPU/GLES/StencilBufferGLES.cpp b/GPU/GLES/StencilBufferGLES.cpp index 2f421c44f5..2e13c35885 100644 --- a/GPU/GLES/StencilBufferGLES.cpp +++ b/GPU/GLES/StencilBufferGLES.cpp @@ -27,7 +27,7 @@ static const char *stencil_fs = R"( #ifdef GL_ES -#if GL_FRAGMENT_PRECISION_HIGH +#ifdef GL_FRAGMENT_PRECISION_HIGH precision highp float; #else precision mediump float; // just hope it's enough.. From 7ad6270623737341818df2e9961d2dbd844a4a79 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 23 Dec 2018 20:21:17 -0800 Subject: [PATCH 256/347] GLES: Remove spurious semicolons in shaders. Were causing compile errors on some devices. --- GPU/D3D11/DepalettizeShaderD3D11.cpp | 2 +- GPU/Directx9/DepalettizeShaderDX9.cpp | 2 +- GPU/Directx9/FramebufferDX9.cpp | 4 ++-- GPU/GLES/DepalettizeShaderGLES.cpp | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/GPU/D3D11/DepalettizeShaderD3D11.cpp b/GPU/D3D11/DepalettizeShaderD3D11.cpp index ddd17dc3a8..834b2a5a3e 100644 --- a/GPU/D3D11/DepalettizeShaderD3D11.cpp +++ b/GPU/D3D11/DepalettizeShaderD3D11.cpp @@ -47,7 +47,7 @@ VS_OUT main(VS_IN input) { output.Texcoord = input.a_texcoord0; output.Position = float4(input.a_position, 1.0); return output; -}; +} )"; static const D3D11_INPUT_ELEMENT_DESC g_DepalVertexElements[] = { diff --git a/GPU/Directx9/DepalettizeShaderDX9.cpp b/GPU/Directx9/DepalettizeShaderDX9.cpp index 6c387e1618..2365e41d58 100644 --- a/GPU/Directx9/DepalettizeShaderDX9.cpp +++ b/GPU/Directx9/DepalettizeShaderDX9.cpp @@ -50,7 +50,7 @@ VS_OUT main(VS_IN input) { output.Texcoord = input.a_texcoord0; output.Position = float4(input.a_position, 1.0); return output; -}; +} )"; DepalShaderCacheDX9::DepalShaderCacheDX9(Draw::DrawContext *draw) : vertexShader_(nullptr) { diff --git a/GPU/Directx9/FramebufferDX9.cpp b/GPU/Directx9/FramebufferDX9.cpp index 8631e7b5db..e6f215168e 100644 --- a/GPU/Directx9/FramebufferDX9.cpp +++ b/GPU/Directx9/FramebufferDX9.cpp @@ -61,7 +61,7 @@ VS_OUT main( VS_IN In ) { Out.ProjPos = In.ObjPos; Out.Uv = In.Uv; return Out; -}; +} )"; static const char *pscode = R"( @@ -72,7 +72,7 @@ struct PS_IN { float4 main( PS_IN In ) : COLOR { float4 c = tex2D(s, In.Uv); return c; -}; +} )"; static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { diff --git a/GPU/GLES/DepalettizeShaderGLES.cpp b/GPU/GLES/DepalettizeShaderGLES.cpp index a6686a5a91..c973909c79 100644 --- a/GPU/GLES/DepalettizeShaderGLES.cpp +++ b/GPU/GLES/DepalettizeShaderGLES.cpp @@ -35,7 +35,7 @@ varying vec2 v_texcoord0; void main() { v_texcoord0 = a_texcoord0; gl_Position = a_position; -}; +} )"; static const char *depalVShader300 = R"( @@ -48,7 +48,7 @@ out vec2 v_texcoord0; void main() { v_texcoord0 = a_texcoord0; gl_Position = a_position; -}; +} )"; DepalShaderCacheGLES::DepalShaderCacheGLES(Draw::DrawContext *draw) { From adeca2c3ba0023eab746aed1a40029053cddeb4e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 23 Dec 2018 12:46:48 -0800 Subject: [PATCH 257/347] GLES: Move some vendor bug checks to Draw. --- GPU/GLES/TextureCacheGLES.cpp | 2 +- Qt/QtMain.h | 2 +- SDL/SDLGLGraphicsContext.h | 2 +- Windows/GPU/WindowsGLContext.cpp | 2 +- android/jni/AndroidEGLContext.h | 2 +- android/jni/AndroidJavaGLContext.h | 2 +- ext/native/gfx_es2/gpu_features.cpp | 7 ------- ext/native/gfx_es2/gpu_features.h | 2 -- ext/native/thin3d/GLRenderManager.cpp | 6 ++++-- ext/native/thin3d/GLRenderManager.h | 6 +++++- ext/native/thin3d/thin3d.h | 2 ++ ext/native/thin3d/thin3d_gl.cpp | 12 ++++++++++++ headless/SDLHeadlessHost.cpp | 2 +- ios/ViewController.mm | 2 +- libretro/LibretroGLContext.h | 2 +- 15 files changed, 32 insertions(+), 21 deletions(-) diff --git a/GPU/GLES/TextureCacheGLES.cpp b/GPU/GLES/TextureCacheGLES.cpp index 395651f24b..9bfc2a6cfa 100644 --- a/GPU/GLES/TextureCacheGLES.cpp +++ b/GPU/GLES/TextureCacheGLES.cpp @@ -672,7 +672,7 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry) { } } else { // Avoid PowerVR driver bug - if (canAutoGen && w > 1 && h > 1 && !(h > w && (gl_extensions.bugs & BUG_PVR_GENMIPMAP_HEIGHT_GREATER))) { // Really! only seems to fail if height > width + if (canAutoGen && w > 1 && h > 1 && !(h > w && draw_->GetBugs().Has(Draw::Bugs::PVR_GENMIPMAP_HEIGHT_GREATER))) { // Really! only seems to fail if height > width // NOTICE_LOG(G3D, "Generating mipmap for texture sized %dx%d%d", w, h, (int)format); genMips = true; } else { diff --git a/Qt/QtMain.h b/Qt/QtMain.h index 70d89b88d8..3e165a8d9f 100644 --- a/Qt/QtMain.h +++ b/Qt/QtMain.h @@ -73,7 +73,7 @@ public: } void ThreadStart() override { - renderManager_->ThreadStart(); + renderManager_->ThreadStart(draw_); } bool ThreadFrame() override { diff --git a/SDL/SDLGLGraphicsContext.h b/SDL/SDLGLGraphicsContext.h index e0cb354701..c32d104814 100644 --- a/SDL/SDLGLGraphicsContext.h +++ b/SDL/SDLGLGraphicsContext.h @@ -32,7 +32,7 @@ public: } void ThreadStart() override { - renderManager_->ThreadStart(); + renderManager_->ThreadStart(draw_); } bool ThreadFrame() override { diff --git a/Windows/GPU/WindowsGLContext.cpp b/Windows/GPU/WindowsGLContext.cpp index 002464cf27..0701ffa4aa 100644 --- a/Windows/GPU/WindowsGLContext.cpp +++ b/Windows/GPU/WindowsGLContext.cpp @@ -458,7 +458,7 @@ void WindowsGLContext::Resize() { } void WindowsGLContext::ThreadStart() { - renderManager_->ThreadStart(); + renderManager_->ThreadStart(draw_); } bool WindowsGLContext::ThreadFrame() { diff --git a/android/jni/AndroidEGLContext.h b/android/jni/AndroidEGLContext.h index 35ae334294..45b33f8241 100644 --- a/android/jni/AndroidEGLContext.h +++ b/android/jni/AndroidEGLContext.h @@ -21,7 +21,7 @@ public: } void ThreadStart() override { - renderManager_->ThreadStart(); + renderManager_->ThreadStart(draw_); } bool ThreadFrame() override { diff --git a/android/jni/AndroidJavaGLContext.h b/android/jni/AndroidJavaGLContext.h index 99db77dfcb..05d3966896 100644 --- a/android/jni/AndroidJavaGLContext.h +++ b/android/jni/AndroidJavaGLContext.h @@ -34,7 +34,7 @@ public: } void ThreadStart() override { - renderManager_->ThreadStart(); + renderManager_->ThreadStart(draw_); } bool ThreadFrame() override { diff --git a/ext/native/gfx_es2/gpu_features.cpp b/ext/native/gfx_es2/gpu_features.cpp index 35b1e421c9..c6b71021af 100644 --- a/ext/native/gfx_es2/gpu_features.cpp +++ b/ext/native/gfx_es2/gpu_features.cpp @@ -114,13 +114,6 @@ void ProcessGPUFeatures() { WLOG("GL DRIVER BUG: PVR with bad precision"); gl_extensions.bugs |= BUG_PVR_SHADER_PRECISION_BAD; } - gl_extensions.bugs |= BUG_PVR_GENMIPMAP_HEIGHT_GREATER; - } - - // TODO: Make this check more lenient. Disabled for all right now - // because it murders performance on Mali. - if (gl_extensions.gpuVendor != GPU_VENDOR_NVIDIA) { - gl_extensions.bugs |= BUG_ANY_MAP_BUFFER_RANGE_SLOW; } } diff --git a/ext/native/gfx_es2/gpu_features.h b/ext/native/gfx_es2/gpu_features.h index 6764d08105..80cbc906bd 100644 --- a/ext/native/gfx_es2/gpu_features.h +++ b/ext/native/gfx_es2/gpu_features.h @@ -22,8 +22,6 @@ enum { BUG_FBO_UNUSABLE = 1, BUG_PVR_SHADER_PRECISION_BAD = 2, BUG_PVR_SHADER_PRECISION_TERRIBLE = 4, - BUG_PVR_GENMIPMAP_HEIGHT_GREATER = 8, - BUG_ANY_MAP_BUFFER_RANGE_SLOW = 16, }; // Extensions to look at using: diff --git a/ext/native/thin3d/GLRenderManager.cpp b/ext/native/thin3d/GLRenderManager.cpp index bc9defccad..b7585b7a03 100644 --- a/ext/native/thin3d/GLRenderManager.cpp +++ b/ext/native/thin3d/GLRenderManager.cpp @@ -2,6 +2,7 @@ #include "GLRenderManager.h" #include "gfx_es2/gpu_features.h" +#include "thin3d/thin3d.h" #include "thread/threadutil.h" #include "base/logging.h" #include "GPU/GPUState.h" @@ -89,12 +90,13 @@ GLRenderManager::~GLRenderManager() { _assert_(deleter_.IsEmpty()); } -void GLRenderManager::ThreadStart() { +void GLRenderManager::ThreadStart(Draw::DrawContext *draw) { queueRunner_.CreateDeviceObjects(); threadFrame_ = threadInitFrame_; renderThreadId = std::this_thread::get_id(); - bool mapBuffers = (gl_extensions.bugs & BUG_ANY_MAP_BUFFER_RANGE_SLOW) == 0; + // Don't save draw, we don't want any thread safety confusion. + bool mapBuffers = draw->GetBugs().Has(Draw::Bugs::ANY_MAP_BUFFER_RANGE_SLOW); bool hasBufferStorage = gl_extensions.ARB_buffer_storage || gl_extensions.EXT_buffer_storage; if (!gl_extensions.VersionGEThan(3, 0, 0) && gl_extensions.IsGLES && !hasBufferStorage) { // Force disable if it wouldn't work anyway. diff --git a/ext/native/thin3d/GLRenderManager.h b/ext/native/thin3d/GLRenderManager.h index 719ad156e6..7b38c024e8 100644 --- a/ext/native/thin3d/GLRenderManager.h +++ b/ext/native/thin3d/GLRenderManager.h @@ -19,6 +19,10 @@ class GLRInputLayout; class GLPushBuffer; +namespace Draw { +class DrawContext; +} + class GLRTexture { public: ~GLRTexture() { @@ -365,7 +369,7 @@ public: GLRenderManager(); ~GLRenderManager(); - void ThreadStart(); + void ThreadStart(Draw::DrawContext *draw); void ThreadEnd(); bool ThreadFrame(); // Returns false to request exiting the loop. diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 8e8f5eb81d..1d0e28a983 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -327,6 +327,8 @@ public: enum : uint32_t { NO_DEPTH_CANNOT_DISCARD_STENCIL = 0, DUAL_SOURCE_BLENDING_BROKEN = 1, + ANY_MAP_BUFFER_RANGE_SLOW = 2, + PVR_GENMIPMAP_HEIGHT_GREATER = 3, }; protected: diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index e3668b8b97..1d812ce496 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -568,6 +568,18 @@ OpenGLContext::OpenGLContext() { } } } + + // TODO: Make this check more lenient. Disabled for all right now + // because it murders performance on Mali. + if (caps_.vendor != GPUVendor::VENDOR_NVIDIA) { + bugs_.Infest(Bugs::ANY_MAP_BUFFER_RANGE_SLOW); + } + + if (caps_.vendor == GPUVendor::VENDOR_IMGTEC) { + // See https://github.com/hrydgard/ppsspp/commit/8974cd675e538f4445955e3eac572a9347d84232 + // TODO: Should this workaround be removed for newer devices/drivers? + bugs_.Infest(Bugs::PVR_GENMIPMAP_HEIGHT_GREATER); + } } OpenGLContext::~OpenGLContext() { diff --git a/headless/SDLHeadlessHost.cpp b/headless/SDLHeadlessHost.cpp index 1545a53f9c..c5702eabc4 100644 --- a/headless/SDLHeadlessHost.cpp +++ b/headless/SDLHeadlessHost.cpp @@ -76,7 +76,7 @@ public: } void ThreadStart() override { - renderManager_->ThreadStart(); + renderManager_->ThreadStart(draw_); } bool ThreadFrame() override { diff --git a/ios/ViewController.mm b/ios/ViewController.mm index 61c2eee554..0c5c5ae5da 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -51,7 +51,7 @@ public: return draw_; } void ThreadStart() override { - renderManager_->ThreadStart(); + renderManager_->ThreadStart(draw_); } bool ThreadFrame() override { diff --git a/libretro/LibretroGLContext.h b/libretro/LibretroGLContext.h index 8a91044fdd..b85c8affb0 100644 --- a/libretro/LibretroGLContext.h +++ b/libretro/LibretroGLContext.h @@ -26,7 +26,7 @@ public: g_defaultFBO = hw_render_.get_current_framebuffer(); } - void ThreadStart() override { renderManager_->ThreadStart(); } + void ThreadStart() override { renderManager_->ThreadStart(draw_); } bool ThreadFrame() override { return renderManager_->ThreadFrame(); } void ThreadEnd() override { renderManager_->ThreadEnd(); } void StopThread() override { From 58ef662a65ecff21dbd742b397669fafcad53c33 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 23 Dec 2018 12:47:06 -0800 Subject: [PATCH 258/347] GLES: Remove FBO_UNUSABLE bug check. Was no longer affecting behavior... --- ext/native/gfx_es2/gpu_features.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ext/native/gfx_es2/gpu_features.cpp b/ext/native/gfx_es2/gpu_features.cpp index c6b71021af..9ff80a51de 100644 --- a/ext/native/gfx_es2/gpu_features.cpp +++ b/ext/native/gfx_es2/gpu_features.cpp @@ -98,11 +98,6 @@ void ProcessGPUFeatures() { DLOG("Checking for GL driver bugs... vendor=%i model='%s'", (int)gl_extensions.gpuVendor, gl_extensions.model); - // Should be table driven instead, this is a quick hack for Galaxy Y - if (System_GetProperty(SYSPROP_NAME) == "samsung:GT-S5360") { - gl_extensions.bugs |= BUG_FBO_UNUSABLE; - } - if (gl_extensions.gpuVendor == GPU_VENDOR_IMGTEC) { if (!strcmp(gl_extensions.model, "PowerVR SGX 543") || !strcmp(gl_extensions.model, "PowerVR SGX 540") || From 6b975caa3bcaa85b5f768228464c92296a3bfbae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 26 Dec 2018 20:32:21 +0100 Subject: [PATCH 259/347] Update lang submodule --- assets/lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/lang b/assets/lang index c4698e4f04..f01d2de306 160000 --- a/assets/lang +++ b/assets/lang @@ -1 +1 @@ -Subproject commit c4698e4f04c61503d95de032fad8e28909b4d447 +Subproject commit f01d2de306fb645d24550ccb4a4c8f701268e38f From 359afb2d6b6f170c53460d01fd39963f5c51c136 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 27 Dec 2018 10:15:58 -0800 Subject: [PATCH 260/347] http: Add timeout on no response. Firewalls can cause this, by opening a connection but never responding. --- Core/FileLoaders/HTTPFileLoader.cpp | 5 ++++- ext/native/base/buffer.cpp | 8 ++++++-- ext/native/base/buffer.h | 8 ++++---- ext/native/net/http_client.cpp | 6 +++++- ext/native/net/http_client.h | 6 ++++++ 5 files changed, 25 insertions(+), 8 deletions(-) diff --git a/Core/FileLoaders/HTTPFileLoader.cpp b/Core/FileLoaders/HTTPFileLoader.cpp index 4dda285844..f3407d1127 100644 --- a/Core/FileLoaders/HTTPFileLoader.cpp +++ b/Core/FileLoaders/HTTPFileLoader.cpp @@ -28,17 +28,20 @@ HTTPFileLoader::HTTPFileLoader(const std::string &filename) void HTTPFileLoader::Prepare() { std::call_once(preparedFlag_, [this](){ if (!client_.Resolve(url_.Host().c_str(), url_.Port())) { - // TODO: Should probably set some flag? + ERROR_LOG(LOADER, "HTTP request failed, unable to resolve: %s port %d", url_.Host().c_str(), url_.Port()); return; } + client_.SetDataTimeout(20.0); Connect(); if (!connected_) { + ERROR_LOG(LOADER, "HTTP request failed, failed to connect: %s port %d", url_.Host().c_str(), url_.Port()); return; } int err = client_.SendRequest("HEAD", url_.Resource().c_str()); if (err < 0) { + ERROR_LOG(LOADER, "HTTP request failed, failed to send request: %s port %d", url_.Host().c_str(), url_.Port()); Disconnect(); return; } diff --git a/ext/native/base/buffer.cpp b/ext/native/base/buffer.cpp index 9b268976bb..8e48848319 100644 --- a/ext/native/base/buffer.cpp +++ b/ext/native/base/buffer.cpp @@ -146,8 +146,12 @@ bool Buffer::FlushToFile(const char *filename) { return true; } -bool Buffer::FlushSocket(uintptr_t sock) { +bool Buffer::FlushSocket(uintptr_t sock, double timeout) { for (size_t pos = 0, end = data_.size(); pos < end; ) { + if (timeout >= 0.0 && !fd_util::WaitUntilReady(sock, timeout, true)) { + ELOG("FlushSocket timed out"); + return false; + } int sent = send(sock, &data_[pos], (int)(end - pos), MSG_NOSIGNAL); if (sent < 0) { ELOG("FlushSocket failed"); @@ -156,7 +160,7 @@ bool Buffer::FlushSocket(uintptr_t sock) { pos += sent; // Buffer full, don't spin. - if (sent == 0) { + if (sent == 0 && timeout < 0.0) { sleep_ms(1); } } diff --git a/ext/native/base/buffer.h b/ext/native/base/buffer.h index bca84d9ba7..b34901fb17 100644 --- a/ext/native/base/buffer.h +++ b/ext/native/base/buffer.h @@ -59,12 +59,12 @@ class Buffer { // Simple I/O. - // Writes the entire buffer to the file descriptor. Also resets the - // size to zero. On failure, data remains in buffer and nothing is - // written. + // Writes the entire buffer to the file descriptor. Also resets the + // size to zero. On failure, data remains in buffer and nothing is + // written. bool Flush(int fd); bool FlushToFile(const char *filename); - bool FlushSocket(uintptr_t sock); // Windows portability + bool FlushSocket(uintptr_t sock, double timeout = -1.0); // Windows portability bool ReadAll(int fd, int hintSize = 0); bool ReadAllWithProgress(int fd, int knownSize, float *progress, bool *cancelled); diff --git a/ext/native/net/http_client.cpp b/ext/native/net/http_client.cpp index 3cb6967326..1954f69ce2 100644 --- a/ext/native/net/http_client.cpp +++ b/ext/native/net/http_client.cpp @@ -283,7 +283,7 @@ int Client::SendRequestWithData(const char *method, const char *resource, const userAgent_, otherHeaders ? otherHeaders : ""); buffer.Append(data); - bool flushed = buffer.FlushSocket(sock()); + bool flushed = buffer.FlushSocket(sock(), dataTimeout_); if (!flushed) { return -1; // TODO error code. } @@ -292,6 +292,10 @@ int Client::SendRequestWithData(const char *method, const char *resource, const int Client::ReadResponseHeaders(Buffer *readbuf, std::vector &responseHeaders, float *progress) { // Snarf all the data we can into RAM. A little unsafe but hey. + if (dataTimeout_ >= 0.0 && fd_util::WaitUntilReady(sock(), dataTimeout_, false)) { + ELOG("HTTP headers timed out"); + return -1; + } if (readbuf->Read(sock(), 4096) < 0) { ELOG("Failed to read HTTP headers :("); return -1; diff --git a/ext/native/net/http_client.h b/ext/native/net/http_client.h index ac3d26ed97..348cf33d93 100644 --- a/ext/native/net/http_client.h +++ b/ext/native/net/http_client.h @@ -75,8 +75,14 @@ public: // If your response contains a response, you must read it. int ReadResponseEntity(Buffer *readbuf, const std::vector &responseHeaders, Buffer *output, float *progress = nullptr, bool *cancelled = nullptr); + void SetDataTimeout(double t) { + dataTimeout_ = t; + } + +protected: const char *userAgent_; const char *httpVersion_; + double dataTimeout_ = -1.0; }; // Not particularly efficient, but hey - it's a background download, that's pretty cool :P From 7f84c87931eaafd1ddb3928292bf8ee85c5be195 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 27 Dec 2018 10:32:47 -0800 Subject: [PATCH 261/347] Loaders: Refactor chaining to avoid dup code. --- Core/FileLoaders/CachingFileLoader.cpp | 24 ++++----------- Core/FileLoaders/CachingFileLoader.h | 7 +---- Core/FileLoaders/DiskCachingFileLoader.cpp | 28 ++++------------- Core/FileLoaders/DiskCachingFileLoader.h | 8 +---- Core/FileLoaders/RamCachingFileLoader.cpp | 20 ++++--------- Core/FileLoaders/RamCachingFileLoader.h | 5 +--- Core/FileLoaders/RetryingFileLoader.cpp | 33 +++++--------------- Core/FileLoaders/RetryingFileLoader.h | 9 +----- Core/Loaders.h | 35 ++++++++++++++++++++++ 9 files changed, 62 insertions(+), 107 deletions(-) diff --git a/Core/FileLoaders/CachingFileLoader.cpp b/Core/FileLoaders/CachingFileLoader.cpp index 597fafadcc..61a7459045 100644 --- a/Core/FileLoaders/CachingFileLoader.cpp +++ b/Core/FileLoaders/CachingFileLoader.cpp @@ -25,12 +25,12 @@ // Takes ownership of backend. CachingFileLoader::CachingFileLoader(FileLoader *backend) - : backend_(backend) { + : ProxiedFileLoader(backend) { } void CachingFileLoader::Prepare() { std::call_once(preparedFlag_, [this](){ - filesize_ = backend_->FileSize(); + filesize_ = ProxiedFileLoader::FileSize(); if (filesize_ > 0) { InitCache(); } @@ -41,27 +41,25 @@ CachingFileLoader::~CachingFileLoader() { if (filesize_ > 0) { ShutdownCache(); } - // Takes ownership. - delete backend_; } bool CachingFileLoader::Exists() { if (exists_ == -1) { - exists_ = backend_->Exists() ? 1 : 0; + exists_ = ProxiedFileLoader::Exists() ? 1 : 0; } return exists_ == 1; } bool CachingFileLoader::ExistsFast() { if (exists_ == -1) { - return backend_->ExistsFast(); + return ProxiedFileLoader::ExistsFast(); } return exists_ == 1; } bool CachingFileLoader::IsDirectory() { if (isDirectory_ == -1) { - isDirectory_ = backend_->IsDirectory() ? 1 : 0; + isDirectory_ = ProxiedFileLoader::IsDirectory() ? 1 : 0; } return isDirectory_ == 1; } @@ -71,10 +69,6 @@ s64 CachingFileLoader::FileSize() { return filesize_; } -std::string CachingFileLoader::Path() const { - return backend_->Path(); -} - size_t CachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags) { Prepare(); if (absolutePos >= filesize_) { @@ -288,11 +282,3 @@ void CachingFileLoader::StartReadAhead(s64 pos) { }); th.detach(); } - -bool CachingFileLoader::IsRemote() { - return backend_->IsRemote(); -} - -void CachingFileLoader::Cancel() { - backend_->Cancel(); -} diff --git a/Core/FileLoaders/CachingFileLoader.h b/Core/FileLoaders/CachingFileLoader.h index 03d3aa726e..97fe0aa682 100644 --- a/Core/FileLoaders/CachingFileLoader.h +++ b/Core/FileLoaders/CachingFileLoader.h @@ -23,25 +23,21 @@ #include "Common/CommonTypes.h" #include "Core/Loaders.h" -class CachingFileLoader : public FileLoader { +class CachingFileLoader : public ProxiedFileLoader { public: CachingFileLoader(FileLoader *backend); ~CachingFileLoader() override; - bool IsRemote() override; bool Exists() override; bool ExistsFast() override; bool IsDirectory() override; s64 FileSize() override; - std::string Path() const override; size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override { return ReadAt(absolutePos, bytes * count, data, flags) / bytes; } size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override; - void Cancel() override; - private: void Prepare(); void InitCache(); @@ -61,7 +57,6 @@ private: }; s64 filesize_ = 0; - FileLoader *backend_; int exists_ = -1; int isDirectory_ = -1; u64 generation_; diff --git a/Core/FileLoaders/DiskCachingFileLoader.cpp b/Core/FileLoaders/DiskCachingFileLoader.cpp index b098df4866..bb48ad3dbf 100644 --- a/Core/FileLoaders/DiskCachingFileLoader.cpp +++ b/Core/FileLoaders/DiskCachingFileLoader.cpp @@ -41,12 +41,12 @@ std::mutex DiskCachingFileLoader::cachesMutex_; // Takes ownership of backend. DiskCachingFileLoader::DiskCachingFileLoader(FileLoader *backend) - : backend_(backend) { + : ProxiedFileLoader(backend) { } void DiskCachingFileLoader::Prepare() { std::call_once(preparedFlag_, [this]() { - filesize_ = backend_->FileSize(); + filesize_ = ProxiedFileLoader::FileSize(); if (filesize_ > 0) { InitCache(); } @@ -57,13 +57,11 @@ DiskCachingFileLoader::~DiskCachingFileLoader() { if (filesize_ > 0) { ShutdownCache(); } - // Takes ownership. - delete backend_; } bool DiskCachingFileLoader::Exists() { Prepare(); - return backend_->Exists(); + return ProxiedFileLoader::Exists(); } bool DiskCachingFileLoader::ExistsFast() { @@ -72,19 +70,11 @@ bool DiskCachingFileLoader::ExistsFast() { return true; } -bool DiskCachingFileLoader::IsDirectory() { - return backend_->IsDirectory(); -} - s64 DiskCachingFileLoader::FileSize() { Prepare(); return filesize_; } -std::string DiskCachingFileLoader::Path() const { - return backend_->Path(); -} - size_t DiskCachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags) { Prepare(); size_t readSize; @@ -115,14 +105,6 @@ size_t DiskCachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, return readSize; } -bool DiskCachingFileLoader::IsRemote() { - return backend_->IsRemote(); -} - -void DiskCachingFileLoader::Cancel() { - backend_->Cancel(); -} - std::vector DiskCachingFileLoader::GetCachedPathsInUse() { std::lock_guard guard(cachesMutex_); @@ -139,7 +121,7 @@ std::vector DiskCachingFileLoader::GetCachedPathsInUse() { void DiskCachingFileLoader::InitCache() { std::lock_guard guard(cachesMutex_); - std::string path = backend_->Path(); + std::string path = ProxiedFileLoader::Path(); auto &entry = caches_[path]; if (!entry) { entry = new DiskCachingFileLoaderCache(path, filesize_); @@ -155,7 +137,7 @@ void DiskCachingFileLoader::ShutdownCache() { if (cache_->Release()) { // If it ran out of counts, delete it. delete cache_; - caches_.erase(backend_->Path()); + caches_.erase(ProxiedFileLoader::Path()); } cache_ = nullptr; } diff --git a/Core/FileLoaders/DiskCachingFileLoader.h b/Core/FileLoaders/DiskCachingFileLoader.h index e396ff5736..622ffb0f07 100644 --- a/Core/FileLoaders/DiskCachingFileLoader.h +++ b/Core/FileLoaders/DiskCachingFileLoader.h @@ -27,25 +27,20 @@ class DiskCachingFileLoaderCache; -class DiskCachingFileLoader : public FileLoader { +class DiskCachingFileLoader : public ProxiedFileLoader { public: DiskCachingFileLoader(FileLoader *backend); ~DiskCachingFileLoader() override; - bool IsRemote() override; bool Exists() override; bool ExistsFast() override; - bool IsDirectory() override; s64 FileSize() override; - std::string Path() const override; size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override { return ReadAt(absolutePos, bytes * count, data, flags) / bytes; } size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override; - void Cancel() override; - static std::vector GetCachedPathsInUse(); private: @@ -55,7 +50,6 @@ private: std::once_flag preparedFlag_; s64 filesize_ = 0; - FileLoader *backend_; DiskCachingFileLoaderCache *cache_ = nullptr; // We don't support concurrent disk cache access (we use memory cached indexes.) diff --git a/Core/FileLoaders/RamCachingFileLoader.cpp b/Core/FileLoaders/RamCachingFileLoader.cpp index ccaa3c7bef..4b934cebdf 100644 --- a/Core/FileLoaders/RamCachingFileLoader.cpp +++ b/Core/FileLoaders/RamCachingFileLoader.cpp @@ -28,7 +28,7 @@ // Takes ownership of backend. RamCachingFileLoader::RamCachingFileLoader(FileLoader *backend) - : backend_(backend) { + : ProxiedFileLoader(backend) { filesize_ = backend->FileSize(); if (filesize_ > 0) { InitCache(); @@ -39,27 +39,25 @@ RamCachingFileLoader::~RamCachingFileLoader() { if (filesize_ > 0) { ShutdownCache(); } - // Takes ownership. - delete backend_; } bool RamCachingFileLoader::Exists() { if (exists_ == -1) { - exists_ = backend_->Exists() ? 1 : 0; + exists_ = ProxiedFileLoader::Exists() ? 1 : 0; } return exists_ == 1; } bool RamCachingFileLoader::ExistsFast() { if (exists_ == -1) { - return backend_->ExistsFast(); + return ProxiedFileLoader::ExistsFast(); } return exists_ == 1; } bool RamCachingFileLoader::IsDirectory() { if (isDirectory_ == -1) { - isDirectory_ = backend_->IsDirectory() ? 1 : 0; + isDirectory_ = ProxiedFileLoader::IsDirectory() ? 1 : 0; } return isDirectory_ == 1; } @@ -68,10 +66,6 @@ s64 RamCachingFileLoader::FileSize() { return filesize_; } -std::string RamCachingFileLoader::Path() const { - return backend_->Path(); -} - size_t RamCachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags) { size_t readSize = 0; if (cache_ == nullptr || (flags & Flags::HINT_UNCACHED) != 0) { @@ -129,7 +123,7 @@ void RamCachingFileLoader::Cancel() { aheadCancel_ = true; } - backend_->Cancel(); + ProxiedFileLoader::Cancel(); } size_t RamCachingFileLoader::ReadFromCache(s64 pos, size_t bytes, void *data) { @@ -270,7 +264,3 @@ u32 RamCachingFileLoader::NextAheadBlock() { return 0xFFFFFFFF; } - -bool RamCachingFileLoader::IsRemote() { - return backend_->IsRemote(); -} diff --git a/Core/FileLoaders/RamCachingFileLoader.h b/Core/FileLoaders/RamCachingFileLoader.h index 624305155a..60ca2afc91 100644 --- a/Core/FileLoaders/RamCachingFileLoader.h +++ b/Core/FileLoaders/RamCachingFileLoader.h @@ -23,17 +23,15 @@ #include "Common/CommonTypes.h" #include "Core/Loaders.h" -class RamCachingFileLoader : public FileLoader { +class RamCachingFileLoader : public ProxiedFileLoader { public: RamCachingFileLoader(FileLoader *backend); ~RamCachingFileLoader() override; - bool IsRemote() override; bool Exists() override; bool ExistsFast() override; bool IsDirectory() override; s64 FileSize() override; - std::string Path() const override; size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override { return ReadAt(absolutePos, bytes * count, data, flags) / bytes; @@ -59,7 +57,6 @@ private: }; s64 filesize_ = 0; - FileLoader *backend_; u8 *cache_ = nullptr; int exists_ = -1; int isDirectory_ = -1; diff --git a/Core/FileLoaders/RetryingFileLoader.cpp b/Core/FileLoaders/RetryingFileLoader.cpp index 4ce1da0261..b986d76bc9 100644 --- a/Core/FileLoaders/RetryingFileLoader.cpp +++ b/Core/FileLoaders/RetryingFileLoader.cpp @@ -19,47 +19,38 @@ // Takes ownership of backend. RetryingFileLoader::RetryingFileLoader(FileLoader *backend) - : backend_(backend) { -} - -RetryingFileLoader::~RetryingFileLoader() { - // Takes ownership. - delete backend_; + : ProxiedFileLoader(backend) { } bool RetryingFileLoader::Exists() { - if (!backend_->Exists()) { + if (!ProxiedFileLoader::Exists()) { // Retry once, immediately. - return backend_->Exists(); + return ProxiedFileLoader::Exists(); } return true; } bool RetryingFileLoader::ExistsFast() { - if (!backend_->ExistsFast()) { + if (!ProxiedFileLoader::ExistsFast()) { // Retry once, immediately. - return backend_->ExistsFast(); + return ProxiedFileLoader::ExistsFast(); } return true; } bool RetryingFileLoader::IsDirectory() { // Can't tell if it's an error either way. - return backend_->IsDirectory(); + return ProxiedFileLoader::IsDirectory(); } s64 RetryingFileLoader::FileSize() { - s64 filesize = backend_->FileSize(); + s64 filesize = ProxiedFileLoader::FileSize(); if (filesize == 0) { - return backend_->FileSize(); + return ProxiedFileLoader::FileSize(); } return filesize; } -std::string RetryingFileLoader::Path() const { - return backend_->Path(); -} - size_t RetryingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags) { size_t readSize = backend_->ReadAt(absolutePos, bytes, data, flags); @@ -72,11 +63,3 @@ size_t RetryingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Fla return readSize; } - -bool RetryingFileLoader::IsRemote() { - return backend_->IsRemote(); -} - -void RetryingFileLoader::Cancel() { - backend_->Cancel(); -} diff --git a/Core/FileLoaders/RetryingFileLoader.h b/Core/FileLoaders/RetryingFileLoader.h index 5c8cb59292..c13edba926 100644 --- a/Core/FileLoaders/RetryingFileLoader.h +++ b/Core/FileLoaders/RetryingFileLoader.h @@ -20,29 +20,22 @@ #include "Common/CommonTypes.h" #include "Core/Loaders.h" -class RetryingFileLoader : public FileLoader { +class RetryingFileLoader : public ProxiedFileLoader { public: RetryingFileLoader(FileLoader *backend); - ~RetryingFileLoader() override; - bool IsRemote() override; bool Exists() override; bool ExistsFast() override; bool IsDirectory() override; s64 FileSize() override; - std::string Path() const override; size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override { return ReadAt(absolutePos, bytes * count, data, flags) / bytes; } size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override; - void Cancel() override; - private: enum { MAX_RETRIES = 3, }; - - FileLoader *backend_; }; diff --git a/Core/Loaders.h b/Core/Loaders.h index f0e83adab4..216cc0fcd9 100644 --- a/Core/Loaders.h +++ b/Core/Loaders.h @@ -95,6 +95,41 @@ public: } }; +class ProxiedFileLoader : public FileLoader { +public: + ProxiedFileLoader(FileLoader *backend) : backend_(backend) { + } + ~ProxiedFileLoader() override { + // Takes ownership. + delete backend_; + } + + bool IsRemote() override { + return backend_->IsRemote(); + } + bool Exists() override { + return backend_->Exists(); + } + bool ExistsFast() override { + return backend_->ExistsFast(); + } + bool IsDirectory() override { + return backend_->IsDirectory(); + } + s64 FileSize() override { + return backend_->FileSize(); + } + std::string Path() const override { + return backend_->Path(); + } + void Cancel() override { + backend_->Cancel(); + } + +protected: + FileLoader *backend_; +}; + inline u32 operator & (const FileLoader::Flags &a, const FileLoader::Flags &b) { return (u32)a & (u32)b; } From 872fcecfad5bb2291800e1daea3aa2e9fedb81a8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 27 Dec 2018 10:33:32 -0800 Subject: [PATCH 262/347] http: Report errors reading discs. For more clarity when they can't load. --- Core/FileLoaders/HTTPFileLoader.cpp | 7 +++++++ Core/FileLoaders/HTTPFileLoader.h | 5 +++++ Core/Loaders.cpp | 4 +++- Core/Loaders.h | 7 +++++++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Core/FileLoaders/HTTPFileLoader.cpp b/Core/FileLoaders/HTTPFileLoader.cpp index f3407d1127..9c14f5b9fb 100644 --- a/Core/FileLoaders/HTTPFileLoader.cpp +++ b/Core/FileLoaders/HTTPFileLoader.cpp @@ -29,6 +29,7 @@ void HTTPFileLoader::Prepare() { std::call_once(preparedFlag_, [this](){ if (!client_.Resolve(url_.Host().c_str(), url_.Port())) { ERROR_LOG(LOADER, "HTTP request failed, unable to resolve: %s port %d", url_.Host().c_str(), url_.Port()); + latestError_ = "Could not connect (name not resolved)"; return; } @@ -36,12 +37,14 @@ void HTTPFileLoader::Prepare() { Connect(); if (!connected_) { ERROR_LOG(LOADER, "HTTP request failed, failed to connect: %s port %d", url_.Host().c_str(), url_.Port()); + latestError_ = "Could not connect (refused to connect)"; return; } int err = client_.SendRequest("HEAD", url_.Resource().c_str()); if (err < 0) { ERROR_LOG(LOADER, "HTTP request failed, failed to send request: %s port %d", url_.Host().c_str(), url_.Port()); + latestError_ = "Could not connect (could not request data)"; Disconnect(); return; } @@ -52,6 +55,7 @@ void HTTPFileLoader::Prepare() { if (code != 200) { // Leave size at 0, invalid. ERROR_LOG(LOADER, "HTTP request failed, got %03d for %s", code, filename_.c_str()); + latestError_ = "Could not connect (invalid response)"; Disconnect(); return; } @@ -141,6 +145,7 @@ size_t HTTPFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags f int err = client_.SendRequest("GET", url_.Resource().c_str(), requestHeaders, nullptr); if (err < 0) { + latestError_ = "Invalid response reading data"; Disconnect(); return 0; } @@ -150,6 +155,7 @@ size_t HTTPFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags f int code = client_.ReadResponseHeaders(&readbuf, responseHeaders); if (code != 206) { ERROR_LOG(LOADER, "HTTP server did not respond with range, received code=%03d", code); + latestError_ = "Invalid response reading data"; Disconnect(); return 0; } @@ -188,6 +194,7 @@ size_t HTTPFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags f if (!supportedResponse) { ERROR_LOG(LOADER, "HTTP server did not respond with the range we wanted."); + latestError_ = "Invalid response reading data"; return 0; } diff --git a/Core/FileLoaders/HTTPFileLoader.h b/Core/FileLoaders/HTTPFileLoader.h index ab4773604f..d853153177 100644 --- a/Core/FileLoaders/HTTPFileLoader.h +++ b/Core/FileLoaders/HTTPFileLoader.h @@ -48,6 +48,10 @@ public: cancelConnect_ = true; } + std::string LatestError() const override { + return latestError_; + } + private: void Prepare(); @@ -67,6 +71,7 @@ private: std::string filename_; bool connected_ = false; bool cancelConnect_ = false; + const char *latestError_ = ""; std::once_flag preparedFlag_; std::mutex readAtMutex_; diff --git a/Core/Loaders.cpp b/Core/Loaders.cpp index c901a1245a..14bc31973d 100644 --- a/Core/Loaders.cpp +++ b/Core/Loaders.cpp @@ -294,7 +294,9 @@ bool LoadFile(FileLoader **fileLoaderPtr, std::string *error_string) { case IdentifiedFileType::ERROR_IDENTIFYING: ERROR_LOG(LOADER, "Could not read file"); - *error_string = "Error reading file"; + *error_string = fileLoader ? fileLoader->LatestError() : ""; + if (error_string->empty()) + *error_string = "Error reading file"; break; case IdentifiedFileType::ARCHIVE_RAR: diff --git a/Core/Loaders.h b/Core/Loaders.h index 216cc0fcd9..527fa52f5b 100644 --- a/Core/Loaders.h +++ b/Core/Loaders.h @@ -93,6 +93,10 @@ public: // Cancel any operations that might block, if possible. virtual void Cancel() { } + + virtual std::string LatestError() const { + return ""; + } }; class ProxiedFileLoader : public FileLoader { @@ -125,6 +129,9 @@ public: void Cancel() override { backend_->Cancel(); } + std::string LatestError() const override { + return backend_->LatestError(); + } protected: FileLoader *backend_; From 809c0f3e2c9617c174daa46c5c8d12b4a373f3a5 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Dec 2018 08:16:56 -0800 Subject: [PATCH 263/347] http: Correct typo. Oops, somehow deleted an important character when pushing up. --- ext/native/net/http_client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/native/net/http_client.cpp b/ext/native/net/http_client.cpp index 1954f69ce2..22e5fb9c56 100644 --- a/ext/native/net/http_client.cpp +++ b/ext/native/net/http_client.cpp @@ -292,7 +292,7 @@ int Client::SendRequestWithData(const char *method, const char *resource, const int Client::ReadResponseHeaders(Buffer *readbuf, std::vector &responseHeaders, float *progress) { // Snarf all the data we can into RAM. A little unsafe but hey. - if (dataTimeout_ >= 0.0 && fd_util::WaitUntilReady(sock(), dataTimeout_, false)) { + if (dataTimeout_ >= 0.0 && !fd_util::WaitUntilReady(sock(), dataTimeout_, false)) { ELOG("HTTP headers timed out"); return -1; } From 581cb1a069204c701e22ca7aa771fbf77413e531 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 30 Dec 2018 12:16:33 -0800 Subject: [PATCH 264/347] UI: Check for step debugging on unthrottle. Fixes #11704. --- UI/GamepadEmu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/GamepadEmu.cpp b/UI/GamepadEmu.cpp index d8c5ad0b70..a703616178 100644 --- a/UI/GamepadEmu.cpp +++ b/UI/GamepadEmu.cpp @@ -617,7 +617,7 @@ UI::ViewGroup *CreatePadLayout(float xres, float yres, bool *pause) { if (unthrottle) { unthrottle->SetAngle(180.0f); unthrottle->OnChange.Add([](UI::EventParams &e) { - if (e.a) { + if (e.a && coreState == CORE_STEPPING) { Core_EnableStepping(false); } return UI::EVENT_DONE; From f71c7c5ffb7db6fb5d4e4f2f49c922dc7e1b4c3a Mon Sep 17 00:00:00 2001 From: mygizli04 <42012824+mygizli04@users.noreply.github.com> Date: Tue, 1 Jan 2019 01:22:47 +0400 Subject: [PATCH 265/347] Configure CMake to include the new logo --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 65d7a330e6..e71ed358bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1927,6 +1927,7 @@ set(NativeAssets assets/rargray.png assets/unknown.png assets/zip.png + assets/logo.png ) @@ -2039,6 +2040,7 @@ if(IOS) set_target_properties(${TargetBin} PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/ios/PPSSPP-Info.plist" RESOURCE "ios/Launch Screen.storyboard" + RESOURCE "ios/logo.png" XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET} XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "iPhone/iPad" XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES From cf173db0407457b051d8f06b94905632f8b89bf6 Mon Sep 17 00:00:00 2001 From: mygizli04 <42012824+mygizli04@users.noreply.github.com> Date: Tue, 1 Jan 2019 01:23:48 +0400 Subject: [PATCH 266/347] A new logo file ( I couldn't find a actual logo file, well i'm just including this in case i can't find the actual files ) --- assets/logo.png | Bin 0 -> 428424 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/logo.png diff --git a/assets/logo.png b/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f4ce6bfb240c64e2cbea7d7d46b94bd1328eeb0a GIT binary patch literal 428424 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 literal 0 HcmV?d00001 From 9a210b4dec17189150979ec8505dbe9991213712 Mon Sep 17 00:00:00 2001 From: mygizli04 <42012824+mygizli04@users.noreply.github.com> Date: Tue, 1 Jan 2019 01:24:48 +0400 Subject: [PATCH 267/347] The new Launch Screen ( to include the logo ) --- ios/Launch Screen.storyboard | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/ios/Launch Screen.storyboard b/ios/Launch Screen.storyboard index 5b0377f076..e28834e5c5 100644 --- a/ios/Launch Screen.storyboard +++ b/ios/Launch Screen.storyboard @@ -1,10 +1,10 @@ - + - + @@ -19,6 +19,12 @@ + + + + + + @@ -27,4 +33,7 @@ + + + From bef7b005ddc09206a00d39a5efb2366cbe961ce0 Mon Sep 17 00:00:00 2001 From: mygizli04 <42012824+mygizli04@users.noreply.github.com> Date: Tue, 1 Jan 2019 01:29:22 +0400 Subject: [PATCH 268/347] I don't know why i included it there haha --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e71ed358bb..7a3fa426a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2040,7 +2040,6 @@ if(IOS) set_target_properties(${TargetBin} PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/ios/PPSSPP-Info.plist" RESOURCE "ios/Launch Screen.storyboard" - RESOURCE "ios/logo.png" XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET} XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "iPhone/iPad" XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES From 12e54baebb29ae090fa5b850addfcdda1fef92e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 2 Jan 2019 15:07:18 +0100 Subject: [PATCH 269/347] Update lang submodule --- assets/lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/lang b/assets/lang index f01d2de306..0adba3e390 160000 --- a/assets/lang +++ b/assets/lang @@ -1 +1 @@ -Subproject commit f01d2de306fb645d24550ccb4a4c8f701268e38f +Subproject commit 0adba3e390d12e792bf272519d126113a771d6b1 From 12f295c4a5cf6aa3667d87d2a637f4499cab41db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 3 Jan 2019 12:43:00 +0100 Subject: [PATCH 270/347] GLES: Detect Vivante GPU, disable vertex range culling Should work-around #11703 --- GPU/GLES/GPU_GLES.cpp | 5 ++++- ext/native/gfx_es2/gpu_features.cpp | 2 ++ ext/native/gfx_es2/gpu_features.h | 2 ++ ext/native/thin3d/thin3d.h | 2 ++ ext/native/thin3d/thin3d_gl.cpp | 4 ++++ 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 3a37ba24d8..bb54322f7f 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -147,7 +147,10 @@ void GPU_GLES::CheckGPUFeatures() { u32 features = 0; features |= GPU_SUPPORTS_16BIT_FORMATS; - features |= GPU_SUPPORTS_VS_RANGE_CULLING; + + if (!draw_->GetBugs().Has(Draw::Bugs::BROKEN_NAN_IN_CONDITIONAL)) { + features |= GPU_SUPPORTS_VS_RANGE_CULLING; + } if (gl_extensions.ARB_blend_func_extended || gl_extensions.EXT_blend_func_extended) { if (!g_Config.bVendorBugChecksEnabled || !draw_->GetBugs().Has(Draw::Bugs::DUAL_SOURCE_BLENDING_BROKEN)) { diff --git a/ext/native/gfx_es2/gpu_features.cpp b/ext/native/gfx_es2/gpu_features.cpp index 3c8fb46663..3d81f59287 100644 --- a/ext/native/gfx_es2/gpu_features.cpp +++ b/ext/native/gfx_es2/gpu_features.cpp @@ -159,6 +159,8 @@ void CheckGLExtensions() { } else if (vendor == "Broadcom") { gl_extensions.gpuVendor = GPU_VENDOR_BROADCOM; // Just for reference: Galaxy Y has renderer == "VideoCore IV HW" + } else if (vendor == "Vivante Corporation") { + gl_extensions.gpuVendor = GPU_VENDOR_VIVANTE; } else { gl_extensions.gpuVendor = GPU_VENDOR_UNKNOWN; } diff --git a/ext/native/gfx_es2/gpu_features.h b/ext/native/gfx_es2/gpu_features.h index 80cbc906bd..94ba18912a 100644 --- a/ext/native/gfx_es2/gpu_features.h +++ b/ext/native/gfx_es2/gpu_features.h @@ -15,9 +15,11 @@ enum { GPU_VENDOR_IMGTEC = 5, GPU_VENDOR_QUALCOMM = 6, GPU_VENDOR_BROADCOM = 7, + GPU_VENDOR_VIVANTE = 8, GPU_VENDOR_UNKNOWN = 0, }; +// TODO: Move to Draw::Bugs enum { BUG_FBO_UNUSABLE = 1, BUG_PVR_SHADER_PRECISION_BAD = 2, diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 1d0e28a983..20b96d5f0b 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -234,6 +234,7 @@ enum class GPUVendor { VENDOR_QUALCOMM, VENDOR_IMGTEC, // PowerVR VENDOR_BROADCOM, // Raspberry + VENDOR_VIVANTE, }; enum class NativeObject { @@ -329,6 +330,7 @@ public: DUAL_SOURCE_BLENDING_BROKEN = 1, ANY_MAP_BUFFER_RANGE_SLOW = 2, PVR_GENMIPMAP_HEIGHT_GREATER = 3, + BROKEN_NAN_IN_CONDITIONAL = 4, }; protected: diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index 1d812ce496..872c169aff 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -453,6 +453,7 @@ public: case GPUVendor::VENDOR_QUALCOMM: return "VENDOR_ADRENO"; case GPUVendor::VENDOR_ARM: return "VENDOR_ARM"; case GPUVendor::VENDOR_BROADCOM: return "VENDOR_BROADCOM"; + case GPUVendor::VENDOR_VIVANTE: return "VENDOR_VIVANTE"; case GPUVendor::VENDOR_UNKNOWN: default: return "VENDOR_UNKNOWN"; @@ -545,6 +546,7 @@ OpenGLContext::OpenGLContext() { case GPU_VENDOR_BROADCOM: caps_.vendor = GPUVendor::VENDOR_BROADCOM; break; case GPU_VENDOR_INTEL: caps_.vendor = GPUVendor::VENDOR_INTEL; break; case GPU_VENDOR_IMGTEC: caps_.vendor = GPUVendor::VENDOR_IMGTEC; break; + case GPU_VENDOR_VIVANTE: caps_.vendor = GPUVendor::VENDOR_VIVANTE; break; case GPU_VENDOR_UNKNOWN: default: caps_.vendor = GPUVendor::VENDOR_UNKNOWN; @@ -567,6 +569,8 @@ OpenGLContext::OpenGLContext() { bugs_.Infest(Bugs::DUAL_SOURCE_BLENDING_BROKEN); } } + } else if (caps_.vendor == GPUVendor::VENDOR_VIVANTE) { + bugs_.Infest(Bugs::BROKEN_NAN_IN_CONDITIONAL); } // TODO: Make this check more lenient. Disabled for all right now From e5b75dc294d9a194baec3326fcc332b0a3b7759c Mon Sep 17 00:00:00 2001 From: z2442 Date: Sat, 5 Jan 2019 18:46:38 -0500 Subject: [PATCH 271/347] Added a check to the pointer for memcpy This check enables the newer builds of daedalus to run. --- Core/HLE/sceKernelInterrupt.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Core/HLE/sceKernelInterrupt.cpp b/Core/HLE/sceKernelInterrupt.cpp index 9513d2d019..862e9eeb8d 100644 --- a/Core/HLE/sceKernelInterrupt.cpp +++ b/Core/HLE/sceKernelInterrupt.cpp @@ -684,7 +684,9 @@ const HLEFunction Kernel_Library[] = static u32 sysclib_memcpy(u32 dst, u32 src, u32 size) { ERROR_LOG(SCEKERNEL, "Untested sysclib_memcpy(dest=%08x, src=%08x, size=%i)", dst, src, size); - memcpy(Memory::GetPointer(dst), Memory::GetPointer(src), size); + if (Memory::IsValidRange(dst, size) && Memory::IsValidRange(src, size)) { + memcpy(Memory::GetPointer(dst), Memory::GetPointer(src), size); + } return dst; } From 501ec51c6b6bd7131f45117542a0ebecc867ecc8 Mon Sep 17 00:00:00 2001 From: mygizli04 <42012824+mygizli04@users.noreply.github.com> Date: Sun, 6 Jan 2019 14:06:02 +0400 Subject: [PATCH 272/347] Removing a now unused file. I don't use a premade logo anymore, since 1) It made it look like crap on newer devices 2) It took some space ( I mean it's 418KB but still ) --- assets/logo.png | Bin 428424 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 assets/logo.png diff --git a/assets/logo.png b/assets/logo.png deleted file mode 100644 index f4ce6bfb240c64e2cbea7d7d46b94bd1328eeb0a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 428424 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 From 6dcf95781a65dc6cc4f374a8b36b4fae58ea1b13 Mon Sep 17 00:00:00 2001 From: mygizli04 <42012824+mygizli04@users.noreply.github.com> Date: Sun, 6 Jan 2019 14:12:55 +0400 Subject: [PATCH 273/347] Changing it to import some logo files on the iOS port. I searched EVERYWHERE but couldn't find anything even related to logos or fons.. Well reimporting them has no downside so why not --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a3fa426a1..1187487130 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1927,7 +1927,9 @@ set(NativeAssets assets/rargray.png assets/unknown.png assets/zip.png - assets/logo.png + assets/Roboto-Condensed.tff + source_assets/image/logo.png + source_assets/image/icon_regular_72.png ) From 8596cc11909819b58d9f73eabc96453d5208017f Mon Sep 17 00:00:00 2001 From: mygizli04 <42012824+mygizli04@users.noreply.github.com> Date: Sun, 6 Jan 2019 14:15:18 +0400 Subject: [PATCH 274/347] Removed the premade picture Well this both saves some space ( KB's count right? ) and looks better :P The logo is slightly displaced but it's good enough --- ios/Launch Screen.storyboard | 38 +++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/ios/Launch Screen.storyboard b/ios/Launch Screen.storyboard index e28834e5c5..12ec417b14 100644 --- a/ios/Launch Screen.storyboard +++ b/ios/Launch Screen.storyboard @@ -4,9 +4,15 @@ + + + + Roboto-Condensed + + @@ -20,10 +26,35 @@ - - + + + + + + + + + @@ -34,6 +65,7 @@ - + + From 855df8b5634c9c941fc56e0a5f81d99b63cb211d Mon Sep 17 00:00:00 2001 From: mygizli04 <42012824+mygizli04@users.noreply.github.com> Date: Sun, 6 Jan 2019 14:38:35 +0400 Subject: [PATCH 275/347] Typo --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1187487130..1a1d21d3d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1927,7 +1927,7 @@ set(NativeAssets assets/rargray.png assets/unknown.png assets/zip.png - assets/Roboto-Condensed.tff + assets/Roboto-Condensed.ttf source_assets/image/logo.png source_assets/image/icon_regular_72.png ) From 8a888c57d0c2741768cd66585f04a73515f7bfde Mon Sep 17 00:00:00 2001 From: mygizli04 <42012824+mygizli04@users.noreply.github.com> Date: Sun, 6 Jan 2019 14:42:49 +0400 Subject: [PATCH 276/347] Update Launch Screen.storyboard --- ios/Launch Screen.storyboard | 1 - 1 file changed, 1 deletion(-) diff --git a/ios/Launch Screen.storyboard b/ios/Launch Screen.storyboard index 12ec417b14..513011ac21 100644 --- a/ios/Launch Screen.storyboard +++ b/ios/Launch Screen.storyboard @@ -4,7 +4,6 @@ - From 266dd17c2a05390cb124e44ca3a66c253ce594a0 Mon Sep 17 00:00:00 2001 From: mygizli04 <42012824+mygizli04@users.noreply.github.com> Date: Sun, 6 Jan 2019 15:24:39 +0400 Subject: [PATCH 277/347] Remove the duplicate --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a1d21d3d0..e56611ec09 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1927,7 +1927,6 @@ set(NativeAssets assets/rargray.png assets/unknown.png assets/zip.png - assets/Roboto-Condensed.ttf source_assets/image/logo.png source_assets/image/icon_regular_72.png ) From 79d4b0f5a2e8da753312aa0a48cbf96e85a754e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Jan 2019 13:50:23 +0100 Subject: [PATCH 278/347] Check that allocations in SplineCommon succeed. Attempt at #11660 but not optimistic. --- GPU/Common/SplineCommon.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 0e10a4e8ec..436e7d87c2 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -517,7 +517,16 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic // Simplify away bones and morph before proceeding // There are normally not a lot of control points so just splitting decoded should be reasonably safe, although not great. SimpleVertex *simplified_control_points = (SimpleVertex *)managedBuf.Allocate(sizeof(SimpleVertex) * (index_upper_bound + 1)); + if (!simplified_control_points) { + ERROR_LOG(G3D, "Failed to allocate space for simplified control points, skipping curve draw"); + return; + } + u8 *temp_buffer = managedBuf.Allocate(sizeof(SimpleVertex) * num_points); + if (!temp_buffer) { + ERROR_LOG(G3D, "Failed to allocate space for temp buffer, skipping curve draw"); + return; + } u32 origVertType = vertType; vertType = NormalizeVertices((u8 *)simplified_control_points, temp_buffer, (u8 *)control_points, index_lower_bound, index_upper_bound, vertType); @@ -531,6 +540,10 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic // Make an array of pointers to the control points, to get rid of indices. const SimpleVertex **points = (const SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * num_points); + if (!points) { + ERROR_LOG(G3D, "Failed to allocate space for control point pointers, skipping curve draw"); + return; + } for (int idx = 0; idx < num_points; idx++) points[idx] = simplified_control_points + (indices ? ConvertIndex(idx) : idx); From 5a1fa6008714b96b1506a3f265104a0cfa830b0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 6 Jan 2019 23:46:43 +0100 Subject: [PATCH 279/347] Try to support Qt keyboard input directly. Partially fixes #11653 (nickname crash on mac) --- Qt/QtMain.cpp | 26 +++++++++++++++++++++++++- UI/GameSettingsScreen.cpp | 9 +++++---- ext/native/base/NKCodeFromQt.h | 3 ++- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/Qt/QtMain.cpp b/Qt/QtMain.cpp index ada30411ad..f7937d8547 100644 --- a/Qt/QtMain.cpp +++ b/Qt/QtMain.cpp @@ -31,6 +31,7 @@ #include "gfx_es2/gpu_features.h" #include "math/math_util.h" #include "thread/threadutil.h" +#include "util/text/utf8.h" #include "Core/Config.h" #include "Core/ConfigValues.h" @@ -354,7 +355,30 @@ bool MainUI::event(QEvent *e) NativeKey(KeyInput(DEVICE_ID_MOUSE, ((QWheelEvent*)e)->delta()<0 ? NKCODE_EXT_MOUSEWHEEL_DOWN : NKCODE_EXT_MOUSEWHEEL_UP, KEY_DOWN)); break; case QEvent::KeyPress: - NativeKey(KeyInput(DEVICE_ID_KEYBOARD, KeyMapRawQttoNative.find(((QKeyEvent*)e)->key())->second, KEY_DOWN)); + { + auto qtKeycode = ((QKeyEvent*)e)->key(); + int nativeKeycode = KeyMapRawQttoNative.find(qtKeycode)->second; + NativeKey(KeyInput(DEVICE_ID_KEYBOARD, nativeKeycode, KEY_DOWN)); + // Also get the unicode value. + QString text = ((QKeyEvent*)e)->text(); + std::string str = text.toStdString(); + + // Now, we don't want CHAR events for non-printable characters. Not quite sure how we'll best + // do that, but here's one attempt.... + switch (nativeKeycode) { + case NKCODE_DEL: + case NKCODE_FORWARD_DEL: + case NKCODE_TAB: + break; + default: + if (str.size()) { + int pos = 0; + int code = u8_nextchar(str.c_str(), &pos); + NativeKey(KeyInput(DEVICE_ID_KEYBOARD, code, KEY_CHAR)); + } + break; + } + } break; case QEvent::KeyRelease: NativeKey(KeyInput(DEVICE_ID_KEYBOARD, KeyMapRawQttoNative.find(((QKeyEvent*)e)->key())->second, KEY_UP)); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 37f5451f2f..6f4c284f94 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -643,7 +643,7 @@ void GameSettingsScreen::CreateViews() { networkingSettings->Add(new CheckBox(&g_Config.bEnableWlan, n->T("Enable networking", "Enable networking/wlan (beta)"))); networkingSettings->Add(new CheckBox(&g_Config.bDiscordPresence, n->T("Send Discord Presence information"))); -#if !defined(MOBILE_DEVICE) && !defined(USING_QT_UI) +#if !defined(MOBILE_DEVICE) networkingSettings->Add(new PopupTextInputChoice(&g_Config.proAdhocServer, n->T("Change proAdhocServer Address"), "", 255, screenManager())); #elif defined(__ANDROID__) networkingSettings->Add(new ChoiceWithValueDisplay(&g_Config.proAdhocServer, n->T("Change proAdhocServer Address"), (const char *)nullptr))->OnClick.Handle(this, &GameSettingsScreen::OnChangeproAdhocServerAddress); @@ -801,13 +801,14 @@ void GameSettingsScreen::CreateViews() { systemSettings->Add(new PopupMultiChoice(&g_Config.iPSPModel, sy->T("PSP Model"), models, 0, ARRAY_SIZE(models), sy->GetName(), screenManager()))->SetEnabled(!PSP_IsInited()); // TODO: Come up with a way to display a keyboard for mobile users, // so until then, this is Windows/Desktop only. -#if !defined(MOBILE_DEVICE) && !defined(USING_QT_UI) // TODO: Add all platforms where KEY_CHAR support is added +#if !defined(MOBILE_DEVICE) // TODO: Add all platforms where KEY_CHAR support is added systemSettings->Add(new PopupTextInputChoice(&g_Config.sNickName, sy->T("Change Nickname"), "", 32, screenManager())); -#elif defined(USING_QT_UI) - systemSettings->Add(new Choice(sy->T("Change Nickname")))->OnClick.Handle(this, &GameSettingsScreen::OnChangeNickname); +// #elif defined(USING_QT_UI) +// systemSettings->Add(new Choice(sy->T("Change Nickname")))->OnClick.Handle(this, &GameSettingsScreen::OnChangeNickname); #elif defined(__ANDROID__) systemSettings->Add(new ChoiceWithValueDisplay(&g_Config.sNickName, sy->T("Change Nickname"), (const char *)nullptr))->OnClick.Handle(this, &GameSettingsScreen::OnChangeNickname); #endif + #if defined(_WIN32) || (defined(USING_QT_UI) && !defined(MOBILE_DEVICE)) // Screenshot functionality is not yet available on non-Windows/non-Qt systemSettings->Add(new CheckBox(&g_Config.bScreenshotsAsPNG, sy->T("Screenshots as PNG"))); diff --git a/ext/native/base/NKCodeFromQt.h b/ext/native/base/NKCodeFromQt.h index 1d2dd2cb65..ee09d63417 100644 --- a/ext/native/base/NKCodeFromQt.h +++ b/ext/native/base/NKCodeFromQt.h @@ -98,5 +98,6 @@ static const std::map KeyMapRawQttoNative = InitConstMap (Qt::Key_Up, NKCODE_DPAD_UP) (Qt::Key_Right, NKCODE_DPAD_RIGHT) (Qt::Key_Down, NKCODE_DPAD_DOWN) - (Qt::Key_Back, NKCODE_BACK); + (Qt::Key_Back, NKCODE_BACK) + (Qt::Key_Backspace, NKCODE_DEL); From 5362e675c414f75cfadbc77279b33cd89448e989 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 7 Jan 2019 00:28:57 +0100 Subject: [PATCH 280/347] Address feedback --- Qt/QtMain.cpp | 10 +++++++--- UI/GameSettingsScreen.cpp | 2 -- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Qt/QtMain.cpp b/Qt/QtMain.cpp index f7937d8547..178f3f82c4 100644 --- a/Qt/QtMain.cpp +++ b/Qt/QtMain.cpp @@ -357,12 +357,16 @@ bool MainUI::event(QEvent *e) case QEvent::KeyPress: { auto qtKeycode = ((QKeyEvent*)e)->key(); - int nativeKeycode = KeyMapRawQttoNative.find(qtKeycode)->second; - NativeKey(KeyInput(DEVICE_ID_KEYBOARD, nativeKeycode, KEY_DOWN)); + auto iter = KeyMapRawQttoNative.find(qtKeycode); + int nativeKeycode = 0; + if (iter != KeyMapRawQttoNative.end()) { + nativeKeycode = iter->second; + NativeKey(KeyInput(DEVICE_ID_KEYBOARD, nativeKeycode, KEY_DOWN)); + } + // Also get the unicode value. QString text = ((QKeyEvent*)e)->text(); std::string str = text.toStdString(); - // Now, we don't want CHAR events for non-printable characters. Not quite sure how we'll best // do that, but here's one attempt.... switch (nativeKeycode) { diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 6f4c284f94..0f34bdc50c 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -803,8 +803,6 @@ void GameSettingsScreen::CreateViews() { // so until then, this is Windows/Desktop only. #if !defined(MOBILE_DEVICE) // TODO: Add all platforms where KEY_CHAR support is added systemSettings->Add(new PopupTextInputChoice(&g_Config.sNickName, sy->T("Change Nickname"), "", 32, screenManager())); -// #elif defined(USING_QT_UI) -// systemSettings->Add(new Choice(sy->T("Change Nickname")))->OnClick.Handle(this, &GameSettingsScreen::OnChangeNickname); #elif defined(__ANDROID__) systemSettings->Add(new ChoiceWithValueDisplay(&g_Config.sNickName, sy->T("Change Nickname"), (const char *)nullptr))->OnClick.Handle(this, &GameSettingsScreen::OnChangeNickname); #endif From cb63df2a34d0fb066cce7d7fb92a195bebee9ae6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 8 Jan 2019 12:16:39 +0100 Subject: [PATCH 281/347] Qt: Temporary workaround for #11721 - simply remove the load button (you can still load games from the Games tab) --- UI/MainScreen.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index 6956f95b50..904bcfac7f 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -915,7 +915,8 @@ void MainScreen::CreateViews() { TextView *ver = rightColumnItems->Add(new TextView(versionString, new LinearLayoutParams(Margins(70, -6, 0, 0)))); ver->SetSmall(true); ver->SetClip(false); -#if defined(_WIN32) || defined(USING_QT_UI) +// Temporarily disabled the load button for Qt. See #11721 +#if defined(_WIN32) // || defined(USING_QT_UI) rightColumnItems->Add(new Choice(mm->T("Load","Load...")))->OnClick.Handle(this, &MainScreen::OnLoadFile); #endif rightColumnItems->Add(new Choice(mm->T("Game Settings", "Settings")))->OnClick.Handle(this, &MainScreen::OnGameSettings); From b572dc52a527ab6f0f1b0c19d40ea773a7139432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 8 Jan 2019 12:29:59 +0100 Subject: [PATCH 282/347] Remove usage of deprecated function readdir_r (and ugly Blackberry hack diren_large) --- Common/FileUtil.cpp | 8 +++----- Core/FileSystems/DirectoryFileSystem.cpp | 5 +---- ext/native/file/file_util.cpp | 4 +--- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/Common/FileUtil.cpp b/Common/FileUtil.cpp index 2c699e3581..9cced3871b 100644 --- a/Common/FileUtil.cpp +++ b/Common/FileUtil.cpp @@ -661,13 +661,13 @@ bool DeleteDirRecursively(const std::string &directory) { const std::string virtualName = ConvertWStringToUTF8(ffd.cFileName); #else - struct dirent dirent, *result = NULL; + struct dirent *result = NULL; DIR *dirp = opendir(directory.c_str()); if (!dirp) return false; // non windows loop - while (!readdir_r(dirp, &dirent, &result) && result) + while ((result = readdir(dirp))) { const std::string virtualName = result->d_name; #endif @@ -723,13 +723,11 @@ void CopyDir(const std::string &source_path, const std::string &dest_path) if (!File::Exists(source_path)) return; if (!File::Exists(dest_path)) File::CreateFullPath(dest_path); - struct dirent_large { struct dirent entry; char padding[FILENAME_MAX+1]; }; - struct dirent_large diren; struct dirent *result = NULL; DIR *dirp = opendir(source_path.c_str()); if (!dirp) return; - while (!readdir_r(dirp, (dirent*) &diren, &result) && result) + while ((result = readdir(dirp))) { const std::string virtualName(result->d_name); // check for "." and ".." diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp index 20dc6565c0..40810d1fae 100644 --- a/Core/FileSystems/DirectoryFileSystem.cpp +++ b/Core/FileSystems/DirectoryFileSystem.cpp @@ -66,9 +66,6 @@ static bool FixFilenameCase(const std::string &path, std::string &filename) } //TODO: lookup filename in cache for "path" - - struct dirent_large { struct dirent entry; char padding[FILENAME_MAX+1]; } diren; - struct dirent_large; struct dirent *result = NULL; DIR *dirp = opendir(path.c_str()); @@ -77,7 +74,7 @@ static bool FixFilenameCase(const std::string &path, std::string &filename) bool retValue = false; - while (!readdir_r(dirp, (dirent*) &diren, &result) && result) + while ((result = readdir(dirp))) { if (strlen(result->d_name) != filenameSize) continue; diff --git a/ext/native/file/file_util.cpp b/ext/native/file/file_util.cpp index be654ef9c3..6cf0ae7606 100644 --- a/ext/native/file/file_util.cpp +++ b/ext/native/file/file_util.cpp @@ -238,8 +238,6 @@ size_t getFilesInDir(const char *directory, std::vector *files, const { const std::string virtualName = ConvertWStringToUTF8(ffd.cFileName); #else - struct dirent_large { struct dirent entry; char padding[FILENAME_MAX+1]; }; - struct dirent_large diren; struct dirent *result = NULL; //std::string directoryWithSlash = directory; @@ -250,7 +248,7 @@ size_t getFilesInDir(const char *directory, std::vector *files, const if (!dirp) return 0; // non windows loop - while (!readdir_r(dirp, (dirent*) &diren, &result) && result) + while ((result = readdir(dirp))) { const std::string virtualName(result->d_name); #endif From b86c96261ae051977a2766e047a2cf710fe204bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 15 Jan 2019 23:31:55 +0100 Subject: [PATCH 283/347] Update to latest gradle, update lang submodule. --- android/gradle.properties | 1 - assets/lang | 2 +- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/android/gradle.properties b/android/gradle.properties index d8813c3693..8bd86f6805 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,2 +1 @@ org.gradle.jvmargs=-Xmx1536M -android.enableAapt2=true diff --git a/assets/lang b/assets/lang index 0adba3e390..53dd77fcc6 160000 --- a/assets/lang +++ b/assets/lang @@ -1 +1 @@ -Subproject commit 0adba3e390d12e792bf272519d126113a771d6b1 +Subproject commit 53dd77fcc6d0de85f58a16360d53dcd0afe68da6 diff --git a/build.gradle b/build.gradle index 2b29ba2521..e5bb841343 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.android.tools.build:gradle:3.3.0' } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 95c68256f8..32bb5e0c8d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue May 08 18:23:21 CEST 2018 +#Tue Jan 15 23:30:05 CET 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.8.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip From 1771cea5a34ae4115691f757681b2f885568f7bb Mon Sep 17 00:00:00 2001 From: Cody Tilkins <7494772+tilkinsc@users.noreply.github.com> Date: Wed, 16 Jan 2019 11:39:34 -0500 Subject: [PATCH 284/347] Added " guards to if not exists The reason why I added this is a just-in-case due to the nature that cmd explodes when something isn't set properly... it can start executing code that shouldn't be obtained. I also fixed a minor formatting error --- Windows/build-x86.cmd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Windows/build-x86.cmd b/Windows/build-x86.cmd index 3b6b548c16..f6c1aff8b6 100644 --- a/Windows/build-x86.cmd +++ b/Windows/build-x86.cmd @@ -19,7 +19,7 @@ rem // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. if not defined vs140comntools ( echo "Visual Studio 2015 doesn't appear to be installed properly. Quitting." goto quit - ) else ( +) else ( call "%vs140comntools%\vsvars32.bat" x86_amd64 ) @@ -39,12 +39,12 @@ if not exist %PPSSPP_ROOT%\%RELEASEX86% ( ) call msbuild PPSSPP.sln /t:Clean %DBG_PPSSPP% /m call msbuild PPSSPP.sln /t:Build %DBG_PPSSPP% /m -if not exist %PPSSPP_ROOT%\%DEBUGX86% ( +if not exist "%PPSSPP_ROOT%\%DEBUGX86%" ( echo Debug build failed. goto Quit ) -if not exist %RELEASE_DIR%\\. ( +if not exist "%RELEASE_DIR%\\." ( mkdir %RELEASE_DIR% ) else ( rmdir /S /Q %RELEASE_DIR% From 05f53a0fe3636c8a164e34492ae02a375d29c17a Mon Sep 17 00:00:00 2001 From: Cody Tilkins <7494772+tilkinsc@users.noreply.github.com> Date: Wed, 16 Jan 2019 11:41:01 -0500 Subject: [PATCH 285/347] Update build-x64.cmd --- Windows/build-x64.cmd | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Windows/build-x64.cmd b/Windows/build-x64.cmd index 97c80e5cc4..83dfcb80bd 100644 --- a/Windows/build-x64.cmd +++ b/Windows/build-x64.cmd @@ -19,7 +19,7 @@ rem // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. if not defined vs140comntools ( echo "Visual Studio 2015 doesn't appear to be installed properly. Quitting." goto quit - ) else ( +) else ( call "%vs140comntools%\vsvars32.bat" x86_amd64 ) @@ -33,18 +33,18 @@ set DBG_PPSSPP=/m /p:Configuration=Debug;Platform=x64 call msbuild PPSSPP.sln /t:Clean %RLS_PPSSPP% call msbuild PPSSPP.sln /t:Build %RLS_PPSSPP% -if not exist %PPSSPP_ROOT%\%RELEASEX64% ( +if not exist "%PPSSPP_ROOT%\%RELEASEX64%" ( echo Release build failed. goto Quit ) call msbuild PPSSPP.sln /t:Clean %DBG_PPSSPP% /m call msbuild PPSSPP.sln /t:Build %DBG_PPSSPP% /m -if not exist %PPSSPP_ROOT%\%DEBUGX64% ( +if not exist "%PPSSPP_ROOT%\%DEBUGX64%" ( echo Debug build failed. goto Quit ) -if not exist %RELEASE_DIR%\\. ( +if not exist "%RELEASE_DIR%\\." ( mkdir %RELEASE_DIR% ) else ( rmdir /S /Q %RELEASE_DIR% From ac8d1deebdfb9a3ca95b25e3ed58a87c8174739e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 22 Jan 2019 08:37:30 +0100 Subject: [PATCH 286/347] Update armips submodule with bugfix. Also lang. --- assets/lang | 2 +- ext/armips | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/lang b/assets/lang index 53dd77fcc6..4238fedf68 160000 --- a/assets/lang +++ b/assets/lang @@ -1 +1 @@ -Subproject commit 53dd77fcc6d0de85f58a16360d53dcd0afe68da6 +Subproject commit 4238fedf686fb868bbe8d32ec009260e4ecc1e09 diff --git a/ext/armips b/ext/armips index 9efe336728..7885552b20 160000 --- a/ext/armips +++ b/ext/armips @@ -1 +1 @@ -Subproject commit 9efe3367284d2d1eeb14fc302a2c12c36e3e255e +Subproject commit 7885552b208493a6a0f21663770c446c3ba65576 From f9c37cce56e2d14010ff96ebe0b53a1936c46720 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 22 Jan 2019 21:21:59 +0100 Subject: [PATCH 287/347] Fix for weird Xbox B button behavior, see #10948. A simpler change was tested to work by Ruler. --- UWP/App.cpp | 13 +++++++++---- UWP/App.h | 3 ++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/UWP/App.cpp b/UWP/App.cpp index 5950a5ada2..124905478f 100644 --- a/UWP/App.cpp +++ b/UWP/App.cpp @@ -1,4 +1,4 @@ -#include "ppsspp_config.h" +#include "ppsspp_config.h" #include "pch.h" #include "App.h" @@ -92,6 +92,7 @@ void App::SetWindow(CoreWindow^ window) { if (Windows::Foundation::Metadata::ApiInformation::IsTypePresent("Windows.Phone.UI.Input.HardwareButtons")) { m_hardwareButtons.insert(HardwareButton::BACK); + m_isPhone = true; } Windows::UI::Core::SystemNavigationManager::GetForCurrentView()-> @@ -103,11 +104,15 @@ void App::SetWindow(CoreWindow^ window) { } bool App::HasBackButton() { - return m_hardwareButtons.find(HardwareButton::BACK) != m_hardwareButtons.end(); + return m_isPhone; } void App::App_BackRequested(Platform::Object^ sender, Windows::UI::Core::BackRequestedEventArgs^ e) { - e->Handled = m_main->OnHardwareButton(HardwareButton::BACK); + if (m_isPhone) { + e->Handled = m_main->OnHardwareButton(HardwareButton::BACK); + } else { + e->Handled = true; + } } void App::OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args) { @@ -262,4 +267,4 @@ void App::OnOrientationChanged(DisplayInformation^ sender, Object^ args) { void App::OnDisplayContentsInvalidated(DisplayInformation^ sender, Object^ args) { m_deviceResources->ValidateDevice(); -} \ No newline at end of file +} diff --git a/UWP/App.h b/UWP/App.h index d329ac2c20..bd1fd0b331 100644 --- a/UWP/App.h +++ b/UWP/App.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include @@ -102,6 +102,7 @@ namespace UWP { bool m_windowClosed; bool m_windowVisible; + bool m_isPhone = false; TouchMapper touchMap_; }; } From c8e5dd325a4c2dac3652b4c72298dfbbb8b42a10 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Wed, 23 Jan 2019 10:27:01 +0100 Subject: [PATCH 288/347] VK device allocator: Support separate memory type per slab. --- Common/Vulkan/VulkanMemory.cpp | 16 +++++++--------- Common/Vulkan/VulkanMemory.h | 4 ++-- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Common/Vulkan/VulkanMemory.cpp b/Common/Vulkan/VulkanMemory.cpp index a6457af0b2..3d2c7dcf3c 100644 --- a/Common/Vulkan/VulkanMemory.cpp +++ b/Common/Vulkan/VulkanMemory.cpp @@ -195,12 +195,6 @@ size_t VulkanDeviceAllocator::Allocate(const VkMemoryRequirements &reqs, VkDevic if (!pass) { return ALLOCATE_FAILED; } - if (memoryTypeIndex_ == UNDEFINED_MEMORY_TYPE) { - memoryTypeIndex_ = memoryTypeIndex; - } else if (memoryTypeIndex_ != memoryTypeIndex) { - assert(memoryTypeIndex_ == memoryTypeIndex); - return ALLOCATE_FAILED; - } size_t size = reqs.size; @@ -213,6 +207,8 @@ size_t VulkanDeviceAllocator::Allocate(const VkMemoryRequirements &reqs, VkDevic // This helps us "creep forward", and also spend less time allocating. const size_t actualSlab = (lastSlab_ + i) % numSlabs; Slab &slab = slabs_[actualSlab]; + if (slab.memoryTypeIndex != memoryTypeIndex) + continue; size_t start = slab.nextFree; while (start < slab.usage.size()) { @@ -227,7 +223,7 @@ size_t VulkanDeviceAllocator::Allocate(const VkMemoryRequirements &reqs, VkDevic } // Okay, we couldn't fit it into any existing slabs. We need a new one. - if (!AllocateSlab(size)) { + if (!AllocateSlab(size, memoryTypeIndex)) { return ALLOCATE_FAILED; } @@ -401,16 +397,17 @@ void VulkanDeviceAllocator::ExecuteFree(FreeInfo *userdata) { delete userdata; } -bool VulkanDeviceAllocator::AllocateSlab(VkDeviceSize minBytes) { +bool VulkanDeviceAllocator::AllocateSlab(VkDeviceSize minBytes, int memoryTypeIndex) { assert(!destroyed_); if (!slabs_.empty() && minSlabSize_ < maxSlabSize_) { // We're allocating an additional slab, so rachet up its size. + // TODO: Maybe should not do this when we are allocating a new slab due to memoryTypeIndex not matching? minSlabSize_ <<= 1; } VkMemoryAllocateInfo alloc{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; alloc.allocationSize = minSlabSize_; - alloc.memoryTypeIndex = memoryTypeIndex_; + alloc.memoryTypeIndex = memoryTypeIndex; while (alloc.allocationSize < minBytes) { alloc.allocationSize <<= 1; @@ -427,6 +424,7 @@ bool VulkanDeviceAllocator::AllocateSlab(VkDeviceSize minBytes) { slabs_.resize(slabs_.size() + 1); Slab &slab = slabs_[slabs_.size() - 1]; + slab.memoryTypeIndex = memoryTypeIndex; slab.deviceMemory = deviceMemory; slab.usage.resize((size_t)(alloc.allocationSize >> SLAB_GRAIN_SHIFT)); diff --git a/Common/Vulkan/VulkanMemory.h b/Common/Vulkan/VulkanMemory.h index 05d892cd1b..ef14de80ed 100644 --- a/Common/Vulkan/VulkanMemory.h +++ b/Common/Vulkan/VulkanMemory.h @@ -174,6 +174,7 @@ private: struct Slab { VkDeviceMemory deviceMemory; + uint32_t memoryTypeIndex = UNDEFINED_MEMORY_TYPE; std::vector usage; std::unordered_map allocSizes; std::unordered_map tags; @@ -200,7 +201,7 @@ private: freeInfo->allocator->ExecuteFree(freeInfo); // this deletes freeInfo } - bool AllocateSlab(VkDeviceSize minBytes); + bool AllocateSlab(VkDeviceSize minBytes, int memoryTypeIndex); bool AllocateFromSlab(Slab &slab, size_t &start, size_t blocks, const std::string &tag); void Decimate(); void DoTouch(VkDeviceMemory deviceMemory, size_t offset); @@ -212,6 +213,5 @@ private: size_t lastSlab_ = 0; size_t minSlabSize_; const size_t maxSlabSize_; - uint32_t memoryTypeIndex_ = UNDEFINED_MEMORY_TYPE; bool destroyed_ = false; }; From 46585a5da9a276499e78afdcf5d6ced311eef86d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 23 Jan 2019 18:34:25 +0100 Subject: [PATCH 289/347] Additional logging --- Common/Vulkan/VulkanContext.cpp | 8 ++++++++ Common/Vulkan/VulkanImage.cpp | 6 ++++++ Common/Vulkan/VulkanMemory.cpp | 2 +- android/jni/AndroidVulkanContext.cpp | 1 + 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index aeb29f20ea..d222576e5e 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -507,6 +507,14 @@ void VulkanContext::ChooseDevice(int physical_device) { // This is as good a place as any to do this vkGetPhysicalDeviceMemoryProperties(physical_devices_[physical_device_], &memory_properties); + ILOG("Memory Types (%d):", memory_properties.memoryTypeCount); + for (int i = 0; i < memory_properties.memoryTypeCount; i++) { + ILOG(" %d: Heap %d; Flags: %s%s%s%s ", i, memory_properties.memoryTypes[i].heapIndex, + (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) ? "DEVICE_LOCAL_BIT" : "", + (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ? "HOST_VISIBLE_BIT" : "", + (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) ? "HOST_CACHED_BIT" : "", + (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) ? "HOST_COHERENT_BIT" : ""); + } // Optional features vkGetPhysicalDeviceFeatures(physical_devices_[physical_device_], &featuresAvailable_); diff --git a/Common/Vulkan/VulkanImage.cpp b/Common/Vulkan/VulkanImage.cpp index 4528e4b375..1db379e2ab 100644 --- a/Common/Vulkan/VulkanImage.cpp +++ b/Common/Vulkan/VulkanImage.cpp @@ -67,6 +67,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &image_); if (res != VK_SUCCESS) { _assert_(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS); + ELOG("vkCreateImage failed: %s", VulkanResultToString(res)); return false; } @@ -76,6 +77,8 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, if (allocator_) { offset_ = allocator_->Allocate(mem_reqs, &mem_, Tag()); if (offset_ == VulkanDeviceAllocator::ALLOCATE_FAILED) { + vkDestroyImage(vulkan_->GetDevice(), image_, nullptr); + ELOG("Image memory allocation failed (mem_reqs.size = %d)", (int)mem_reqs.size); return false; } } else { @@ -89,6 +92,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, res = vkAllocateMemory(vulkan_->GetDevice(), &mem_alloc, NULL, &mem_); if (res != VK_SUCCESS) { + ELOG("vkAllocateMemory failed: %s", VulkanResultToString(res)); _assert_msg_(G3D, res != VK_ERROR_TOO_MANY_OBJECTS, "Too many Vulkan memory objects!"); _assert_(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS); vkDestroyImage(vulkan_->GetDevice(), image_, nullptr); @@ -101,6 +105,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, res = vkBindImageMemory(vulkan_->GetDevice(), image_, mem_, offset_); if (res != VK_SUCCESS) { + ELOG("vkBindImageMemory failed: %s", VulkanResultToString(res)); // This leaks the image and memory. Should not really happen though... _assert_(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS); return false; @@ -144,6 +149,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view_); if (res != VK_SUCCESS) { + ELOG("vkCreateImageView failed: %s", VulkanResultToString(res)); // This leaks the image. _assert_(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS); return false; diff --git a/Common/Vulkan/VulkanMemory.cpp b/Common/Vulkan/VulkanMemory.cpp index 3d2c7dcf3c..2b13be2e01 100644 --- a/Common/Vulkan/VulkanMemory.cpp +++ b/Common/Vulkan/VulkanMemory.cpp @@ -191,8 +191,8 @@ size_t VulkanDeviceAllocator::Allocate(const VkMemoryRequirements &reqs, VkDevic assert(!destroyed_); uint32_t memoryTypeIndex; bool pass = vulkan_->MemoryTypeFromProperties(reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memoryTypeIndex); - assert(pass); if (!pass) { + ELOG("Failed to pick an appropriate memory type (req: %08x)", reqs.memoryTypeBits); return ALLOCATE_FAILED; } diff --git a/android/jni/AndroidVulkanContext.cpp b/android/jni/AndroidVulkanContext.cpp index 0e597e0a7e..776d553066 100644 --- a/android/jni/AndroidVulkanContext.cpp +++ b/android/jni/AndroidVulkanContext.cpp @@ -130,6 +130,7 @@ bool AndroidVulkanContext::InitAPI() { g_Vulkan = nullptr; return false; } + ILOG("Vulkan device created!"); return true; } From 99c2440d1465c0c7ce5c004539ce1fba804e4876 Mon Sep 17 00:00:00 2001 From: Conn O'Griofa Date: Fri, 25 Jan 2019 15:38:03 +0000 Subject: [PATCH 290/347] CMakeLists: fix EGL detection for ARM devices ARM macro has been renamed to ARM_DEVICE; fixes Raspberry Pi builds. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e56611ec09..10fb061423 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,7 +66,7 @@ if(MINGW AND NOT DEFINED USE_SYSTEM_FFMPEG) endif() if(NOT ANDROID AND NOT IOS) - if(ARM OR SIMULATOR) + if(ARM_DEVICE OR SIMULATOR) set(USING_EGL ON) endif() endif() From add5e3c1fa275a54ceab2fd6d11223e073321f69 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 25 Jan 2019 15:12:01 +0100 Subject: [PATCH 291/347] DeleteDirRecursively: Don't leak the find handle on failure (win32) Don't close invalid handles. --- Common/FileUtil.cpp | 19 +++++++++---------- ext/native/file/file_util.cpp | 1 - 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Common/FileUtil.cpp b/Common/FileUtil.cpp index 9cced3871b..c6fbd73eff 100644 --- a/Common/FileUtil.cpp +++ b/Common/FileUtil.cpp @@ -652,7 +652,6 @@ bool DeleteDirRecursively(const std::string &directory) if (hFind == INVALID_HANDLE_VALUE) { - FindClose(hFind); return false; } @@ -671,7 +670,6 @@ bool DeleteDirRecursively(const std::string &directory) { const std::string virtualName = result->d_name; #endif - // check for "." and ".." if (((virtualName[0] == '.') && (virtualName[1] == '\0')) || ((virtualName[0] == '.') && (virtualName[1] == '.') && @@ -683,10 +681,11 @@ bool DeleteDirRecursively(const std::string &directory) { if (!DeleteDirRecursively(newPath)) { - #ifndef _WIN32 +#ifndef _WIN32 closedir(dirp); - #endif - +#else + FindClose(hFind); +#endif return false; } } @@ -694,10 +693,11 @@ bool DeleteDirRecursively(const std::string &directory) { if (!File::Delete(newPath)) { - #ifndef _WIN32 +#ifndef _WIN32 closedir(dirp); - #endif - +#else + FindClose(hFind); +#endif return false; } } @@ -709,8 +709,7 @@ bool DeleteDirRecursively(const std::string &directory) } closedir(dirp); #endif - File::DeleteDir(directory); - return true; + return File::DeleteDir(directory); #endif } diff --git a/ext/native/file/file_util.cpp b/ext/native/file/file_util.cpp index 6cf0ae7606..0882213e9b 100644 --- a/ext/native/file/file_util.cpp +++ b/ext/native/file/file_util.cpp @@ -230,7 +230,6 @@ size_t getFilesInDir(const char *directory, std::vector *files, const WIN32_FIND_DATA ffd; HANDLE hFind = FindFirstFileEx((ConvertUTF8ToWString(directory) + L"\\*").c_str(), FindExInfoStandard, &ffd, FindExSearchNameMatch, NULL, 0); if (hFind == INVALID_HANDLE_VALUE) { - FindClose(hFind); return 0; } // windows loop From c38c5469c4151bc29df7af299a085f471f0882b4 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 25 Jan 2019 10:44:50 +0100 Subject: [PATCH 292/347] Fixes for issues found by Vulkan validation layers, including a common non-harmful perf warning (doesn't fix all cases, but does fix the most common one). --- Common/Vulkan/VulkanContext.cpp | 4 +++- Common/Vulkan/VulkanDebug.cpp | 2 -- GPU/Vulkan/PipelineManagerVulkan.cpp | 9 ++++++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index d222576e5e..f0296bc694 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -585,7 +585,9 @@ VkResult VulkanContext::CreateDevice() { } assert(found); - deviceExtensionsLookup_.DEDICATED_ALLOCATION = EnableDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); + if (EnableDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME)) { + deviceExtensionsLookup_.DEDICATED_ALLOCATION = EnableDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); + } VkDeviceCreateInfo device_info{ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; device_info.queueCreateInfoCount = 1; diff --git a/Common/Vulkan/VulkanDebug.cpp b/Common/Vulkan/VulkanDebug.cpp index e0d945df38..0ee407b735 100644 --- a/Common/Vulkan/VulkanDebug.cpp +++ b/Common/Vulkan/VulkanDebug.cpp @@ -79,8 +79,6 @@ VkBool32 VKAPI_CALL Vulkan_Dbg(VkDebugReportFlagsEXT msgFlags, VkDebugReportObje return false; if (msgCode == 5) return false; // Not exactly a false positive, see https://github.com/KhronosGroup/glslang/issues/1418 - if (msgCode == 0 && strstr(pMsg, "vertexPipelineStoresAndAtomics")) // https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/73 - return false; #ifdef _WIN32 std::string msg = message.str(); OutputDebugStringA(msg.c_str()); diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 837aec7ffe..6141c87b11 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -112,12 +112,14 @@ static int SetupVertexAttribs(VkVertexInputAttributeDescription attrs[], const D return count; } -static int SetupVertexAttribsPretransformed(VkVertexInputAttributeDescription attrs[]) { +static int SetupVertexAttribsPretransformed(VkVertexInputAttributeDescription attrs[], bool needsColor1) { int count = 0; VertexAttribSetup(&attrs[count++], DEC_FLOAT_4, 0, PspAttributeLocation::POSITION); VertexAttribSetup(&attrs[count++], DEC_FLOAT_3, 16, PspAttributeLocation::TEXCOORD); VertexAttribSetup(&attrs[count++], DEC_U8_4, 28, PspAttributeLocation::COLOR0); - VertexAttribSetup(&attrs[count++], DEC_U8_4, 32, PspAttributeLocation::COLOR1); + if (needsColor1) { + VertexAttribSetup(&attrs[count++], DEC_U8_4, 32, PspAttributeLocation::COLOR1); + } return count; } @@ -243,7 +245,8 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip attributeCount = SetupVertexAttribs(attrs, *decFmt); vertexStride = decFmt->stride; } else { - attributeCount = SetupVertexAttribsPretransformed(attrs); + bool needsColor1 = vs->GetID().Bit(FS_BIT_LMODE); + attributeCount = SetupVertexAttribsPretransformed(attrs, needsColor1); vertexStride = 36; } From 3fd216ad3abcdc223c5f4931f083f413df188c21 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 25 Jan 2019 12:49:18 +0100 Subject: [PATCH 293/347] Better handling of swap chain size, add PowerVR hack. Fixes #11743 --- Common/Vulkan/VulkanContext.cpp | 86 ++++++++++++---------------- Common/Vulkan/VulkanContext.h | 15 ++--- android/jni/AndroidVulkanContext.cpp | 12 +--- 3 files changed, 47 insertions(+), 66 deletions(-) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index f0296bc694..b51649592b 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -508,7 +508,7 @@ void VulkanContext::ChooseDevice(int physical_device) { // This is as good a place as any to do this vkGetPhysicalDeviceMemoryProperties(physical_devices_[physical_device_], &memory_properties); ILOG("Memory Types (%d):", memory_properties.memoryTypeCount); - for (int i = 0; i < memory_properties.memoryTypeCount; i++) { + for (int i = 0; i < (int)memory_properties.memoryTypeCount; i++) { ILOG(" %d: Heap %d; Flags: %s%s%s%s ", i, memory_properties.memoryTypes[i].heapIndex, (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) ? "DEVICE_LOCAL_BIT" : "", (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ? "HOST_VISIBLE_BIT" : "", @@ -644,43 +644,30 @@ void VulkanContext::DestroyDebugMsgCallback() { } } -void VulkanContext::InitSurface(WindowSystem winsys, void *data1, void *data2, int width, int height) { +VkResult VulkanContext::InitSurface(WindowSystem winsys, void *data1, void *data2) { winsys_ = winsys; winsysData1_ = data1; winsysData2_ = data2; - ReinitSurface(width, height); + return ReinitSurface(); } -void VulkanContext::ReinitSurface(int width, int height) { +VkResult VulkanContext::ReinitSurface() { if (surface_ != VK_NULL_HANDLE) { - ILOG("Destroying Vulkan surface (%d, %d)", width_, height_); + ILOG("Destroying Vulkan surface (%d, %d)", swapChainExtent_.width, swapChainExtent_.height); vkDestroySurfaceKHR(instance_, surface_, nullptr); surface_ = VK_NULL_HANDLE; } - ILOG("Creating Vulkan surface (%d, %d)", width, height); + ILOG("Creating Vulkan surface for window"); switch (winsys_) { #ifdef _WIN32 case WINDOWSYSTEM_WIN32: { - HINSTANCE connection = (HINSTANCE)winsysData1_; - HWND window = (HWND)winsysData2_; - - if (width < 0 || height < 0) - { - RECT rc; - GetClientRect(window, &rc); - width = rc.right - rc.left; - height = rc.bottom - rc.top; - } - VkWin32SurfaceCreateInfoKHR win32{ VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR }; win32.flags = 0; - win32.hwnd = window; - win32.hinstance = connection; - VkResult res = vkCreateWin32SurfaceKHR(instance_, &win32, nullptr, &surface_); - assert(res == VK_SUCCESS); - break; + win32.hwnd = (HWND)winsysData2_; + win32.hinstance = (HINSTANCE)winsysData1_; + return vkCreateWin32SurfaceKHR(instance_, &win32, nullptr, &surface_); } #endif #if defined(__ANDROID__) @@ -690,9 +677,7 @@ void VulkanContext::ReinitSurface(int width, int height) { VkAndroidSurfaceCreateInfoKHR android{ VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR }; android.flags = 0; android.window = wnd; - VkResult res = vkCreateAndroidSurfaceKHR(instance_, &android, nullptr, &surface_); - assert(res == VK_SUCCESS); - break; + return vkCreateAndroidSurfaceKHR(instance_, &android, nullptr, &surface_); } #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) @@ -702,9 +687,7 @@ void VulkanContext::ReinitSurface(int width, int height) { xlib.flags = 0; xlib.dpy = (Display *)winsysData1_; xlib.window = (Window)winsysData2_; - VkResult res = vkCreateXlibSurfaceKHR(instance_, &xlib, nullptr, &surface_); - assert(res == VK_SUCCESS); - break; + return vkCreateXlibSurfaceKHR(instance_, &xlib, nullptr, &surface_); } #endif #if defined(VK_USE_PLATFORM_XCB_KHR) @@ -714,9 +697,7 @@ void VulkanContext::ReinitSurface(int width, int height) { xcb.flags = 0; xcb.connection = (Connection *)winsysData1_; xcb.window = (Window)(uintptr_t)winsysData2_; - VkResult res = vkCreateXcbSurfaceKHR(instance_, &xcb, nullptr, &surface_); - assert(res == VK_SUCCESS); - break; + return vkCreateXcbSurfaceKHR(instance_, &xcb, nullptr, &surface_); } #endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) @@ -726,18 +707,14 @@ void VulkanContext::ReinitSurface(int width, int height) { wayland.flags = 0; wayland.display = (wl_display *)winsysData1_; wayland.surface = (wl_surface *)winsysData2_; - VkResult res = vkCreateWaylandSurfaceKHR(instance_, &wayland, nullptr, &surface_); - assert(res == VK_SUCCESS); - break; + return vkCreateWaylandSurfaceKHR(instance_, &wayland, nullptr, &surface_); } #endif default: _assert_msg_(G3D, false, "Vulkan support for chosen window system not implemented"); - break; + return VK_ERROR_INITIALIZATION_FAILED; } - width_ = width; - height_ = height; } bool VulkanContext::InitQueue() { @@ -828,6 +805,14 @@ bool VulkanContext::InitQueue() { return true; } +int clamp(int x, int a, int b) { + if (x < a) + return a; + if (x > b) + return b; + return x; +} + bool VulkanContext::InitSwapchain() { VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_devices_[physical_device_], surface_, &surfCapabilities_); assert(res == VK_SUCCESS); @@ -839,19 +824,20 @@ bool VulkanContext::InitSwapchain() { res = vkGetPhysicalDeviceSurfacePresentModesKHR(physical_devices_[physical_device_], surface_, &presentModeCount, presentModes); assert(res == VK_SUCCESS); - VkExtent2D swapChainExtent; - // width and height are either both -1, or both not -1. - if (surfCapabilities_.currentExtent.width == (uint32_t)-1) { - // If the surface size is undefined, the size is set to - // the size of the images requested. - ILOG("initSwapchain: %dx%d", width_, height_); - swapChainExtent.width = width_; - swapChainExtent.height = height_; - } else { - // If the surface size is defined, the swap chain size must match - swapChainExtent = surfCapabilities_.currentExtent; + ILOG("surfCapabilities_.currentExtent: %dx%d", surfCapabilities_.currentExtent.width, surfCapabilities_.currentExtent.height); + ILOG("surfCapabilities_.minImageExtent: %dx%d", surfCapabilities_.minImageExtent.width, surfCapabilities_.minImageExtent.height); + ILOG("surfCapabilities_.maxImageExtent: %dx%d", surfCapabilities_.maxImageExtent.width, surfCapabilities_.maxImageExtent.height); + + swapChainExtent_.width = clamp(surfCapabilities_.currentExtent.width, surfCapabilities_.minImageExtent.width, surfCapabilities_.maxImageExtent.width); + swapChainExtent_.height = clamp(surfCapabilities_.currentExtent.height, surfCapabilities_.minImageExtent.height, surfCapabilities_.maxImageExtent.height); + + if (physicalDeviceProperties_[physical_device_].vendorID == VULKAN_VENDOR_IMGTEC) { + // Swap chain width hack to avoid issue #11743 (PowerVR driver bug). + swapChainExtent_.width &= ~31; } + ILOG("swapChainExtent: %dx%d", swapChainExtent_.width, swapChainExtent_.height); + // TODO: Find a better way to specify the prioritized present mode while being able // to fall back in a sensible way. VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR; @@ -906,8 +892,8 @@ bool VulkanContext::InitSwapchain() { swap_chain_info.minImageCount = desiredNumberOfSwapChainImages; swap_chain_info.imageFormat = swapchainFormat_; swap_chain_info.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; - swap_chain_info.imageExtent.width = swapChainExtent.width; - swap_chain_info.imageExtent.height = swapChainExtent.height; + swap_chain_info.imageExtent.width = swapChainExtent_.width; + swap_chain_info.imageExtent.height = swapChainExtent_.height; swap_chain_info.preTransform = preTransform; swap_chain_info.imageArrayLayers = 1; swap_chain_info.presentMode = swapchainPresentMode; diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index e58824cd26..9cd169a71c 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -142,8 +142,9 @@ public: VulkanDeleteList &Delete() { return globalDeleteList_; } // The parameters are whatever the chosen window system wants. - void InitSurface(WindowSystem winsys, void *data1, void *data2, int width = -1, int height = -1); - void ReinitSurface(int width = -1, int height = -1); + // The extents will be automatically determined. + VkResult InitSurface(WindowSystem winsys, void *data1, void *data2); + VkResult ReinitSurface(); bool InitQueue(); bool InitObjects(); @@ -160,8 +161,8 @@ public: VkFence CreateFence(bool presignalled); bool CreateShaderModule(const std::vector &spirv, VkShaderModule *shaderModule); - int GetBackbufferWidth() { return width_; } - int GetBackbufferHeight() { return height_; } + int GetBackbufferWidth() { return (int)swapChainExtent_.width; } + int GetBackbufferHeight() { return (int)swapChainExtent_.height; } void BeginFrame(); void EndFrame(); @@ -295,9 +296,9 @@ private: // Custom collection of things that are good to know VulkanPhysicalDeviceInfo deviceInfo_{}; - // Swap chain - int width_ = 0; - int height_ = 0; + // Swap chain extent + VkExtent2D swapChainExtent_{}; + int flags_ = 0; int inflightFrames_ = MAX_INFLIGHT_FRAMES; diff --git a/android/jni/AndroidVulkanContext.cpp b/android/jni/AndroidVulkanContext.cpp index 776d553066..78b1211b10 100644 --- a/android/jni/AndroidVulkanContext.cpp +++ b/android/jni/AndroidVulkanContext.cpp @@ -135,14 +135,8 @@ bool AndroidVulkanContext::InitAPI() { } bool AndroidVulkanContext::InitFromRenderThread(ANativeWindow *wnd, int desiredBackbufferSizeX, int desiredBackbufferSizeY, int backbufferFormat, int androidVersion) { - int width = desiredBackbufferSizeX; - int height = desiredBackbufferSizeY; - if (!width || !height) { - width = pixel_xres; - height = pixel_yres; - } - ILOG("InitSurfaceAndroid: width=%d height=%d", width, height); - g_Vulkan->InitSurface(WINDOWSYSTEM_ANDROID, (void *)wnd, nullptr, width, height); + ILOG("InitSurfaceAndroid: desiredwidth=%d desiredheight=%d", desiredBackbufferSizeX, desiredBackbufferSizeY); + g_Vulkan->InitSurface(WINDOWSYSTEM_ANDROID, (void *)wnd, nullptr); if (g_validate_) { int bits = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; g_Vulkan->InitDebugMsgCallback(&Vulkan_Dbg, bits, &g_LogOptions); @@ -205,7 +199,7 @@ void AndroidVulkanContext::Resize() { g_Vulkan->DestroyObjects(); // backbufferResize updated these values. TODO: Notify another way? - g_Vulkan->ReinitSurface(pixel_xres, pixel_yres); + g_Vulkan->ReinitSurface(); g_Vulkan->InitObjects(); draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); ILOG("AndroidVulkanContext::Resize end (%d, %d)", g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); From 7ccf23542de31aa2b2b6e1c09fc595ed44afb0fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 26 Jan 2019 12:03:20 +0100 Subject: [PATCH 294/347] Fix SDL build --- Common/Vulkan/VulkanContext.cpp | 13 ++++++++----- SDL/SDLVulkanGraphicsContext.cpp | 7 +++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index b51649592b..9df43d902b 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -505,15 +505,18 @@ void VulkanContext::ChooseDevice(int physical_device) { ELOG("Could not find a usable depth stencil format."); } - // This is as good a place as any to do this + // This is as good a place as any to do this. vkGetPhysicalDeviceMemoryProperties(physical_devices_[physical_device_], &memory_properties); ILOG("Memory Types (%d):", memory_properties.memoryTypeCount); for (int i = 0; i < (int)memory_properties.memoryTypeCount; i++) { + // Don't bother printing dummy memory types. + if (!memory_properties.memoryTypes[i].propertyFlags) + continue; ILOG(" %d: Heap %d; Flags: %s%s%s%s ", i, memory_properties.memoryTypes[i].heapIndex, - (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) ? "DEVICE_LOCAL_BIT" : "", - (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ? "HOST_VISIBLE_BIT" : "", - (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) ? "HOST_CACHED_BIT" : "", - (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) ? "HOST_COHERENT_BIT" : ""); + (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) ? "DEVICE_LOCAL " : "", + (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ? "HOST_VISIBLE " : "", + (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) ? "HOST_CACHED " : "", + (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) ? "HOST_COHERENT " : ""); } // Optional features diff --git a/SDL/SDLVulkanGraphicsContext.cpp b/SDL/SDLVulkanGraphicsContext.cpp index a29d41ac3e..123c016ef7 100644 --- a/SDL/SDLVulkanGraphicsContext.cpp +++ b/SDL/SDLVulkanGraphicsContext.cpp @@ -63,16 +63,15 @@ bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, case SDL_SYSWM_X11: #if defined(VK_USE_PLATFORM_XLIB_KHR) vulkan_->InitSurface(WINDOWSYSTEM_XLIB, (void*)sys_info.info.x11.display, - (void *)(intptr_t)sys_info.info.x11.window, pixel_xres, pixel_yres); + (void *)(intptr_t)sys_info.info.x11.window); #elif defined(VK_USE_PLATFORM_XCB_KHR) vulkan_->InitSurface(WINDOWSYSTEM_XCB, (void*)XGetXCBConnection(sys_info.info.x11.display), - (void *)(intptr_t)sys_info.info.x11.window, pixel_xres, pixel_yres); + (void *)(intptr_t)sys_info.info.x11.window); #endif break; #if defined(VK_USE_PLATFORM_WAYLAND_KHR) case SDL_SYSWM_WAYLAND: - vulkan_->InitSurface(WINDOWSYSTEM_WAYLAND, (void*)sys_info.info.wl.display, - (void *)sys_info.info.wl.surface, pixel_xres, pixel_yres); + vulkan_->InitSurface(WINDOWSYSTEM_WAYLAND, (void*)sys_info.info.wl.display, (void *)sys_info.info.wl.surface); break; #endif default: From 68f391707f47d2d3a0f76d0b91cb2b105b54dafa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 26 Jan 2019 12:09:45 +0100 Subject: [PATCH 295/347] Remove some unnecessary vkDestroyImage calls. --- Common/Vulkan/VulkanImage.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Common/Vulkan/VulkanImage.cpp b/Common/Vulkan/VulkanImage.cpp index 1db379e2ab..e39f2ce724 100644 --- a/Common/Vulkan/VulkanImage.cpp +++ b/Common/Vulkan/VulkanImage.cpp @@ -76,11 +76,8 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, if (allocator_) { offset_ = allocator_->Allocate(mem_reqs, &mem_, Tag()); - if (offset_ == VulkanDeviceAllocator::ALLOCATE_FAILED) { - vkDestroyImage(vulkan_->GetDevice(), image_, nullptr); - ELOG("Image memory allocation failed (mem_reqs.size = %d)", (int)mem_reqs.size); - return false; - } + // Destructor will take care of the image. + return false; } else { VkMemoryAllocateInfo mem_alloc{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; mem_alloc.memoryTypeIndex = 0; @@ -95,8 +92,6 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, ELOG("vkAllocateMemory failed: %s", VulkanResultToString(res)); _assert_msg_(G3D, res != VK_ERROR_TOO_MANY_OBJECTS, "Too many Vulkan memory objects!"); _assert_(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS); - vkDestroyImage(vulkan_->GetDevice(), image_, nullptr); - image_ = VK_NULL_HANDLE; return false; } From 6f1996413515f6afcf05d59ce1c6a5e0d796b141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 26 Jan 2019 12:20:09 +0100 Subject: [PATCH 296/347] Also buildfix for libretro --- libretro/LibretroVulkanContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libretro/LibretroVulkanContext.cpp b/libretro/LibretroVulkanContext.cpp index 5cc7d4f09b..69679f16bc 100644 --- a/libretro/LibretroVulkanContext.cpp +++ b/libretro/LibretroVulkanContext.cpp @@ -134,7 +134,7 @@ void LibretroVulkanContext::CreateDrawContext() { } vk_libretro_set_hwrender_interface(vulkan); - vk->ReinitSurface(PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight); + vk->ReinitSurface(); if (!vk->InitSwapchain()) { return; From ca6298e24de6e93f6a8972d1a34c5992e33af2ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 27 Jan 2019 19:28:23 +0100 Subject: [PATCH 297/347] Fix silly mistake editing the vulkan image code Thanks unknown. --- Common/Vulkan/VulkanImage.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Common/Vulkan/VulkanImage.cpp b/Common/Vulkan/VulkanImage.cpp index e39f2ce724..8344699157 100644 --- a/Common/Vulkan/VulkanImage.cpp +++ b/Common/Vulkan/VulkanImage.cpp @@ -76,8 +76,11 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, if (allocator_) { offset_ = allocator_->Allocate(mem_reqs, &mem_, Tag()); - // Destructor will take care of the image. - return false; + if (offset_ == VulkanDeviceAllocator::ALLOCATE_FAILED) { + ELOG("Image memory allocation failed (mem_reqs.size=%d, typebits=%08x", (int)mem_reqs.size, (int)mem_reqs.memoryTypeBits); + // Destructor will take care of the image. + return false; + } } else { VkMemoryAllocateInfo mem_alloc{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; mem_alloc.memoryTypeIndex = 0; From bb4d91c9588c2238c76602f891dc6379464d6a79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 30 Jan 2019 17:57:20 +0100 Subject: [PATCH 298/347] If we lose the Vulkan device, recommend the user to switch to Direct3D11. :-( --- ext/native/thin3d/VulkanRenderManager.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index fb36d8a3df..185968d6c7 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -898,7 +898,11 @@ void VulkanRenderManager::Submit(int frame, bool triggerFence) { submit_info.pCommandBuffers = cmdBufs; res = vkQueueSubmit(vulkan_->GetGraphicsQueue(), 1, &submit_info, VK_NULL_HANDLE); if (res == VK_ERROR_DEVICE_LOST) { - _assert_msg_(G3D, false, "Lost the Vulkan device!"); +#ifdef _WIN32 + _assert_msg_(G3D, false, "Lost the Vulkan device! If this happens again, switch Graphics Backend from Vulkan to Direct3D11"); +#else + _assert_msg_(G3D, false, "Lost the Vulkan device! If this happens again, switch Graphics Backend from Vulkan to OpenGL"); +#endif } else { _assert_msg_(G3D, res == VK_SUCCESS, "vkQueueSubmit failed (init)! result=%s", VulkanResultToString(res)); } @@ -922,7 +926,11 @@ void VulkanRenderManager::Submit(int frame, bool triggerFence) { } res = vkQueueSubmit(vulkan_->GetGraphicsQueue(), 1, &submit_info, triggerFence ? frameData.fence : VK_NULL_HANDLE); if (res == VK_ERROR_DEVICE_LOST) { - _assert_msg_(G3D, false, "Lost the Vulkan device!"); +#ifdef _WIN32 + _assert_msg_(G3D, false, "Lost the Vulkan device! If this happens again, switch Graphics Backend from Vulkan to Direct3D11"); +#else + _assert_msg_(G3D, false, "Lost the Vulkan device! If this happens again, switch Graphics Backend from Vulkan to OpenGL"); +#endif } else { _assert_msg_(G3D, res == VK_SUCCESS, "vkQueueSubmit failed (main, split=%d)! result=%s", (int)splitSubmit_, VulkanResultToString(res)); } From 852f522ebcc896aeefd0f9857c7ad6e91a8da69f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 30 Jan 2019 19:45:04 +0100 Subject: [PATCH 299/347] Improve the check for Vulkan to check for surface extensions first. Might fix the crashing issues we've seen on AMD? --- Common/Vulkan/VulkanLoader.cpp | 45 ++++++++++++++++++++++++++++++---- Core/HLE/sceUsbGps.h | 3 +-- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/Common/Vulkan/VulkanLoader.cpp b/Common/Vulkan/VulkanLoader.cpp index 04755dc555..1ddeec3c60 100644 --- a/Common/Vulkan/VulkanLoader.cpp +++ b/Common/Vulkan/VulkanLoader.cpp @@ -246,6 +246,7 @@ bool VulkanMayBeAvailable() { // Do a hyper minimal initialization and teardown to figure out if there's any chance // that any sort of Vulkan will be usable. + PFN_vkEnumerateInstanceExtensionProperties localEnumerateInstanceExtensionProperties = LOAD_GLOBAL_FUNC_LOCAL(lib, vkEnumerateInstanceExtensionProperties); PFN_vkCreateInstance localCreateInstance = LOAD_GLOBAL_FUNC_LOCAL(lib, vkCreateInstance); PFN_vkEnumeratePhysicalDevices localEnumerate = LOAD_GLOBAL_FUNC_LOCAL(lib, vkEnumeratePhysicalDevices); PFN_vkDestroyInstance localDestroyInstance = LOAD_GLOBAL_FUNC_LOCAL(lib, vkDestroyInstance); @@ -260,18 +261,52 @@ bool VulkanMayBeAvailable() { VkInstance instance = VK_NULL_HANDLE; VkResult res; uint32_t physicalDeviceCount = 0; + std::vector instanceExts; - if (!localCreateInstance || !localEnumerate || !localDestroyInstance || !localGetPhysicalDeviceProperties) + if (!localEnumerateInstanceExtensionProperties || !localCreateInstance || !localEnumerate || !localDestroyInstance || !localGetPhysicalDeviceProperties) goto bail; + uint32_t instanceExtCount = 0; + res = localEnumerateInstanceExtensionProperties(nullptr, &instanceExtCount, nullptr); + // Maximum paranoia. + if (res != VK_SUCCESS) { + ELOG("Counting VK extensions failed."); + goto bail; + } + if (instanceExtCount == 0) { + ELOG("No VK instance extensions - won't be able to present."); + goto bail; + } + instanceExts.resize(instanceExtCount); + res = localEnumerateInstanceExtensionProperties(nullptr, &instanceExtCount, instanceExts.data()); + if (res != VK_SUCCESS) { + ELOG("Enumerating VK extensions failed."); + goto bail; + } + #ifdef _WIN32 - instanceExtensions[0] = VK_KHR_WIN32_SURFACE_EXTENSION_NAME; - ci.enabledExtensionCount = 1; + const char * const surfaceExtension = VK_KHR_WIN32_SURFACE_EXTENSION_NAME; #elif defined(__ANDROID__) - instanceExtensions[0] = VK_KHR_ANDROID_SURFACE_EXTENSION_NAME; - ci.enabledExtensionCount = 1; + const char *surfaceExtension = VK_KHR_ANDROID_SURFACE_EXTENSION_NAME; +#else + const char *surfaceExtension = 0; #endif + if (surfaceExtension) { + bool foundSurfaceExtension = false; + for (auto iter : instanceExts) { + if (!strcmp(iter.extensionName, surfaceExtension)) { + instanceExtensions[0] = surfaceExtension; + ci.enabledExtensionCount = 1; + foundSurfaceExtension = true; + } + } + if (!foundSurfaceExtension) { + ELOG("Surface extension not found"); + goto bail; + } + } + ci.ppEnabledExtensionNames = instanceExtensions; ci.enabledLayerCount = 0; info.apiVersion = VK_API_VERSION_1_0; diff --git a/Core/HLE/sceUsbGps.h b/Core/HLE/sceUsbGps.h index 7c2671fb9c..c9f1b7e8f0 100644 --- a/Core/HLE/sceUsbGps.h +++ b/Core/HLE/sceUsbGps.h @@ -22,8 +22,7 @@ void Register_sceUsbGps(); void __UsbGpsInit(); void __UsbGpsDoState(PointerWrap &p); -#pragma pack(push) -#pragma pack(1) +#pragma pack(push, 1) typedef struct { short year; From e91ce854bf9d7529a7a0c576abb6f20ce83ac38a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 30 Jan 2019 19:53:44 +0100 Subject: [PATCH 300/347] Minor cleanup --- Common/Vulkan/VulkanLoader.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Common/Vulkan/VulkanLoader.cpp b/Common/Vulkan/VulkanLoader.cpp index 1ddeec3c60..a8723fb1fe 100644 --- a/Common/Vulkan/VulkanLoader.cpp +++ b/Common/Vulkan/VulkanLoader.cpp @@ -270,7 +270,7 @@ bool VulkanMayBeAvailable() { res = localEnumerateInstanceExtensionProperties(nullptr, &instanceExtCount, nullptr); // Maximum paranoia. if (res != VK_SUCCESS) { - ELOG("Counting VK extensions failed."); + ELOG("Enumerating VK extensions failed."); goto bail; } if (instanceExtCount == 0) { @@ -293,15 +293,14 @@ bool VulkanMayBeAvailable() { #endif if (surfaceExtension) { - bool foundSurfaceExtension = false; for (auto iter : instanceExts) { if (!strcmp(iter.extensionName, surfaceExtension)) { instanceExtensions[0] = surfaceExtension; ci.enabledExtensionCount = 1; - foundSurfaceExtension = true; + break; } } - if (!foundSurfaceExtension) { + if (!ci.enabledExtensionCount) { ELOG("Surface extension not found"); goto bail; } From b82462bf30df94e661f33ccad450aad23a95ed41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 30 Jan 2019 20:18:56 +0100 Subject: [PATCH 301/347] Reorder stuff to make the compiler happy. I should get rid of those gotos. --- Common/Vulkan/VulkanLoader.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Common/Vulkan/VulkanLoader.cpp b/Common/Vulkan/VulkanLoader.cpp index a8723fb1fe..81d141b778 100644 --- a/Common/Vulkan/VulkanLoader.cpp +++ b/Common/Vulkan/VulkanLoader.cpp @@ -261,12 +261,20 @@ bool VulkanMayBeAvailable() { VkInstance instance = VK_NULL_HANDLE; VkResult res; uint32_t physicalDeviceCount = 0; + uint32_t instanceExtCount = 0; std::vector instanceExts; +#ifdef _WIN32 + const char * const surfaceExtension = VK_KHR_WIN32_SURFACE_EXTENSION_NAME; +#elif defined(__ANDROID__) + const char *surfaceExtension = VK_KHR_ANDROID_SURFACE_EXTENSION_NAME; +#else + const char *surfaceExtension = 0; +#endif + if (!localEnumerateInstanceExtensionProperties || !localCreateInstance || !localEnumerate || !localDestroyInstance || !localGetPhysicalDeviceProperties) goto bail; - uint32_t instanceExtCount = 0; res = localEnumerateInstanceExtensionProperties(nullptr, &instanceExtCount, nullptr); // Maximum paranoia. if (res != VK_SUCCESS) { @@ -284,14 +292,6 @@ bool VulkanMayBeAvailable() { goto bail; } -#ifdef _WIN32 - const char * const surfaceExtension = VK_KHR_WIN32_SURFACE_EXTENSION_NAME; -#elif defined(__ANDROID__) - const char *surfaceExtension = VK_KHR_ANDROID_SURFACE_EXTENSION_NAME; -#else - const char *surfaceExtension = 0; -#endif - if (surfaceExtension) { for (auto iter : instanceExts) { if (!strcmp(iter.extensionName, surfaceExtension)) { From ff633e2cc65ef6d304c736ccae4dcc879c2c031d Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 31 Jan 2019 13:39:18 +0100 Subject: [PATCH 302/347] Update Vulkan headers to SDK 1.1.97 --- ext/vulkan/spirv.h | 206 ++- ext/vulkan/spirv.hpp | 1019 --------------- ext/vulkan/spirv.hpp11 | 1019 --------------- ext/vulkan/spirv.json | 218 +++- ext/vulkan/spirv.lua | 202 ++- ext/vulkan/spirv.py | 202 ++- ext/vulkan/vk_icd.h | 38 +- ext/vulkan/vk_layer.h | 6 +- ext/vulkan/vk_layer_dispatch_table.h | 507 -------- ext/vulkan/vulkan.h | 12 +- ext/vulkan/vulkan_android.h | 68 +- ext/vulkan/vulkan_core.h | 1808 +++++++++++++++++++++++++- ext/vulkan/vulkan_fuchsia.h | 58 + ext/vulkan/vulkan_ios.h | 2 +- ext/vulkan/vulkan_macos.h | 2 +- ext/vulkan/vulkan_vi.h | 2 +- ext/vulkan/vulkan_wayland.h | 2 +- ext/vulkan/vulkan_win32.h | 2 +- ext/vulkan/vulkan_xcb.h | 2 +- ext/vulkan/vulkan_xlib.h | 2 +- ext/vulkan/vulkan_xlib_xrandr.h | 2 +- 21 files changed, 2751 insertions(+), 2628 deletions(-) delete mode 100644 ext/vulkan/spirv.hpp delete mode 100644 ext/vulkan/spirv.hpp11 delete mode 100644 ext/vulkan/vk_layer_dispatch_table.h create mode 100644 ext/vulkan/vulkan_fuchsia.h diff --git a/ext/vulkan/spirv.h b/ext/vulkan/spirv.h index 2be35146df..081e12b4c1 100644 --- a/ext/vulkan/spirv.h +++ b/ext/vulkan/spirv.h @@ -1,5 +1,5 @@ /* -** Copyright (c) 2014-2017 The Khronos Group Inc. +** Copyright (c) 2014-2019 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a copy ** of this software and/or associated documentation files (the "Materials"), @@ -31,13 +31,16 @@ /* ** Enumeration tokens for SPIR-V, in various styles: -** C, C++, C++11, JSON, Lua, Python +** C, C++, C++11, JSON, Lua, Python, C#, D ** ** - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL ** - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL ** - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL ** - Lua will use tables, e.g.: spv.SourceLanguage.GLSL ** - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL'] +** - C# will use enum classes in the Specification class located in the "Spv" namespace, +** e.g.: Spv.Specification.SourceLanguage.GLSL +** - D will have tokens under the "spv" module, e.g: spv.SourceLanguage.GLSL ** ** Some tokens act like mask values, which can be OR'd together, ** while others are mutually exclusive. The mask-like ones have @@ -50,12 +53,12 @@ typedef unsigned int SpvId; -#define SPV_VERSION 0x10100 -#define SPV_REVISION 8 +#define SPV_VERSION 0x10300 +#define SPV_REVISION 6 static const unsigned int SpvMagicNumber = 0x07230203; -static const unsigned int SpvVersion = 0x00010100; -static const unsigned int SpvRevision = 8; +static const unsigned int SpvVersion = 0x00010300; +static const unsigned int SpvRevision = 6; static const unsigned int SpvOpCodeMask = 0xffff; static const unsigned int SpvWordCountShift = 16; @@ -77,6 +80,14 @@ typedef enum SpvExecutionModel_ { SpvExecutionModelFragment = 4, SpvExecutionModelGLCompute = 5, SpvExecutionModelKernel = 6, + SpvExecutionModelTaskNV = 5267, + SpvExecutionModelMeshNV = 5268, + SpvExecutionModelRayGenerationNV = 5313, + SpvExecutionModelIntersectionNV = 5314, + SpvExecutionModelAnyHitNV = 5315, + SpvExecutionModelClosestHitNV = 5316, + SpvExecutionModelMissNV = 5317, + SpvExecutionModelCallableNV = 5318, SpvExecutionModelMax = 0x7fffffff, } SpvExecutionModel; @@ -84,6 +95,7 @@ typedef enum SpvAddressingModel_ { SpvAddressingModelLogical = 0, SpvAddressingModelPhysical32 = 1, SpvAddressingModelPhysical64 = 2, + SpvAddressingModelPhysicalStorageBuffer64EXT = 5348, SpvAddressingModelMax = 0x7fffffff, } SpvAddressingModel; @@ -91,6 +103,7 @@ typedef enum SpvMemoryModel_ { SpvMemoryModelSimple = 0, SpvMemoryModelGLSL450 = 1, SpvMemoryModelOpenCL = 2, + SpvMemoryModelVulkanKHR = 3, SpvMemoryModelMax = 0x7fffffff, } SpvMemoryModel; @@ -130,8 +143,21 @@ typedef enum SpvExecutionMode_ { SpvExecutionModeFinalizer = 34, SpvExecutionModeSubgroupSize = 35, SpvExecutionModeSubgroupsPerWorkgroup = 36, + SpvExecutionModeSubgroupsPerWorkgroupId = 37, + SpvExecutionModeLocalSizeId = 38, + SpvExecutionModeLocalSizeHintId = 39, SpvExecutionModePostDepthCoverage = 4446, + SpvExecutionModeDenormPreserve = 4459, + SpvExecutionModeDenormFlushToZero = 4460, + SpvExecutionModeSignedZeroInfNanPreserve = 4461, + SpvExecutionModeRoundingModeRTE = 4462, + SpvExecutionModeRoundingModeRTZ = 4463, SpvExecutionModeStencilRefReplacingEXT = 5027, + SpvExecutionModeOutputLinesNV = 5269, + SpvExecutionModeOutputPrimitivesNV = 5270, + SpvExecutionModeDerivativeGroupQuadsNV = 5289, + SpvExecutionModeDerivativeGroupLinearNV = 5290, + SpvExecutionModeOutputTrianglesNV = 5298, SpvExecutionModeMax = 0x7fffffff, } SpvExecutionMode; @@ -149,6 +175,13 @@ typedef enum SpvStorageClass_ { SpvStorageClassAtomicCounter = 10, SpvStorageClassImage = 11, SpvStorageClassStorageBuffer = 12, + SpvStorageClassCallableDataNV = 5328, + SpvStorageClassIncomingCallableDataNV = 5329, + SpvStorageClassRayPayloadNV = 5338, + SpvStorageClassHitAttributeNV = 5339, + SpvStorageClassIncomingRayPayloadNV = 5342, + SpvStorageClassShaderRecordBufferNV = 5343, + SpvStorageClassPhysicalStorageBufferEXT = 5349, SpvStorageClassMax = 0x7fffffff, } SpvStorageClass; @@ -276,6 +309,10 @@ typedef enum SpvImageOperandsShift_ { SpvImageOperandsConstOffsetsShift = 5, SpvImageOperandsSampleShift = 6, SpvImageOperandsMinLodShift = 7, + SpvImageOperandsMakeTexelAvailableKHRShift = 8, + SpvImageOperandsMakeTexelVisibleKHRShift = 9, + SpvImageOperandsNonPrivateTexelKHRShift = 10, + SpvImageOperandsVolatileTexelKHRShift = 11, SpvImageOperandsMax = 0x7fffffff, } SpvImageOperandsShift; @@ -289,6 +326,10 @@ typedef enum SpvImageOperandsMask_ { SpvImageOperandsConstOffsetsMask = 0x00000020, SpvImageOperandsSampleMask = 0x00000040, SpvImageOperandsMinLodMask = 0x00000080, + SpvImageOperandsMakeTexelAvailableKHRMask = 0x00000100, + SpvImageOperandsMakeTexelVisibleKHRMask = 0x00000200, + SpvImageOperandsNonPrivateTexelKHRMask = 0x00000400, + SpvImageOperandsVolatileTexelKHRMask = 0x00000800, } SpvImageOperandsMask; typedef enum SpvFPFastMathModeShift_ { @@ -387,11 +428,24 @@ typedef enum SpvDecoration_ { SpvDecorationInputAttachmentIndex = 43, SpvDecorationAlignment = 44, SpvDecorationMaxByteOffset = 45, + SpvDecorationAlignmentId = 46, + SpvDecorationMaxByteOffsetId = 47, + SpvDecorationNoSignedWrap = 4469, + SpvDecorationNoUnsignedWrap = 4470, SpvDecorationExplicitInterpAMD = 4999, SpvDecorationOverrideCoverageNV = 5248, SpvDecorationPassthroughNV = 5250, SpvDecorationViewportRelativeNV = 5252, SpvDecorationSecondaryViewportRelativeNV = 5256, + SpvDecorationPerPrimitiveNV = 5271, + SpvDecorationPerViewNV = 5272, + SpvDecorationPerTaskNV = 5273, + SpvDecorationPerVertexNV = 5285, + SpvDecorationNonUniformEXT = 5300, + SpvDecorationRestrictPointerEXT = 5355, + SpvDecorationAliasedPointerEXT = 5356, + SpvDecorationHlslCounterBufferGOOGLE = 5634, + SpvDecorationHlslSemanticGOOGLE = 5635, SpvDecorationMax = 0x7fffffff, } SpvDecoration; @@ -437,10 +491,15 @@ typedef enum SpvBuiltIn_ { SpvBuiltInSubgroupLocalInvocationId = 41, SpvBuiltInVertexIndex = 42, SpvBuiltInInstanceIndex = 43, + SpvBuiltInSubgroupEqMask = 4416, SpvBuiltInSubgroupEqMaskKHR = 4416, + SpvBuiltInSubgroupGeMask = 4417, SpvBuiltInSubgroupGeMaskKHR = 4417, + SpvBuiltInSubgroupGtMask = 4418, SpvBuiltInSubgroupGtMaskKHR = 4418, + SpvBuiltInSubgroupLeMask = 4419, SpvBuiltInSubgroupLeMaskKHR = 4419, + SpvBuiltInSubgroupLtMask = 4420, SpvBuiltInSubgroupLtMaskKHR = 4420, SpvBuiltInBaseVertex = 4424, SpvBuiltInBaseInstance = 4425, @@ -460,6 +519,35 @@ typedef enum SpvBuiltIn_ { SpvBuiltInSecondaryViewportMaskNV = 5258, SpvBuiltInPositionPerViewNV = 5261, SpvBuiltInViewportMaskPerViewNV = 5262, + SpvBuiltInFullyCoveredEXT = 5264, + SpvBuiltInTaskCountNV = 5274, + SpvBuiltInPrimitiveCountNV = 5275, + SpvBuiltInPrimitiveIndicesNV = 5276, + SpvBuiltInClipDistancePerViewNV = 5277, + SpvBuiltInCullDistancePerViewNV = 5278, + SpvBuiltInLayerPerViewNV = 5279, + SpvBuiltInMeshViewCountNV = 5280, + SpvBuiltInMeshViewIndicesNV = 5281, + SpvBuiltInBaryCoordNV = 5286, + SpvBuiltInBaryCoordNoPerspNV = 5287, + SpvBuiltInFragSizeEXT = 5292, + SpvBuiltInFragmentSizeNV = 5292, + SpvBuiltInFragInvocationCountEXT = 5293, + SpvBuiltInInvocationsPerPixelNV = 5293, + SpvBuiltInLaunchIdNV = 5319, + SpvBuiltInLaunchSizeNV = 5320, + SpvBuiltInWorldRayOriginNV = 5321, + SpvBuiltInWorldRayDirectionNV = 5322, + SpvBuiltInObjectRayOriginNV = 5323, + SpvBuiltInObjectRayDirectionNV = 5324, + SpvBuiltInRayTminNV = 5325, + SpvBuiltInRayTmaxNV = 5326, + SpvBuiltInInstanceCustomIndexNV = 5327, + SpvBuiltInObjectToWorldNV = 5330, + SpvBuiltInWorldToObjectNV = 5331, + SpvBuiltInHitTNV = 5332, + SpvBuiltInHitKindNV = 5333, + SpvBuiltInIncomingRayFlagsNV = 5351, SpvBuiltInMax = 0x7fffffff, } SpvBuiltIn; @@ -518,6 +606,9 @@ typedef enum SpvMemorySemanticsShift_ { SpvMemorySemanticsCrossWorkgroupMemoryShift = 9, SpvMemorySemanticsAtomicCounterMemoryShift = 10, SpvMemorySemanticsImageMemoryShift = 11, + SpvMemorySemanticsOutputMemoryKHRShift = 12, + SpvMemorySemanticsMakeAvailableKHRShift = 13, + SpvMemorySemanticsMakeVisibleKHRShift = 14, SpvMemorySemanticsMax = 0x7fffffff, } SpvMemorySemanticsShift; @@ -533,12 +624,18 @@ typedef enum SpvMemorySemanticsMask_ { SpvMemorySemanticsCrossWorkgroupMemoryMask = 0x00000200, SpvMemorySemanticsAtomicCounterMemoryMask = 0x00000400, SpvMemorySemanticsImageMemoryMask = 0x00000800, + SpvMemorySemanticsOutputMemoryKHRMask = 0x00001000, + SpvMemorySemanticsMakeAvailableKHRMask = 0x00002000, + SpvMemorySemanticsMakeVisibleKHRMask = 0x00004000, } SpvMemorySemanticsMask; typedef enum SpvMemoryAccessShift_ { SpvMemoryAccessVolatileShift = 0, SpvMemoryAccessAlignedShift = 1, SpvMemoryAccessNontemporalShift = 2, + SpvMemoryAccessMakePointerAvailableKHRShift = 3, + SpvMemoryAccessMakePointerVisibleKHRShift = 4, + SpvMemoryAccessNonPrivatePointerKHRShift = 5, SpvMemoryAccessMax = 0x7fffffff, } SpvMemoryAccessShift; @@ -547,6 +644,9 @@ typedef enum SpvMemoryAccessMask_ { SpvMemoryAccessVolatileMask = 0x00000001, SpvMemoryAccessAlignedMask = 0x00000002, SpvMemoryAccessNontemporalMask = 0x00000004, + SpvMemoryAccessMakePointerAvailableKHRMask = 0x00000008, + SpvMemoryAccessMakePointerVisibleKHRMask = 0x00000010, + SpvMemoryAccessNonPrivatePointerKHRMask = 0x00000020, } SpvMemoryAccessMask; typedef enum SpvScope_ { @@ -555,6 +655,7 @@ typedef enum SpvScope_ { SpvScopeWorkgroup = 2, SpvScopeSubgroup = 3, SpvScopeInvocation = 4, + SpvScopeQueueFamilyKHR = 5, SpvScopeMax = 0x7fffffff, } SpvScope; @@ -562,6 +663,10 @@ typedef enum SpvGroupOperation_ { SpvGroupOperationReduce = 0, SpvGroupOperationInclusiveScan = 1, SpvGroupOperationExclusiveScan = 2, + SpvGroupOperationClusteredReduce = 3, + SpvGroupOperationPartitionedReduceNV = 6, + SpvGroupOperationPartitionedInclusiveScanNV = 7, + SpvGroupOperationPartitionedExclusiveScanNV = 8, SpvGroupOperationMax = 0x7fffffff, } SpvGroupOperation; @@ -642,6 +747,14 @@ typedef enum SpvCapability_ { SpvCapabilitySubgroupDispatch = 58, SpvCapabilityNamedBarrier = 59, SpvCapabilityPipeStorage = 60, + SpvCapabilityGroupNonUniform = 61, + SpvCapabilityGroupNonUniformVote = 62, + SpvCapabilityGroupNonUniformArithmetic = 63, + SpvCapabilityGroupNonUniformBallot = 64, + SpvCapabilityGroupNonUniformShuffle = 65, + SpvCapabilityGroupNonUniformShuffleRelative = 66, + SpvCapabilityGroupNonUniformClustered = 67, + SpvCapabilityGroupNonUniformQuad = 68, SpvCapabilitySubgroupBallotKHR = 4423, SpvCapabilityDrawParameters = 4427, SpvCapabilitySubgroupVoteKHR = 4431, @@ -657,6 +770,15 @@ typedef enum SpvCapability_ { SpvCapabilityVariablePointers = 4442, SpvCapabilityAtomicStorageOps = 4445, SpvCapabilitySampleMaskPostDepthCoverage = 4447, + SpvCapabilityStorageBuffer8BitAccess = 4448, + SpvCapabilityUniformAndStorageBuffer8BitAccess = 4449, + SpvCapabilityStoragePushConstant8 = 4450, + SpvCapabilityDenormPreserve = 4464, + SpvCapabilityDenormFlushToZero = 4465, + SpvCapabilitySignedZeroInfNanPreserve = 4466, + SpvCapabilityRoundingModeRTE = 4467, + SpvCapabilityRoundingModeRTZ = 4468, + SpvCapabilityFloat16ImageAMD = 5008, SpvCapabilityImageGatherBiasLodAMD = 5009, SpvCapabilityFragmentMaskAMD = 5010, SpvCapabilityStencilExportEXT = 5013, @@ -668,6 +790,31 @@ typedef enum SpvCapability_ { SpvCapabilityShaderViewportMaskNV = 5255, SpvCapabilityShaderStereoViewNV = 5259, SpvCapabilityPerViewAttributesNV = 5260, + SpvCapabilityFragmentFullyCoveredEXT = 5265, + SpvCapabilityMeshShadingNV = 5266, + SpvCapabilityImageFootprintNV = 5282, + SpvCapabilityFragmentBarycentricNV = 5284, + SpvCapabilityComputeDerivativeGroupQuadsNV = 5288, + SpvCapabilityFragmentDensityEXT = 5291, + SpvCapabilityShadingRateNV = 5291, + SpvCapabilityGroupNonUniformPartitionedNV = 5297, + SpvCapabilityShaderNonUniformEXT = 5301, + SpvCapabilityRuntimeDescriptorArrayEXT = 5302, + SpvCapabilityInputAttachmentArrayDynamicIndexingEXT = 5303, + SpvCapabilityUniformTexelBufferArrayDynamicIndexingEXT = 5304, + SpvCapabilityStorageTexelBufferArrayDynamicIndexingEXT = 5305, + SpvCapabilityUniformBufferArrayNonUniformIndexingEXT = 5306, + SpvCapabilitySampledImageArrayNonUniformIndexingEXT = 5307, + SpvCapabilityStorageBufferArrayNonUniformIndexingEXT = 5308, + SpvCapabilityStorageImageArrayNonUniformIndexingEXT = 5309, + SpvCapabilityInputAttachmentArrayNonUniformIndexingEXT = 5310, + SpvCapabilityUniformTexelBufferArrayNonUniformIndexingEXT = 5311, + SpvCapabilityStorageTexelBufferArrayNonUniformIndexingEXT = 5312, + SpvCapabilityRayTracingNV = 5340, + SpvCapabilityVulkanMemoryModelKHR = 5345, + SpvCapabilityVulkanMemoryModelDeviceScopeKHR = 5346, + SpvCapabilityPhysicalStorageBufferAddressesEXT = 5347, + SpvCapabilityComputeDerivativeGroupLinearNV = 5350, SpvCapabilitySubgroupShuffleINTEL = 5568, SpvCapabilitySubgroupBufferBlockIOINTEL = 5569, SpvCapabilitySubgroupImageBlockIOINTEL = 5570, @@ -979,6 +1126,42 @@ typedef enum SpvOp_ { SpvOpNamedBarrierInitialize = 328, SpvOpMemoryNamedBarrier = 329, SpvOpModuleProcessed = 330, + SpvOpExecutionModeId = 331, + SpvOpDecorateId = 332, + SpvOpGroupNonUniformElect = 333, + SpvOpGroupNonUniformAll = 334, + SpvOpGroupNonUniformAny = 335, + SpvOpGroupNonUniformAllEqual = 336, + SpvOpGroupNonUniformBroadcast = 337, + SpvOpGroupNonUniformBroadcastFirst = 338, + SpvOpGroupNonUniformBallot = 339, + SpvOpGroupNonUniformInverseBallot = 340, + SpvOpGroupNonUniformBallotBitExtract = 341, + SpvOpGroupNonUniformBallotBitCount = 342, + SpvOpGroupNonUniformBallotFindLSB = 343, + SpvOpGroupNonUniformBallotFindMSB = 344, + SpvOpGroupNonUniformShuffle = 345, + SpvOpGroupNonUniformShuffleXor = 346, + SpvOpGroupNonUniformShuffleUp = 347, + SpvOpGroupNonUniformShuffleDown = 348, + SpvOpGroupNonUniformIAdd = 349, + SpvOpGroupNonUniformFAdd = 350, + SpvOpGroupNonUniformIMul = 351, + SpvOpGroupNonUniformFMul = 352, + SpvOpGroupNonUniformSMin = 353, + SpvOpGroupNonUniformUMin = 354, + SpvOpGroupNonUniformFMin = 355, + SpvOpGroupNonUniformSMax = 356, + SpvOpGroupNonUniformUMax = 357, + SpvOpGroupNonUniformFMax = 358, + SpvOpGroupNonUniformBitwiseAnd = 359, + SpvOpGroupNonUniformBitwiseOr = 360, + SpvOpGroupNonUniformBitwiseXor = 361, + SpvOpGroupNonUniformLogicalAnd = 362, + SpvOpGroupNonUniformLogicalOr = 363, + SpvOpGroupNonUniformLogicalXor = 364, + SpvOpGroupNonUniformQuadBroadcast = 365, + SpvOpGroupNonUniformQuadSwap = 366, SpvOpSubgroupBallotKHR = 4421, SpvOpSubgroupFirstInvocationKHR = 4422, SpvOpSubgroupAllKHR = 4428, @@ -995,6 +1178,15 @@ typedef enum SpvOp_ { SpvOpGroupSMaxNonUniformAMD = 5007, SpvOpFragmentMaskFetchAMD = 5011, SpvOpFragmentFetchAMD = 5012, + SpvOpImageSampleFootprintNV = 5283, + SpvOpGroupNonUniformPartitionNV = 5296, + SpvOpWritePackedPrimitiveIndices4x8NV = 5299, + SpvOpReportIntersectionNV = 5334, + SpvOpIgnoreIntersectionNV = 5335, + SpvOpTerminateRayNV = 5336, + SpvOpTraceNV = 5337, + SpvOpTypeAccelerationStructureNV = 5341, + SpvOpExecuteCallableNV = 5344, SpvOpSubgroupShuffleINTEL = 5571, SpvOpSubgroupShuffleDownINTEL = 5572, SpvOpSubgroupShuffleUpINTEL = 5573, @@ -1003,6 +1195,8 @@ typedef enum SpvOp_ { SpvOpSubgroupBlockWriteINTEL = 5576, SpvOpSubgroupImageBlockReadINTEL = 5577, SpvOpSubgroupImageBlockWriteINTEL = 5578, + SpvOpDecorateStringGOOGLE = 5632, + SpvOpMemberDecorateStringGOOGLE = 5633, SpvOpMax = 0x7fffffff, } SpvOp; diff --git a/ext/vulkan/spirv.hpp b/ext/vulkan/spirv.hpp deleted file mode 100644 index b9ae21ecef..0000000000 --- a/ext/vulkan/spirv.hpp +++ /dev/null @@ -1,1019 +0,0 @@ -// Copyright (c) 2014-2017 The Khronos Group Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and/or associated documentation files (the "Materials"), -// to deal in the Materials without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Materials, and to permit persons to whom the -// Materials are furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Materials. -// -// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS -// STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND -// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ -// -// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS -// IN THE MATERIALS. - -// This header is automatically generated by the same tool that creates -// the Binary Section of the SPIR-V specification. - -// Enumeration tokens for SPIR-V, in various styles: -// C, C++, C++11, JSON, Lua, Python -// -// - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL -// - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL -// - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL -// - Lua will use tables, e.g.: spv.SourceLanguage.GLSL -// - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL'] -// -// Some tokens act like mask values, which can be OR'd together, -// while others are mutually exclusive. The mask-like ones have -// "Mask" in their name, and a parallel enum that has the shift -// amount (1 << x) for each corresponding enumerant. - -#ifndef spirv_HPP -#define spirv_HPP - -namespace spv { - -typedef unsigned int Id; - -#define SPV_VERSION 0x10100 -#define SPV_REVISION 8 - -static const unsigned int MagicNumber = 0x07230203; -static const unsigned int Version = 0x00010100; -static const unsigned int Revision = 8; -static const unsigned int OpCodeMask = 0xffff; -static const unsigned int WordCountShift = 16; - -enum SourceLanguage { - SourceLanguageUnknown = 0, - SourceLanguageESSL = 1, - SourceLanguageGLSL = 2, - SourceLanguageOpenCL_C = 3, - SourceLanguageOpenCL_CPP = 4, - SourceLanguageHLSL = 5, - SourceLanguageMax = 0x7fffffff, -}; - -enum ExecutionModel { - ExecutionModelVertex = 0, - ExecutionModelTessellationControl = 1, - ExecutionModelTessellationEvaluation = 2, - ExecutionModelGeometry = 3, - ExecutionModelFragment = 4, - ExecutionModelGLCompute = 5, - ExecutionModelKernel = 6, - ExecutionModelMax = 0x7fffffff, -}; - -enum AddressingModel { - AddressingModelLogical = 0, - AddressingModelPhysical32 = 1, - AddressingModelPhysical64 = 2, - AddressingModelMax = 0x7fffffff, -}; - -enum MemoryModel { - MemoryModelSimple = 0, - MemoryModelGLSL450 = 1, - MemoryModelOpenCL = 2, - MemoryModelMax = 0x7fffffff, -}; - -enum ExecutionMode { - ExecutionModeInvocations = 0, - ExecutionModeSpacingEqual = 1, - ExecutionModeSpacingFractionalEven = 2, - ExecutionModeSpacingFractionalOdd = 3, - ExecutionModeVertexOrderCw = 4, - ExecutionModeVertexOrderCcw = 5, - ExecutionModePixelCenterInteger = 6, - ExecutionModeOriginUpperLeft = 7, - ExecutionModeOriginLowerLeft = 8, - ExecutionModeEarlyFragmentTests = 9, - ExecutionModePointMode = 10, - ExecutionModeXfb = 11, - ExecutionModeDepthReplacing = 12, - ExecutionModeDepthGreater = 14, - ExecutionModeDepthLess = 15, - ExecutionModeDepthUnchanged = 16, - ExecutionModeLocalSize = 17, - ExecutionModeLocalSizeHint = 18, - ExecutionModeInputPoints = 19, - ExecutionModeInputLines = 20, - ExecutionModeInputLinesAdjacency = 21, - ExecutionModeTriangles = 22, - ExecutionModeInputTrianglesAdjacency = 23, - ExecutionModeQuads = 24, - ExecutionModeIsolines = 25, - ExecutionModeOutputVertices = 26, - ExecutionModeOutputPoints = 27, - ExecutionModeOutputLineStrip = 28, - ExecutionModeOutputTriangleStrip = 29, - ExecutionModeVecTypeHint = 30, - ExecutionModeContractionOff = 31, - ExecutionModeInitializer = 33, - ExecutionModeFinalizer = 34, - ExecutionModeSubgroupSize = 35, - ExecutionModeSubgroupsPerWorkgroup = 36, - ExecutionModePostDepthCoverage = 4446, - ExecutionModeStencilRefReplacingEXT = 5027, - ExecutionModeMax = 0x7fffffff, -}; - -enum StorageClass { - StorageClassUniformConstant = 0, - StorageClassInput = 1, - StorageClassUniform = 2, - StorageClassOutput = 3, - StorageClassWorkgroup = 4, - StorageClassCrossWorkgroup = 5, - StorageClassPrivate = 6, - StorageClassFunction = 7, - StorageClassGeneric = 8, - StorageClassPushConstant = 9, - StorageClassAtomicCounter = 10, - StorageClassImage = 11, - StorageClassStorageBuffer = 12, - StorageClassMax = 0x7fffffff, -}; - -enum Dim { - Dim1D = 0, - Dim2D = 1, - Dim3D = 2, - DimCube = 3, - DimRect = 4, - DimBuffer = 5, - DimSubpassData = 6, - DimMax = 0x7fffffff, -}; - -enum SamplerAddressingMode { - SamplerAddressingModeNone = 0, - SamplerAddressingModeClampToEdge = 1, - SamplerAddressingModeClamp = 2, - SamplerAddressingModeRepeat = 3, - SamplerAddressingModeRepeatMirrored = 4, - SamplerAddressingModeMax = 0x7fffffff, -}; - -enum SamplerFilterMode { - SamplerFilterModeNearest = 0, - SamplerFilterModeLinear = 1, - SamplerFilterModeMax = 0x7fffffff, -}; - -enum ImageFormat { - ImageFormatUnknown = 0, - ImageFormatRgba32f = 1, - ImageFormatRgba16f = 2, - ImageFormatR32f = 3, - ImageFormatRgba8 = 4, - ImageFormatRgba8Snorm = 5, - ImageFormatRg32f = 6, - ImageFormatRg16f = 7, - ImageFormatR11fG11fB10f = 8, - ImageFormatR16f = 9, - ImageFormatRgba16 = 10, - ImageFormatRgb10A2 = 11, - ImageFormatRg16 = 12, - ImageFormatRg8 = 13, - ImageFormatR16 = 14, - ImageFormatR8 = 15, - ImageFormatRgba16Snorm = 16, - ImageFormatRg16Snorm = 17, - ImageFormatRg8Snorm = 18, - ImageFormatR16Snorm = 19, - ImageFormatR8Snorm = 20, - ImageFormatRgba32i = 21, - ImageFormatRgba16i = 22, - ImageFormatRgba8i = 23, - ImageFormatR32i = 24, - ImageFormatRg32i = 25, - ImageFormatRg16i = 26, - ImageFormatRg8i = 27, - ImageFormatR16i = 28, - ImageFormatR8i = 29, - ImageFormatRgba32ui = 30, - ImageFormatRgba16ui = 31, - ImageFormatRgba8ui = 32, - ImageFormatR32ui = 33, - ImageFormatRgb10a2ui = 34, - ImageFormatRg32ui = 35, - ImageFormatRg16ui = 36, - ImageFormatRg8ui = 37, - ImageFormatR16ui = 38, - ImageFormatR8ui = 39, - ImageFormatMax = 0x7fffffff, -}; - -enum ImageChannelOrder { - ImageChannelOrderR = 0, - ImageChannelOrderA = 1, - ImageChannelOrderRG = 2, - ImageChannelOrderRA = 3, - ImageChannelOrderRGB = 4, - ImageChannelOrderRGBA = 5, - ImageChannelOrderBGRA = 6, - ImageChannelOrderARGB = 7, - ImageChannelOrderIntensity = 8, - ImageChannelOrderLuminance = 9, - ImageChannelOrderRx = 10, - ImageChannelOrderRGx = 11, - ImageChannelOrderRGBx = 12, - ImageChannelOrderDepth = 13, - ImageChannelOrderDepthStencil = 14, - ImageChannelOrdersRGB = 15, - ImageChannelOrdersRGBx = 16, - ImageChannelOrdersRGBA = 17, - ImageChannelOrdersBGRA = 18, - ImageChannelOrderABGR = 19, - ImageChannelOrderMax = 0x7fffffff, -}; - -enum ImageChannelDataType { - ImageChannelDataTypeSnormInt8 = 0, - ImageChannelDataTypeSnormInt16 = 1, - ImageChannelDataTypeUnormInt8 = 2, - ImageChannelDataTypeUnormInt16 = 3, - ImageChannelDataTypeUnormShort565 = 4, - ImageChannelDataTypeUnormShort555 = 5, - ImageChannelDataTypeUnormInt101010 = 6, - ImageChannelDataTypeSignedInt8 = 7, - ImageChannelDataTypeSignedInt16 = 8, - ImageChannelDataTypeSignedInt32 = 9, - ImageChannelDataTypeUnsignedInt8 = 10, - ImageChannelDataTypeUnsignedInt16 = 11, - ImageChannelDataTypeUnsignedInt32 = 12, - ImageChannelDataTypeHalfFloat = 13, - ImageChannelDataTypeFloat = 14, - ImageChannelDataTypeUnormInt24 = 15, - ImageChannelDataTypeUnormInt101010_2 = 16, - ImageChannelDataTypeMax = 0x7fffffff, -}; - -enum ImageOperandsShift { - ImageOperandsBiasShift = 0, - ImageOperandsLodShift = 1, - ImageOperandsGradShift = 2, - ImageOperandsConstOffsetShift = 3, - ImageOperandsOffsetShift = 4, - ImageOperandsConstOffsetsShift = 5, - ImageOperandsSampleShift = 6, - ImageOperandsMinLodShift = 7, - ImageOperandsMax = 0x7fffffff, -}; - -enum ImageOperandsMask { - ImageOperandsMaskNone = 0, - ImageOperandsBiasMask = 0x00000001, - ImageOperandsLodMask = 0x00000002, - ImageOperandsGradMask = 0x00000004, - ImageOperandsConstOffsetMask = 0x00000008, - ImageOperandsOffsetMask = 0x00000010, - ImageOperandsConstOffsetsMask = 0x00000020, - ImageOperandsSampleMask = 0x00000040, - ImageOperandsMinLodMask = 0x00000080, -}; - -enum FPFastMathModeShift { - FPFastMathModeNotNaNShift = 0, - FPFastMathModeNotInfShift = 1, - FPFastMathModeNSZShift = 2, - FPFastMathModeAllowRecipShift = 3, - FPFastMathModeFastShift = 4, - FPFastMathModeMax = 0x7fffffff, -}; - -enum FPFastMathModeMask { - FPFastMathModeMaskNone = 0, - FPFastMathModeNotNaNMask = 0x00000001, - FPFastMathModeNotInfMask = 0x00000002, - FPFastMathModeNSZMask = 0x00000004, - FPFastMathModeAllowRecipMask = 0x00000008, - FPFastMathModeFastMask = 0x00000010, -}; - -enum FPRoundingMode { - FPRoundingModeRTE = 0, - FPRoundingModeRTZ = 1, - FPRoundingModeRTP = 2, - FPRoundingModeRTN = 3, - FPRoundingModeMax = 0x7fffffff, -}; - -enum LinkageType { - LinkageTypeExport = 0, - LinkageTypeImport = 1, - LinkageTypeMax = 0x7fffffff, -}; - -enum AccessQualifier { - AccessQualifierReadOnly = 0, - AccessQualifierWriteOnly = 1, - AccessQualifierReadWrite = 2, - AccessQualifierMax = 0x7fffffff, -}; - -enum FunctionParameterAttribute { - FunctionParameterAttributeZext = 0, - FunctionParameterAttributeSext = 1, - FunctionParameterAttributeByVal = 2, - FunctionParameterAttributeSret = 3, - FunctionParameterAttributeNoAlias = 4, - FunctionParameterAttributeNoCapture = 5, - FunctionParameterAttributeNoWrite = 6, - FunctionParameterAttributeNoReadWrite = 7, - FunctionParameterAttributeMax = 0x7fffffff, -}; - -enum Decoration { - DecorationRelaxedPrecision = 0, - DecorationSpecId = 1, - DecorationBlock = 2, - DecorationBufferBlock = 3, - DecorationRowMajor = 4, - DecorationColMajor = 5, - DecorationArrayStride = 6, - DecorationMatrixStride = 7, - DecorationGLSLShared = 8, - DecorationGLSLPacked = 9, - DecorationCPacked = 10, - DecorationBuiltIn = 11, - DecorationNoPerspective = 13, - DecorationFlat = 14, - DecorationPatch = 15, - DecorationCentroid = 16, - DecorationSample = 17, - DecorationInvariant = 18, - DecorationRestrict = 19, - DecorationAliased = 20, - DecorationVolatile = 21, - DecorationConstant = 22, - DecorationCoherent = 23, - DecorationNonWritable = 24, - DecorationNonReadable = 25, - DecorationUniform = 26, - DecorationSaturatedConversion = 28, - DecorationStream = 29, - DecorationLocation = 30, - DecorationComponent = 31, - DecorationIndex = 32, - DecorationBinding = 33, - DecorationDescriptorSet = 34, - DecorationOffset = 35, - DecorationXfbBuffer = 36, - DecorationXfbStride = 37, - DecorationFuncParamAttr = 38, - DecorationFPRoundingMode = 39, - DecorationFPFastMathMode = 40, - DecorationLinkageAttributes = 41, - DecorationNoContraction = 42, - DecorationInputAttachmentIndex = 43, - DecorationAlignment = 44, - DecorationMaxByteOffset = 45, - DecorationExplicitInterpAMD = 4999, - DecorationOverrideCoverageNV = 5248, - DecorationPassthroughNV = 5250, - DecorationViewportRelativeNV = 5252, - DecorationSecondaryViewportRelativeNV = 5256, - DecorationMax = 0x7fffffff, -}; - -enum BuiltIn { - BuiltInPosition = 0, - BuiltInPointSize = 1, - BuiltInClipDistance = 3, - BuiltInCullDistance = 4, - BuiltInVertexId = 5, - BuiltInInstanceId = 6, - BuiltInPrimitiveId = 7, - BuiltInInvocationId = 8, - BuiltInLayer = 9, - BuiltInViewportIndex = 10, - BuiltInTessLevelOuter = 11, - BuiltInTessLevelInner = 12, - BuiltInTessCoord = 13, - BuiltInPatchVertices = 14, - BuiltInFragCoord = 15, - BuiltInPointCoord = 16, - BuiltInFrontFacing = 17, - BuiltInSampleId = 18, - BuiltInSamplePosition = 19, - BuiltInSampleMask = 20, - BuiltInFragDepth = 22, - BuiltInHelperInvocation = 23, - BuiltInNumWorkgroups = 24, - BuiltInWorkgroupSize = 25, - BuiltInWorkgroupId = 26, - BuiltInLocalInvocationId = 27, - BuiltInGlobalInvocationId = 28, - BuiltInLocalInvocationIndex = 29, - BuiltInWorkDim = 30, - BuiltInGlobalSize = 31, - BuiltInEnqueuedWorkgroupSize = 32, - BuiltInGlobalOffset = 33, - BuiltInGlobalLinearId = 34, - BuiltInSubgroupSize = 36, - BuiltInSubgroupMaxSize = 37, - BuiltInNumSubgroups = 38, - BuiltInNumEnqueuedSubgroups = 39, - BuiltInSubgroupId = 40, - BuiltInSubgroupLocalInvocationId = 41, - BuiltInVertexIndex = 42, - BuiltInInstanceIndex = 43, - BuiltInSubgroupEqMaskKHR = 4416, - BuiltInSubgroupGeMaskKHR = 4417, - BuiltInSubgroupGtMaskKHR = 4418, - BuiltInSubgroupLeMaskKHR = 4419, - BuiltInSubgroupLtMaskKHR = 4420, - BuiltInBaseVertex = 4424, - BuiltInBaseInstance = 4425, - BuiltInDrawIndex = 4426, - BuiltInDeviceIndex = 4438, - BuiltInViewIndex = 4440, - BuiltInBaryCoordNoPerspAMD = 4992, - BuiltInBaryCoordNoPerspCentroidAMD = 4993, - BuiltInBaryCoordNoPerspSampleAMD = 4994, - BuiltInBaryCoordSmoothAMD = 4995, - BuiltInBaryCoordSmoothCentroidAMD = 4996, - BuiltInBaryCoordSmoothSampleAMD = 4997, - BuiltInBaryCoordPullModelAMD = 4998, - BuiltInFragStencilRefEXT = 5014, - BuiltInViewportMaskNV = 5253, - BuiltInSecondaryPositionNV = 5257, - BuiltInSecondaryViewportMaskNV = 5258, - BuiltInPositionPerViewNV = 5261, - BuiltInViewportMaskPerViewNV = 5262, - BuiltInMax = 0x7fffffff, -}; - -enum SelectionControlShift { - SelectionControlFlattenShift = 0, - SelectionControlDontFlattenShift = 1, - SelectionControlMax = 0x7fffffff, -}; - -enum SelectionControlMask { - SelectionControlMaskNone = 0, - SelectionControlFlattenMask = 0x00000001, - SelectionControlDontFlattenMask = 0x00000002, -}; - -enum LoopControlShift { - LoopControlUnrollShift = 0, - LoopControlDontUnrollShift = 1, - LoopControlDependencyInfiniteShift = 2, - LoopControlDependencyLengthShift = 3, - LoopControlMax = 0x7fffffff, -}; - -enum LoopControlMask { - LoopControlMaskNone = 0, - LoopControlUnrollMask = 0x00000001, - LoopControlDontUnrollMask = 0x00000002, - LoopControlDependencyInfiniteMask = 0x00000004, - LoopControlDependencyLengthMask = 0x00000008, -}; - -enum FunctionControlShift { - FunctionControlInlineShift = 0, - FunctionControlDontInlineShift = 1, - FunctionControlPureShift = 2, - FunctionControlConstShift = 3, - FunctionControlMax = 0x7fffffff, -}; - -enum FunctionControlMask { - FunctionControlMaskNone = 0, - FunctionControlInlineMask = 0x00000001, - FunctionControlDontInlineMask = 0x00000002, - FunctionControlPureMask = 0x00000004, - FunctionControlConstMask = 0x00000008, -}; - -enum MemorySemanticsShift { - MemorySemanticsAcquireShift = 1, - MemorySemanticsReleaseShift = 2, - MemorySemanticsAcquireReleaseShift = 3, - MemorySemanticsSequentiallyConsistentShift = 4, - MemorySemanticsUniformMemoryShift = 6, - MemorySemanticsSubgroupMemoryShift = 7, - MemorySemanticsWorkgroupMemoryShift = 8, - MemorySemanticsCrossWorkgroupMemoryShift = 9, - MemorySemanticsAtomicCounterMemoryShift = 10, - MemorySemanticsImageMemoryShift = 11, - MemorySemanticsMax = 0x7fffffff, -}; - -enum MemorySemanticsMask { - MemorySemanticsMaskNone = 0, - MemorySemanticsAcquireMask = 0x00000002, - MemorySemanticsReleaseMask = 0x00000004, - MemorySemanticsAcquireReleaseMask = 0x00000008, - MemorySemanticsSequentiallyConsistentMask = 0x00000010, - MemorySemanticsUniformMemoryMask = 0x00000040, - MemorySemanticsSubgroupMemoryMask = 0x00000080, - MemorySemanticsWorkgroupMemoryMask = 0x00000100, - MemorySemanticsCrossWorkgroupMemoryMask = 0x00000200, - MemorySemanticsAtomicCounterMemoryMask = 0x00000400, - MemorySemanticsImageMemoryMask = 0x00000800, -}; - -enum MemoryAccessShift { - MemoryAccessVolatileShift = 0, - MemoryAccessAlignedShift = 1, - MemoryAccessNontemporalShift = 2, - MemoryAccessMax = 0x7fffffff, -}; - -enum MemoryAccessMask { - MemoryAccessMaskNone = 0, - MemoryAccessVolatileMask = 0x00000001, - MemoryAccessAlignedMask = 0x00000002, - MemoryAccessNontemporalMask = 0x00000004, -}; - -enum Scope { - ScopeCrossDevice = 0, - ScopeDevice = 1, - ScopeWorkgroup = 2, - ScopeSubgroup = 3, - ScopeInvocation = 4, - ScopeMax = 0x7fffffff, -}; - -enum GroupOperation { - GroupOperationReduce = 0, - GroupOperationInclusiveScan = 1, - GroupOperationExclusiveScan = 2, - GroupOperationMax = 0x7fffffff, -}; - -enum KernelEnqueueFlags { - KernelEnqueueFlagsNoWait = 0, - KernelEnqueueFlagsWaitKernel = 1, - KernelEnqueueFlagsWaitWorkGroup = 2, - KernelEnqueueFlagsMax = 0x7fffffff, -}; - -enum KernelProfilingInfoShift { - KernelProfilingInfoCmdExecTimeShift = 0, - KernelProfilingInfoMax = 0x7fffffff, -}; - -enum KernelProfilingInfoMask { - KernelProfilingInfoMaskNone = 0, - KernelProfilingInfoCmdExecTimeMask = 0x00000001, -}; - -enum Capability { - CapabilityMatrix = 0, - CapabilityShader = 1, - CapabilityGeometry = 2, - CapabilityTessellation = 3, - CapabilityAddresses = 4, - CapabilityLinkage = 5, - CapabilityKernel = 6, - CapabilityVector16 = 7, - CapabilityFloat16Buffer = 8, - CapabilityFloat16 = 9, - CapabilityFloat64 = 10, - CapabilityInt64 = 11, - CapabilityInt64Atomics = 12, - CapabilityImageBasic = 13, - CapabilityImageReadWrite = 14, - CapabilityImageMipmap = 15, - CapabilityPipes = 17, - CapabilityGroups = 18, - CapabilityDeviceEnqueue = 19, - CapabilityLiteralSampler = 20, - CapabilityAtomicStorage = 21, - CapabilityInt16 = 22, - CapabilityTessellationPointSize = 23, - CapabilityGeometryPointSize = 24, - CapabilityImageGatherExtended = 25, - CapabilityStorageImageMultisample = 27, - CapabilityUniformBufferArrayDynamicIndexing = 28, - CapabilitySampledImageArrayDynamicIndexing = 29, - CapabilityStorageBufferArrayDynamicIndexing = 30, - CapabilityStorageImageArrayDynamicIndexing = 31, - CapabilityClipDistance = 32, - CapabilityCullDistance = 33, - CapabilityImageCubeArray = 34, - CapabilitySampleRateShading = 35, - CapabilityImageRect = 36, - CapabilitySampledRect = 37, - CapabilityGenericPointer = 38, - CapabilityInt8 = 39, - CapabilityInputAttachment = 40, - CapabilitySparseResidency = 41, - CapabilityMinLod = 42, - CapabilitySampled1D = 43, - CapabilityImage1D = 44, - CapabilitySampledCubeArray = 45, - CapabilitySampledBuffer = 46, - CapabilityImageBuffer = 47, - CapabilityImageMSArray = 48, - CapabilityStorageImageExtendedFormats = 49, - CapabilityImageQuery = 50, - CapabilityDerivativeControl = 51, - CapabilityInterpolationFunction = 52, - CapabilityTransformFeedback = 53, - CapabilityGeometryStreams = 54, - CapabilityStorageImageReadWithoutFormat = 55, - CapabilityStorageImageWriteWithoutFormat = 56, - CapabilityMultiViewport = 57, - CapabilitySubgroupDispatch = 58, - CapabilityNamedBarrier = 59, - CapabilityPipeStorage = 60, - CapabilitySubgroupBallotKHR = 4423, - CapabilityDrawParameters = 4427, - CapabilitySubgroupVoteKHR = 4431, - CapabilityStorageBuffer16BitAccess = 4433, - CapabilityStorageUniformBufferBlock16 = 4433, - CapabilityStorageUniform16 = 4434, - CapabilityUniformAndStorageBuffer16BitAccess = 4434, - CapabilityStoragePushConstant16 = 4435, - CapabilityStorageInputOutput16 = 4436, - CapabilityDeviceGroup = 4437, - CapabilityMultiView = 4439, - CapabilityVariablePointersStorageBuffer = 4441, - CapabilityVariablePointers = 4442, - CapabilityAtomicStorageOps = 4445, - CapabilitySampleMaskPostDepthCoverage = 4447, - CapabilityImageGatherBiasLodAMD = 5009, - CapabilityFragmentMaskAMD = 5010, - CapabilityStencilExportEXT = 5013, - CapabilityImageReadWriteLodAMD = 5015, - CapabilitySampleMaskOverrideCoverageNV = 5249, - CapabilityGeometryShaderPassthroughNV = 5251, - CapabilityShaderViewportIndexLayerEXT = 5254, - CapabilityShaderViewportIndexLayerNV = 5254, - CapabilityShaderViewportMaskNV = 5255, - CapabilityShaderStereoViewNV = 5259, - CapabilityPerViewAttributesNV = 5260, - CapabilitySubgroupShuffleINTEL = 5568, - CapabilitySubgroupBufferBlockIOINTEL = 5569, - CapabilitySubgroupImageBlockIOINTEL = 5570, - CapabilityMax = 0x7fffffff, -}; - -enum Op { - OpNop = 0, - OpUndef = 1, - OpSourceContinued = 2, - OpSource = 3, - OpSourceExtension = 4, - OpName = 5, - OpMemberName = 6, - OpString = 7, - OpLine = 8, - OpExtension = 10, - OpExtInstImport = 11, - OpExtInst = 12, - OpMemoryModel = 14, - OpEntryPoint = 15, - OpExecutionMode = 16, - OpCapability = 17, - OpTypeVoid = 19, - OpTypeBool = 20, - OpTypeInt = 21, - OpTypeFloat = 22, - OpTypeVector = 23, - OpTypeMatrix = 24, - OpTypeImage = 25, - OpTypeSampler = 26, - OpTypeSampledImage = 27, - OpTypeArray = 28, - OpTypeRuntimeArray = 29, - OpTypeStruct = 30, - OpTypeOpaque = 31, - OpTypePointer = 32, - OpTypeFunction = 33, - OpTypeEvent = 34, - OpTypeDeviceEvent = 35, - OpTypeReserveId = 36, - OpTypeQueue = 37, - OpTypePipe = 38, - OpTypeForwardPointer = 39, - OpConstantTrue = 41, - OpConstantFalse = 42, - OpConstant = 43, - OpConstantComposite = 44, - OpConstantSampler = 45, - OpConstantNull = 46, - OpSpecConstantTrue = 48, - OpSpecConstantFalse = 49, - OpSpecConstant = 50, - OpSpecConstantComposite = 51, - OpSpecConstantOp = 52, - OpFunction = 54, - OpFunctionParameter = 55, - OpFunctionEnd = 56, - OpFunctionCall = 57, - OpVariable = 59, - OpImageTexelPointer = 60, - OpLoad = 61, - OpStore = 62, - OpCopyMemory = 63, - OpCopyMemorySized = 64, - OpAccessChain = 65, - OpInBoundsAccessChain = 66, - OpPtrAccessChain = 67, - OpArrayLength = 68, - OpGenericPtrMemSemantics = 69, - OpInBoundsPtrAccessChain = 70, - OpDecorate = 71, - OpMemberDecorate = 72, - OpDecorationGroup = 73, - OpGroupDecorate = 74, - OpGroupMemberDecorate = 75, - OpVectorExtractDynamic = 77, - OpVectorInsertDynamic = 78, - OpVectorShuffle = 79, - OpCompositeConstruct = 80, - OpCompositeExtract = 81, - OpCompositeInsert = 82, - OpCopyObject = 83, - OpTranspose = 84, - OpSampledImage = 86, - OpImageSampleImplicitLod = 87, - OpImageSampleExplicitLod = 88, - OpImageSampleDrefImplicitLod = 89, - OpImageSampleDrefExplicitLod = 90, - OpImageSampleProjImplicitLod = 91, - OpImageSampleProjExplicitLod = 92, - OpImageSampleProjDrefImplicitLod = 93, - OpImageSampleProjDrefExplicitLod = 94, - OpImageFetch = 95, - OpImageGather = 96, - OpImageDrefGather = 97, - OpImageRead = 98, - OpImageWrite = 99, - OpImage = 100, - OpImageQueryFormat = 101, - OpImageQueryOrder = 102, - OpImageQuerySizeLod = 103, - OpImageQuerySize = 104, - OpImageQueryLod = 105, - OpImageQueryLevels = 106, - OpImageQuerySamples = 107, - OpConvertFToU = 109, - OpConvertFToS = 110, - OpConvertSToF = 111, - OpConvertUToF = 112, - OpUConvert = 113, - OpSConvert = 114, - OpFConvert = 115, - OpQuantizeToF16 = 116, - OpConvertPtrToU = 117, - OpSatConvertSToU = 118, - OpSatConvertUToS = 119, - OpConvertUToPtr = 120, - OpPtrCastToGeneric = 121, - OpGenericCastToPtr = 122, - OpGenericCastToPtrExplicit = 123, - OpBitcast = 124, - OpSNegate = 126, - OpFNegate = 127, - OpIAdd = 128, - OpFAdd = 129, - OpISub = 130, - OpFSub = 131, - OpIMul = 132, - OpFMul = 133, - OpUDiv = 134, - OpSDiv = 135, - OpFDiv = 136, - OpUMod = 137, - OpSRem = 138, - OpSMod = 139, - OpFRem = 140, - OpFMod = 141, - OpVectorTimesScalar = 142, - OpMatrixTimesScalar = 143, - OpVectorTimesMatrix = 144, - OpMatrixTimesVector = 145, - OpMatrixTimesMatrix = 146, - OpOuterProduct = 147, - OpDot = 148, - OpIAddCarry = 149, - OpISubBorrow = 150, - OpUMulExtended = 151, - OpSMulExtended = 152, - OpAny = 154, - OpAll = 155, - OpIsNan = 156, - OpIsInf = 157, - OpIsFinite = 158, - OpIsNormal = 159, - OpSignBitSet = 160, - OpLessOrGreater = 161, - OpOrdered = 162, - OpUnordered = 163, - OpLogicalEqual = 164, - OpLogicalNotEqual = 165, - OpLogicalOr = 166, - OpLogicalAnd = 167, - OpLogicalNot = 168, - OpSelect = 169, - OpIEqual = 170, - OpINotEqual = 171, - OpUGreaterThan = 172, - OpSGreaterThan = 173, - OpUGreaterThanEqual = 174, - OpSGreaterThanEqual = 175, - OpULessThan = 176, - OpSLessThan = 177, - OpULessThanEqual = 178, - OpSLessThanEqual = 179, - OpFOrdEqual = 180, - OpFUnordEqual = 181, - OpFOrdNotEqual = 182, - OpFUnordNotEqual = 183, - OpFOrdLessThan = 184, - OpFUnordLessThan = 185, - OpFOrdGreaterThan = 186, - OpFUnordGreaterThan = 187, - OpFOrdLessThanEqual = 188, - OpFUnordLessThanEqual = 189, - OpFOrdGreaterThanEqual = 190, - OpFUnordGreaterThanEqual = 191, - OpShiftRightLogical = 194, - OpShiftRightArithmetic = 195, - OpShiftLeftLogical = 196, - OpBitwiseOr = 197, - OpBitwiseXor = 198, - OpBitwiseAnd = 199, - OpNot = 200, - OpBitFieldInsert = 201, - OpBitFieldSExtract = 202, - OpBitFieldUExtract = 203, - OpBitReverse = 204, - OpBitCount = 205, - OpDPdx = 207, - OpDPdy = 208, - OpFwidth = 209, - OpDPdxFine = 210, - OpDPdyFine = 211, - OpFwidthFine = 212, - OpDPdxCoarse = 213, - OpDPdyCoarse = 214, - OpFwidthCoarse = 215, - OpEmitVertex = 218, - OpEndPrimitive = 219, - OpEmitStreamVertex = 220, - OpEndStreamPrimitive = 221, - OpControlBarrier = 224, - OpMemoryBarrier = 225, - OpAtomicLoad = 227, - OpAtomicStore = 228, - OpAtomicExchange = 229, - OpAtomicCompareExchange = 230, - OpAtomicCompareExchangeWeak = 231, - OpAtomicIIncrement = 232, - OpAtomicIDecrement = 233, - OpAtomicIAdd = 234, - OpAtomicISub = 235, - OpAtomicSMin = 236, - OpAtomicUMin = 237, - OpAtomicSMax = 238, - OpAtomicUMax = 239, - OpAtomicAnd = 240, - OpAtomicOr = 241, - OpAtomicXor = 242, - OpPhi = 245, - OpLoopMerge = 246, - OpSelectionMerge = 247, - OpLabel = 248, - OpBranch = 249, - OpBranchConditional = 250, - OpSwitch = 251, - OpKill = 252, - OpReturn = 253, - OpReturnValue = 254, - OpUnreachable = 255, - OpLifetimeStart = 256, - OpLifetimeStop = 257, - OpGroupAsyncCopy = 259, - OpGroupWaitEvents = 260, - OpGroupAll = 261, - OpGroupAny = 262, - OpGroupBroadcast = 263, - OpGroupIAdd = 264, - OpGroupFAdd = 265, - OpGroupFMin = 266, - OpGroupUMin = 267, - OpGroupSMin = 268, - OpGroupFMax = 269, - OpGroupUMax = 270, - OpGroupSMax = 271, - OpReadPipe = 274, - OpWritePipe = 275, - OpReservedReadPipe = 276, - OpReservedWritePipe = 277, - OpReserveReadPipePackets = 278, - OpReserveWritePipePackets = 279, - OpCommitReadPipe = 280, - OpCommitWritePipe = 281, - OpIsValidReserveId = 282, - OpGetNumPipePackets = 283, - OpGetMaxPipePackets = 284, - OpGroupReserveReadPipePackets = 285, - OpGroupReserveWritePipePackets = 286, - OpGroupCommitReadPipe = 287, - OpGroupCommitWritePipe = 288, - OpEnqueueMarker = 291, - OpEnqueueKernel = 292, - OpGetKernelNDrangeSubGroupCount = 293, - OpGetKernelNDrangeMaxSubGroupSize = 294, - OpGetKernelWorkGroupSize = 295, - OpGetKernelPreferredWorkGroupSizeMultiple = 296, - OpRetainEvent = 297, - OpReleaseEvent = 298, - OpCreateUserEvent = 299, - OpIsValidEvent = 300, - OpSetUserEventStatus = 301, - OpCaptureEventProfilingInfo = 302, - OpGetDefaultQueue = 303, - OpBuildNDRange = 304, - OpImageSparseSampleImplicitLod = 305, - OpImageSparseSampleExplicitLod = 306, - OpImageSparseSampleDrefImplicitLod = 307, - OpImageSparseSampleDrefExplicitLod = 308, - OpImageSparseSampleProjImplicitLod = 309, - OpImageSparseSampleProjExplicitLod = 310, - OpImageSparseSampleProjDrefImplicitLod = 311, - OpImageSparseSampleProjDrefExplicitLod = 312, - OpImageSparseFetch = 313, - OpImageSparseGather = 314, - OpImageSparseDrefGather = 315, - OpImageSparseTexelsResident = 316, - OpNoLine = 317, - OpAtomicFlagTestAndSet = 318, - OpAtomicFlagClear = 319, - OpImageSparseRead = 320, - OpSizeOf = 321, - OpTypePipeStorage = 322, - OpConstantPipeStorage = 323, - OpCreatePipeFromPipeStorage = 324, - OpGetKernelLocalSizeForSubgroupCount = 325, - OpGetKernelMaxNumSubgroups = 326, - OpTypeNamedBarrier = 327, - OpNamedBarrierInitialize = 328, - OpMemoryNamedBarrier = 329, - OpModuleProcessed = 330, - OpSubgroupBallotKHR = 4421, - OpSubgroupFirstInvocationKHR = 4422, - OpSubgroupAllKHR = 4428, - OpSubgroupAnyKHR = 4429, - OpSubgroupAllEqualKHR = 4430, - OpSubgroupReadInvocationKHR = 4432, - OpGroupIAddNonUniformAMD = 5000, - OpGroupFAddNonUniformAMD = 5001, - OpGroupFMinNonUniformAMD = 5002, - OpGroupUMinNonUniformAMD = 5003, - OpGroupSMinNonUniformAMD = 5004, - OpGroupFMaxNonUniformAMD = 5005, - OpGroupUMaxNonUniformAMD = 5006, - OpGroupSMaxNonUniformAMD = 5007, - OpFragmentMaskFetchAMD = 5011, - OpFragmentFetchAMD = 5012, - OpSubgroupShuffleINTEL = 5571, - OpSubgroupShuffleDownINTEL = 5572, - OpSubgroupShuffleUpINTEL = 5573, - OpSubgroupShuffleXorINTEL = 5574, - OpSubgroupBlockReadINTEL = 5575, - OpSubgroupBlockWriteINTEL = 5576, - OpSubgroupImageBlockReadINTEL = 5577, - OpSubgroupImageBlockWriteINTEL = 5578, - OpMax = 0x7fffffff, -}; - -// Overload operator| for mask bit combining - -inline ImageOperandsMask operator|(ImageOperandsMask a, ImageOperandsMask b) { return ImageOperandsMask(unsigned(a) | unsigned(b)); } -inline FPFastMathModeMask operator|(FPFastMathModeMask a, FPFastMathModeMask b) { return FPFastMathModeMask(unsigned(a) | unsigned(b)); } -inline SelectionControlMask operator|(SelectionControlMask a, SelectionControlMask b) { return SelectionControlMask(unsigned(a) | unsigned(b)); } -inline LoopControlMask operator|(LoopControlMask a, LoopControlMask b) { return LoopControlMask(unsigned(a) | unsigned(b)); } -inline FunctionControlMask operator|(FunctionControlMask a, FunctionControlMask b) { return FunctionControlMask(unsigned(a) | unsigned(b)); } -inline MemorySemanticsMask operator|(MemorySemanticsMask a, MemorySemanticsMask b) { return MemorySemanticsMask(unsigned(a) | unsigned(b)); } -inline MemoryAccessMask operator|(MemoryAccessMask a, MemoryAccessMask b) { return MemoryAccessMask(unsigned(a) | unsigned(b)); } -inline KernelProfilingInfoMask operator|(KernelProfilingInfoMask a, KernelProfilingInfoMask b) { return KernelProfilingInfoMask(unsigned(a) | unsigned(b)); } - -} // end namespace spv - -#endif // #ifndef spirv_HPP - diff --git a/ext/vulkan/spirv.hpp11 b/ext/vulkan/spirv.hpp11 deleted file mode 100644 index c345f6da98..0000000000 --- a/ext/vulkan/spirv.hpp11 +++ /dev/null @@ -1,1019 +0,0 @@ -// Copyright (c) 2014-2017 The Khronos Group Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and/or associated documentation files (the "Materials"), -// to deal in the Materials without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Materials, and to permit persons to whom the -// Materials are furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Materials. -// -// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS -// STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND -// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ -// -// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS -// IN THE MATERIALS. - -// This header is automatically generated by the same tool that creates -// the Binary Section of the SPIR-V specification. - -// Enumeration tokens for SPIR-V, in various styles: -// C, C++, C++11, JSON, Lua, Python -// -// - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL -// - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL -// - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL -// - Lua will use tables, e.g.: spv.SourceLanguage.GLSL -// - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL'] -// -// Some tokens act like mask values, which can be OR'd together, -// while others are mutually exclusive. The mask-like ones have -// "Mask" in their name, and a parallel enum that has the shift -// amount (1 << x) for each corresponding enumerant. - -#ifndef spirv_HPP -#define spirv_HPP - -namespace spv { - -typedef unsigned int Id; - -#define SPV_VERSION 0x10100 -#define SPV_REVISION 8 - -static const unsigned int MagicNumber = 0x07230203; -static const unsigned int Version = 0x00010100; -static const unsigned int Revision = 8; -static const unsigned int OpCodeMask = 0xffff; -static const unsigned int WordCountShift = 16; - -enum class SourceLanguage : unsigned { - Unknown = 0, - ESSL = 1, - GLSL = 2, - OpenCL_C = 3, - OpenCL_CPP = 4, - HLSL = 5, - Max = 0x7fffffff, -}; - -enum class ExecutionModel : unsigned { - Vertex = 0, - TessellationControl = 1, - TessellationEvaluation = 2, - Geometry = 3, - Fragment = 4, - GLCompute = 5, - Kernel = 6, - Max = 0x7fffffff, -}; - -enum class AddressingModel : unsigned { - Logical = 0, - Physical32 = 1, - Physical64 = 2, - Max = 0x7fffffff, -}; - -enum class MemoryModel : unsigned { - Simple = 0, - GLSL450 = 1, - OpenCL = 2, - Max = 0x7fffffff, -}; - -enum class ExecutionMode : unsigned { - Invocations = 0, - SpacingEqual = 1, - SpacingFractionalEven = 2, - SpacingFractionalOdd = 3, - VertexOrderCw = 4, - VertexOrderCcw = 5, - PixelCenterInteger = 6, - OriginUpperLeft = 7, - OriginLowerLeft = 8, - EarlyFragmentTests = 9, - PointMode = 10, - Xfb = 11, - DepthReplacing = 12, - DepthGreater = 14, - DepthLess = 15, - DepthUnchanged = 16, - LocalSize = 17, - LocalSizeHint = 18, - InputPoints = 19, - InputLines = 20, - InputLinesAdjacency = 21, - Triangles = 22, - InputTrianglesAdjacency = 23, - Quads = 24, - Isolines = 25, - OutputVertices = 26, - OutputPoints = 27, - OutputLineStrip = 28, - OutputTriangleStrip = 29, - VecTypeHint = 30, - ContractionOff = 31, - Initializer = 33, - Finalizer = 34, - SubgroupSize = 35, - SubgroupsPerWorkgroup = 36, - PostDepthCoverage = 4446, - StencilRefReplacingEXT = 5027, - Max = 0x7fffffff, -}; - -enum class StorageClass : unsigned { - UniformConstant = 0, - Input = 1, - Uniform = 2, - Output = 3, - Workgroup = 4, - CrossWorkgroup = 5, - Private = 6, - Function = 7, - Generic = 8, - PushConstant = 9, - AtomicCounter = 10, - Image = 11, - StorageBuffer = 12, - Max = 0x7fffffff, -}; - -enum class Dim : unsigned { - Dim1D = 0, - Dim2D = 1, - Dim3D = 2, - Cube = 3, - Rect = 4, - Buffer = 5, - SubpassData = 6, - Max = 0x7fffffff, -}; - -enum class SamplerAddressingMode : unsigned { - None = 0, - ClampToEdge = 1, - Clamp = 2, - Repeat = 3, - RepeatMirrored = 4, - Max = 0x7fffffff, -}; - -enum class SamplerFilterMode : unsigned { - Nearest = 0, - Linear = 1, - Max = 0x7fffffff, -}; - -enum class ImageFormat : unsigned { - Unknown = 0, - Rgba32f = 1, - Rgba16f = 2, - R32f = 3, - Rgba8 = 4, - Rgba8Snorm = 5, - Rg32f = 6, - Rg16f = 7, - R11fG11fB10f = 8, - R16f = 9, - Rgba16 = 10, - Rgb10A2 = 11, - Rg16 = 12, - Rg8 = 13, - R16 = 14, - R8 = 15, - Rgba16Snorm = 16, - Rg16Snorm = 17, - Rg8Snorm = 18, - R16Snorm = 19, - R8Snorm = 20, - Rgba32i = 21, - Rgba16i = 22, - Rgba8i = 23, - R32i = 24, - Rg32i = 25, - Rg16i = 26, - Rg8i = 27, - R16i = 28, - R8i = 29, - Rgba32ui = 30, - Rgba16ui = 31, - Rgba8ui = 32, - R32ui = 33, - Rgb10a2ui = 34, - Rg32ui = 35, - Rg16ui = 36, - Rg8ui = 37, - R16ui = 38, - R8ui = 39, - Max = 0x7fffffff, -}; - -enum class ImageChannelOrder : unsigned { - R = 0, - A = 1, - RG = 2, - RA = 3, - RGB = 4, - RGBA = 5, - BGRA = 6, - ARGB = 7, - Intensity = 8, - Luminance = 9, - Rx = 10, - RGx = 11, - RGBx = 12, - Depth = 13, - DepthStencil = 14, - sRGB = 15, - sRGBx = 16, - sRGBA = 17, - sBGRA = 18, - ABGR = 19, - Max = 0x7fffffff, -}; - -enum class ImageChannelDataType : unsigned { - SnormInt8 = 0, - SnormInt16 = 1, - UnormInt8 = 2, - UnormInt16 = 3, - UnormShort565 = 4, - UnormShort555 = 5, - UnormInt101010 = 6, - SignedInt8 = 7, - SignedInt16 = 8, - SignedInt32 = 9, - UnsignedInt8 = 10, - UnsignedInt16 = 11, - UnsignedInt32 = 12, - HalfFloat = 13, - Float = 14, - UnormInt24 = 15, - UnormInt101010_2 = 16, - Max = 0x7fffffff, -}; - -enum class ImageOperandsShift : unsigned { - Bias = 0, - Lod = 1, - Grad = 2, - ConstOffset = 3, - Offset = 4, - ConstOffsets = 5, - Sample = 6, - MinLod = 7, - Max = 0x7fffffff, -}; - -enum class ImageOperandsMask : unsigned { - MaskNone = 0, - Bias = 0x00000001, - Lod = 0x00000002, - Grad = 0x00000004, - ConstOffset = 0x00000008, - Offset = 0x00000010, - ConstOffsets = 0x00000020, - Sample = 0x00000040, - MinLod = 0x00000080, -}; - -enum class FPFastMathModeShift : unsigned { - NotNaN = 0, - NotInf = 1, - NSZ = 2, - AllowRecip = 3, - Fast = 4, - Max = 0x7fffffff, -}; - -enum class FPFastMathModeMask : unsigned { - MaskNone = 0, - NotNaN = 0x00000001, - NotInf = 0x00000002, - NSZ = 0x00000004, - AllowRecip = 0x00000008, - Fast = 0x00000010, -}; - -enum class FPRoundingMode : unsigned { - RTE = 0, - RTZ = 1, - RTP = 2, - RTN = 3, - Max = 0x7fffffff, -}; - -enum class LinkageType : unsigned { - Export = 0, - Import = 1, - Max = 0x7fffffff, -}; - -enum class AccessQualifier : unsigned { - ReadOnly = 0, - WriteOnly = 1, - ReadWrite = 2, - Max = 0x7fffffff, -}; - -enum class FunctionParameterAttribute : unsigned { - Zext = 0, - Sext = 1, - ByVal = 2, - Sret = 3, - NoAlias = 4, - NoCapture = 5, - NoWrite = 6, - NoReadWrite = 7, - Max = 0x7fffffff, -}; - -enum class Decoration : unsigned { - RelaxedPrecision = 0, - SpecId = 1, - Block = 2, - BufferBlock = 3, - RowMajor = 4, - ColMajor = 5, - ArrayStride = 6, - MatrixStride = 7, - GLSLShared = 8, - GLSLPacked = 9, - CPacked = 10, - BuiltIn = 11, - NoPerspective = 13, - Flat = 14, - Patch = 15, - Centroid = 16, - Sample = 17, - Invariant = 18, - Restrict = 19, - Aliased = 20, - Volatile = 21, - Constant = 22, - Coherent = 23, - NonWritable = 24, - NonReadable = 25, - Uniform = 26, - SaturatedConversion = 28, - Stream = 29, - Location = 30, - Component = 31, - Index = 32, - Binding = 33, - DescriptorSet = 34, - Offset = 35, - XfbBuffer = 36, - XfbStride = 37, - FuncParamAttr = 38, - FPRoundingMode = 39, - FPFastMathMode = 40, - LinkageAttributes = 41, - NoContraction = 42, - InputAttachmentIndex = 43, - Alignment = 44, - MaxByteOffset = 45, - ExplicitInterpAMD = 4999, - OverrideCoverageNV = 5248, - PassthroughNV = 5250, - ViewportRelativeNV = 5252, - SecondaryViewportRelativeNV = 5256, - Max = 0x7fffffff, -}; - -enum class BuiltIn : unsigned { - Position = 0, - PointSize = 1, - ClipDistance = 3, - CullDistance = 4, - VertexId = 5, - InstanceId = 6, - PrimitiveId = 7, - InvocationId = 8, - Layer = 9, - ViewportIndex = 10, - TessLevelOuter = 11, - TessLevelInner = 12, - TessCoord = 13, - PatchVertices = 14, - FragCoord = 15, - PointCoord = 16, - FrontFacing = 17, - SampleId = 18, - SamplePosition = 19, - SampleMask = 20, - FragDepth = 22, - HelperInvocation = 23, - NumWorkgroups = 24, - WorkgroupSize = 25, - WorkgroupId = 26, - LocalInvocationId = 27, - GlobalInvocationId = 28, - LocalInvocationIndex = 29, - WorkDim = 30, - GlobalSize = 31, - EnqueuedWorkgroupSize = 32, - GlobalOffset = 33, - GlobalLinearId = 34, - SubgroupSize = 36, - SubgroupMaxSize = 37, - NumSubgroups = 38, - NumEnqueuedSubgroups = 39, - SubgroupId = 40, - SubgroupLocalInvocationId = 41, - VertexIndex = 42, - InstanceIndex = 43, - SubgroupEqMaskKHR = 4416, - SubgroupGeMaskKHR = 4417, - SubgroupGtMaskKHR = 4418, - SubgroupLeMaskKHR = 4419, - SubgroupLtMaskKHR = 4420, - BaseVertex = 4424, - BaseInstance = 4425, - DrawIndex = 4426, - DeviceIndex = 4438, - ViewIndex = 4440, - BaryCoordNoPerspAMD = 4992, - BaryCoordNoPerspCentroidAMD = 4993, - BaryCoordNoPerspSampleAMD = 4994, - BaryCoordSmoothAMD = 4995, - BaryCoordSmoothCentroidAMD = 4996, - BaryCoordSmoothSampleAMD = 4997, - BaryCoordPullModelAMD = 4998, - FragStencilRefEXT = 5014, - ViewportMaskNV = 5253, - SecondaryPositionNV = 5257, - SecondaryViewportMaskNV = 5258, - PositionPerViewNV = 5261, - ViewportMaskPerViewNV = 5262, - Max = 0x7fffffff, -}; - -enum class SelectionControlShift : unsigned { - Flatten = 0, - DontFlatten = 1, - Max = 0x7fffffff, -}; - -enum class SelectionControlMask : unsigned { - MaskNone = 0, - Flatten = 0x00000001, - DontFlatten = 0x00000002, -}; - -enum class LoopControlShift : unsigned { - Unroll = 0, - DontUnroll = 1, - DependencyInfinite = 2, - DependencyLength = 3, - Max = 0x7fffffff, -}; - -enum class LoopControlMask : unsigned { - MaskNone = 0, - Unroll = 0x00000001, - DontUnroll = 0x00000002, - DependencyInfinite = 0x00000004, - DependencyLength = 0x00000008, -}; - -enum class FunctionControlShift : unsigned { - Inline = 0, - DontInline = 1, - Pure = 2, - Const = 3, - Max = 0x7fffffff, -}; - -enum class FunctionControlMask : unsigned { - MaskNone = 0, - Inline = 0x00000001, - DontInline = 0x00000002, - Pure = 0x00000004, - Const = 0x00000008, -}; - -enum class MemorySemanticsShift : unsigned { - Acquire = 1, - Release = 2, - AcquireRelease = 3, - SequentiallyConsistent = 4, - UniformMemory = 6, - SubgroupMemory = 7, - WorkgroupMemory = 8, - CrossWorkgroupMemory = 9, - AtomicCounterMemory = 10, - ImageMemory = 11, - Max = 0x7fffffff, -}; - -enum class MemorySemanticsMask : unsigned { - MaskNone = 0, - Acquire = 0x00000002, - Release = 0x00000004, - AcquireRelease = 0x00000008, - SequentiallyConsistent = 0x00000010, - UniformMemory = 0x00000040, - SubgroupMemory = 0x00000080, - WorkgroupMemory = 0x00000100, - CrossWorkgroupMemory = 0x00000200, - AtomicCounterMemory = 0x00000400, - ImageMemory = 0x00000800, -}; - -enum class MemoryAccessShift : unsigned { - Volatile = 0, - Aligned = 1, - Nontemporal = 2, - Max = 0x7fffffff, -}; - -enum class MemoryAccessMask : unsigned { - MaskNone = 0, - Volatile = 0x00000001, - Aligned = 0x00000002, - Nontemporal = 0x00000004, -}; - -enum class Scope : unsigned { - CrossDevice = 0, - Device = 1, - Workgroup = 2, - Subgroup = 3, - Invocation = 4, - Max = 0x7fffffff, -}; - -enum class GroupOperation : unsigned { - Reduce = 0, - InclusiveScan = 1, - ExclusiveScan = 2, - Max = 0x7fffffff, -}; - -enum class KernelEnqueueFlags : unsigned { - NoWait = 0, - WaitKernel = 1, - WaitWorkGroup = 2, - Max = 0x7fffffff, -}; - -enum class KernelProfilingInfoShift : unsigned { - CmdExecTime = 0, - Max = 0x7fffffff, -}; - -enum class KernelProfilingInfoMask : unsigned { - MaskNone = 0, - CmdExecTime = 0x00000001, -}; - -enum class Capability : unsigned { - Matrix = 0, - Shader = 1, - Geometry = 2, - Tessellation = 3, - Addresses = 4, - Linkage = 5, - Kernel = 6, - Vector16 = 7, - Float16Buffer = 8, - Float16 = 9, - Float64 = 10, - Int64 = 11, - Int64Atomics = 12, - ImageBasic = 13, - ImageReadWrite = 14, - ImageMipmap = 15, - Pipes = 17, - Groups = 18, - DeviceEnqueue = 19, - LiteralSampler = 20, - AtomicStorage = 21, - Int16 = 22, - TessellationPointSize = 23, - GeometryPointSize = 24, - ImageGatherExtended = 25, - StorageImageMultisample = 27, - UniformBufferArrayDynamicIndexing = 28, - SampledImageArrayDynamicIndexing = 29, - StorageBufferArrayDynamicIndexing = 30, - StorageImageArrayDynamicIndexing = 31, - ClipDistance = 32, - CullDistance = 33, - ImageCubeArray = 34, - SampleRateShading = 35, - ImageRect = 36, - SampledRect = 37, - GenericPointer = 38, - Int8 = 39, - InputAttachment = 40, - SparseResidency = 41, - MinLod = 42, - Sampled1D = 43, - Image1D = 44, - SampledCubeArray = 45, - SampledBuffer = 46, - ImageBuffer = 47, - ImageMSArray = 48, - StorageImageExtendedFormats = 49, - ImageQuery = 50, - DerivativeControl = 51, - InterpolationFunction = 52, - TransformFeedback = 53, - GeometryStreams = 54, - StorageImageReadWithoutFormat = 55, - StorageImageWriteWithoutFormat = 56, - MultiViewport = 57, - SubgroupDispatch = 58, - NamedBarrier = 59, - PipeStorage = 60, - SubgroupBallotKHR = 4423, - DrawParameters = 4427, - SubgroupVoteKHR = 4431, - StorageBuffer16BitAccess = 4433, - StorageUniformBufferBlock16 = 4433, - StorageUniform16 = 4434, - UniformAndStorageBuffer16BitAccess = 4434, - StoragePushConstant16 = 4435, - StorageInputOutput16 = 4436, - DeviceGroup = 4437, - MultiView = 4439, - VariablePointersStorageBuffer = 4441, - VariablePointers = 4442, - AtomicStorageOps = 4445, - SampleMaskPostDepthCoverage = 4447, - ImageGatherBiasLodAMD = 5009, - FragmentMaskAMD = 5010, - StencilExportEXT = 5013, - ImageReadWriteLodAMD = 5015, - SampleMaskOverrideCoverageNV = 5249, - GeometryShaderPassthroughNV = 5251, - ShaderViewportIndexLayerEXT = 5254, - ShaderViewportIndexLayerNV = 5254, - ShaderViewportMaskNV = 5255, - ShaderStereoViewNV = 5259, - PerViewAttributesNV = 5260, - SubgroupShuffleINTEL = 5568, - SubgroupBufferBlockIOINTEL = 5569, - SubgroupImageBlockIOINTEL = 5570, - Max = 0x7fffffff, -}; - -enum class Op : unsigned { - OpNop = 0, - OpUndef = 1, - OpSourceContinued = 2, - OpSource = 3, - OpSourceExtension = 4, - OpName = 5, - OpMemberName = 6, - OpString = 7, - OpLine = 8, - OpExtension = 10, - OpExtInstImport = 11, - OpExtInst = 12, - OpMemoryModel = 14, - OpEntryPoint = 15, - OpExecutionMode = 16, - OpCapability = 17, - OpTypeVoid = 19, - OpTypeBool = 20, - OpTypeInt = 21, - OpTypeFloat = 22, - OpTypeVector = 23, - OpTypeMatrix = 24, - OpTypeImage = 25, - OpTypeSampler = 26, - OpTypeSampledImage = 27, - OpTypeArray = 28, - OpTypeRuntimeArray = 29, - OpTypeStruct = 30, - OpTypeOpaque = 31, - OpTypePointer = 32, - OpTypeFunction = 33, - OpTypeEvent = 34, - OpTypeDeviceEvent = 35, - OpTypeReserveId = 36, - OpTypeQueue = 37, - OpTypePipe = 38, - OpTypeForwardPointer = 39, - OpConstantTrue = 41, - OpConstantFalse = 42, - OpConstant = 43, - OpConstantComposite = 44, - OpConstantSampler = 45, - OpConstantNull = 46, - OpSpecConstantTrue = 48, - OpSpecConstantFalse = 49, - OpSpecConstant = 50, - OpSpecConstantComposite = 51, - OpSpecConstantOp = 52, - OpFunction = 54, - OpFunctionParameter = 55, - OpFunctionEnd = 56, - OpFunctionCall = 57, - OpVariable = 59, - OpImageTexelPointer = 60, - OpLoad = 61, - OpStore = 62, - OpCopyMemory = 63, - OpCopyMemorySized = 64, - OpAccessChain = 65, - OpInBoundsAccessChain = 66, - OpPtrAccessChain = 67, - OpArrayLength = 68, - OpGenericPtrMemSemantics = 69, - OpInBoundsPtrAccessChain = 70, - OpDecorate = 71, - OpMemberDecorate = 72, - OpDecorationGroup = 73, - OpGroupDecorate = 74, - OpGroupMemberDecorate = 75, - OpVectorExtractDynamic = 77, - OpVectorInsertDynamic = 78, - OpVectorShuffle = 79, - OpCompositeConstruct = 80, - OpCompositeExtract = 81, - OpCompositeInsert = 82, - OpCopyObject = 83, - OpTranspose = 84, - OpSampledImage = 86, - OpImageSampleImplicitLod = 87, - OpImageSampleExplicitLod = 88, - OpImageSampleDrefImplicitLod = 89, - OpImageSampleDrefExplicitLod = 90, - OpImageSampleProjImplicitLod = 91, - OpImageSampleProjExplicitLod = 92, - OpImageSampleProjDrefImplicitLod = 93, - OpImageSampleProjDrefExplicitLod = 94, - OpImageFetch = 95, - OpImageGather = 96, - OpImageDrefGather = 97, - OpImageRead = 98, - OpImageWrite = 99, - OpImage = 100, - OpImageQueryFormat = 101, - OpImageQueryOrder = 102, - OpImageQuerySizeLod = 103, - OpImageQuerySize = 104, - OpImageQueryLod = 105, - OpImageQueryLevels = 106, - OpImageQuerySamples = 107, - OpConvertFToU = 109, - OpConvertFToS = 110, - OpConvertSToF = 111, - OpConvertUToF = 112, - OpUConvert = 113, - OpSConvert = 114, - OpFConvert = 115, - OpQuantizeToF16 = 116, - OpConvertPtrToU = 117, - OpSatConvertSToU = 118, - OpSatConvertUToS = 119, - OpConvertUToPtr = 120, - OpPtrCastToGeneric = 121, - OpGenericCastToPtr = 122, - OpGenericCastToPtrExplicit = 123, - OpBitcast = 124, - OpSNegate = 126, - OpFNegate = 127, - OpIAdd = 128, - OpFAdd = 129, - OpISub = 130, - OpFSub = 131, - OpIMul = 132, - OpFMul = 133, - OpUDiv = 134, - OpSDiv = 135, - OpFDiv = 136, - OpUMod = 137, - OpSRem = 138, - OpSMod = 139, - OpFRem = 140, - OpFMod = 141, - OpVectorTimesScalar = 142, - OpMatrixTimesScalar = 143, - OpVectorTimesMatrix = 144, - OpMatrixTimesVector = 145, - OpMatrixTimesMatrix = 146, - OpOuterProduct = 147, - OpDot = 148, - OpIAddCarry = 149, - OpISubBorrow = 150, - OpUMulExtended = 151, - OpSMulExtended = 152, - OpAny = 154, - OpAll = 155, - OpIsNan = 156, - OpIsInf = 157, - OpIsFinite = 158, - OpIsNormal = 159, - OpSignBitSet = 160, - OpLessOrGreater = 161, - OpOrdered = 162, - OpUnordered = 163, - OpLogicalEqual = 164, - OpLogicalNotEqual = 165, - OpLogicalOr = 166, - OpLogicalAnd = 167, - OpLogicalNot = 168, - OpSelect = 169, - OpIEqual = 170, - OpINotEqual = 171, - OpUGreaterThan = 172, - OpSGreaterThan = 173, - OpUGreaterThanEqual = 174, - OpSGreaterThanEqual = 175, - OpULessThan = 176, - OpSLessThan = 177, - OpULessThanEqual = 178, - OpSLessThanEqual = 179, - OpFOrdEqual = 180, - OpFUnordEqual = 181, - OpFOrdNotEqual = 182, - OpFUnordNotEqual = 183, - OpFOrdLessThan = 184, - OpFUnordLessThan = 185, - OpFOrdGreaterThan = 186, - OpFUnordGreaterThan = 187, - OpFOrdLessThanEqual = 188, - OpFUnordLessThanEqual = 189, - OpFOrdGreaterThanEqual = 190, - OpFUnordGreaterThanEqual = 191, - OpShiftRightLogical = 194, - OpShiftRightArithmetic = 195, - OpShiftLeftLogical = 196, - OpBitwiseOr = 197, - OpBitwiseXor = 198, - OpBitwiseAnd = 199, - OpNot = 200, - OpBitFieldInsert = 201, - OpBitFieldSExtract = 202, - OpBitFieldUExtract = 203, - OpBitReverse = 204, - OpBitCount = 205, - OpDPdx = 207, - OpDPdy = 208, - OpFwidth = 209, - OpDPdxFine = 210, - OpDPdyFine = 211, - OpFwidthFine = 212, - OpDPdxCoarse = 213, - OpDPdyCoarse = 214, - OpFwidthCoarse = 215, - OpEmitVertex = 218, - OpEndPrimitive = 219, - OpEmitStreamVertex = 220, - OpEndStreamPrimitive = 221, - OpControlBarrier = 224, - OpMemoryBarrier = 225, - OpAtomicLoad = 227, - OpAtomicStore = 228, - OpAtomicExchange = 229, - OpAtomicCompareExchange = 230, - OpAtomicCompareExchangeWeak = 231, - OpAtomicIIncrement = 232, - OpAtomicIDecrement = 233, - OpAtomicIAdd = 234, - OpAtomicISub = 235, - OpAtomicSMin = 236, - OpAtomicUMin = 237, - OpAtomicSMax = 238, - OpAtomicUMax = 239, - OpAtomicAnd = 240, - OpAtomicOr = 241, - OpAtomicXor = 242, - OpPhi = 245, - OpLoopMerge = 246, - OpSelectionMerge = 247, - OpLabel = 248, - OpBranch = 249, - OpBranchConditional = 250, - OpSwitch = 251, - OpKill = 252, - OpReturn = 253, - OpReturnValue = 254, - OpUnreachable = 255, - OpLifetimeStart = 256, - OpLifetimeStop = 257, - OpGroupAsyncCopy = 259, - OpGroupWaitEvents = 260, - OpGroupAll = 261, - OpGroupAny = 262, - OpGroupBroadcast = 263, - OpGroupIAdd = 264, - OpGroupFAdd = 265, - OpGroupFMin = 266, - OpGroupUMin = 267, - OpGroupSMin = 268, - OpGroupFMax = 269, - OpGroupUMax = 270, - OpGroupSMax = 271, - OpReadPipe = 274, - OpWritePipe = 275, - OpReservedReadPipe = 276, - OpReservedWritePipe = 277, - OpReserveReadPipePackets = 278, - OpReserveWritePipePackets = 279, - OpCommitReadPipe = 280, - OpCommitWritePipe = 281, - OpIsValidReserveId = 282, - OpGetNumPipePackets = 283, - OpGetMaxPipePackets = 284, - OpGroupReserveReadPipePackets = 285, - OpGroupReserveWritePipePackets = 286, - OpGroupCommitReadPipe = 287, - OpGroupCommitWritePipe = 288, - OpEnqueueMarker = 291, - OpEnqueueKernel = 292, - OpGetKernelNDrangeSubGroupCount = 293, - OpGetKernelNDrangeMaxSubGroupSize = 294, - OpGetKernelWorkGroupSize = 295, - OpGetKernelPreferredWorkGroupSizeMultiple = 296, - OpRetainEvent = 297, - OpReleaseEvent = 298, - OpCreateUserEvent = 299, - OpIsValidEvent = 300, - OpSetUserEventStatus = 301, - OpCaptureEventProfilingInfo = 302, - OpGetDefaultQueue = 303, - OpBuildNDRange = 304, - OpImageSparseSampleImplicitLod = 305, - OpImageSparseSampleExplicitLod = 306, - OpImageSparseSampleDrefImplicitLod = 307, - OpImageSparseSampleDrefExplicitLod = 308, - OpImageSparseSampleProjImplicitLod = 309, - OpImageSparseSampleProjExplicitLod = 310, - OpImageSparseSampleProjDrefImplicitLod = 311, - OpImageSparseSampleProjDrefExplicitLod = 312, - OpImageSparseFetch = 313, - OpImageSparseGather = 314, - OpImageSparseDrefGather = 315, - OpImageSparseTexelsResident = 316, - OpNoLine = 317, - OpAtomicFlagTestAndSet = 318, - OpAtomicFlagClear = 319, - OpImageSparseRead = 320, - OpSizeOf = 321, - OpTypePipeStorage = 322, - OpConstantPipeStorage = 323, - OpCreatePipeFromPipeStorage = 324, - OpGetKernelLocalSizeForSubgroupCount = 325, - OpGetKernelMaxNumSubgroups = 326, - OpTypeNamedBarrier = 327, - OpNamedBarrierInitialize = 328, - OpMemoryNamedBarrier = 329, - OpModuleProcessed = 330, - OpSubgroupBallotKHR = 4421, - OpSubgroupFirstInvocationKHR = 4422, - OpSubgroupAllKHR = 4428, - OpSubgroupAnyKHR = 4429, - OpSubgroupAllEqualKHR = 4430, - OpSubgroupReadInvocationKHR = 4432, - OpGroupIAddNonUniformAMD = 5000, - OpGroupFAddNonUniformAMD = 5001, - OpGroupFMinNonUniformAMD = 5002, - OpGroupUMinNonUniformAMD = 5003, - OpGroupSMinNonUniformAMD = 5004, - OpGroupFMaxNonUniformAMD = 5005, - OpGroupUMaxNonUniformAMD = 5006, - OpGroupSMaxNonUniformAMD = 5007, - OpFragmentMaskFetchAMD = 5011, - OpFragmentFetchAMD = 5012, - OpSubgroupShuffleINTEL = 5571, - OpSubgroupShuffleDownINTEL = 5572, - OpSubgroupShuffleUpINTEL = 5573, - OpSubgroupShuffleXorINTEL = 5574, - OpSubgroupBlockReadINTEL = 5575, - OpSubgroupBlockWriteINTEL = 5576, - OpSubgroupImageBlockReadINTEL = 5577, - OpSubgroupImageBlockWriteINTEL = 5578, - Max = 0x7fffffff, -}; - -// Overload operator| for mask bit combining - -inline ImageOperandsMask operator|(ImageOperandsMask a, ImageOperandsMask b) { return ImageOperandsMask(unsigned(a) | unsigned(b)); } -inline FPFastMathModeMask operator|(FPFastMathModeMask a, FPFastMathModeMask b) { return FPFastMathModeMask(unsigned(a) | unsigned(b)); } -inline SelectionControlMask operator|(SelectionControlMask a, SelectionControlMask b) { return SelectionControlMask(unsigned(a) | unsigned(b)); } -inline LoopControlMask operator|(LoopControlMask a, LoopControlMask b) { return LoopControlMask(unsigned(a) | unsigned(b)); } -inline FunctionControlMask operator|(FunctionControlMask a, FunctionControlMask b) { return FunctionControlMask(unsigned(a) | unsigned(b)); } -inline MemorySemanticsMask operator|(MemorySemanticsMask a, MemorySemanticsMask b) { return MemorySemanticsMask(unsigned(a) | unsigned(b)); } -inline MemoryAccessMask operator|(MemoryAccessMask a, MemoryAccessMask b) { return MemoryAccessMask(unsigned(a) | unsigned(b)); } -inline KernelProfilingInfoMask operator|(KernelProfilingInfoMask a, KernelProfilingInfoMask b) { return KernelProfilingInfoMask(unsigned(a) | unsigned(b)); } - -} // end namespace spv - -#endif // #ifndef spirv_HPP - diff --git a/ext/vulkan/spirv.json b/ext/vulkan/spirv.json index 988d7bf3ad..3b66cd96ed 100644 --- a/ext/vulkan/spirv.json +++ b/ext/vulkan/spirv.json @@ -6,7 +6,7 @@ "Comment": [ [ - "Copyright (c) 2014-2017 The Khronos Group Inc.", + "Copyright (c) 2014-2019 The Khronos Group Inc.", "", "Permission is hereby granted, free of charge, to any person obtaining a copy", "of this software and/or associated documentation files (the \"Materials\"),", @@ -36,13 +36,16 @@ ], [ "Enumeration tokens for SPIR-V, in various styles:", - " C, C++, C++11, JSON, Lua, Python", + " C, C++, C++11, JSON, Lua, Python, C#, D", "", "- C will have tokens with a \"Spv\" prefix, e.g.: SpvSourceLanguageGLSL", "- C++ will have tokens in the \"spv\" name space, e.g.: spv::SourceLanguageGLSL", "- C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL", "- Lua will use tables, e.g.: spv.SourceLanguage.GLSL", "- Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL']", + "- C# will use enum classes in the Specification class located in the \"Spv\" namespace,", + " e.g.: Spv.Specification.SourceLanguage.GLSL", + "- D will have tokens under the \"spv\" module, e.g: spv.SourceLanguage.GLSL", "", "Some tokens act like mask values, which can be OR'd together,", "while others are mutually exclusive. The mask-like ones have", @@ -51,8 +54,8 @@ ] ], "MagicNumber": 119734787, - "Version": 65792, - "Revision": 8, + "Version": 66304, + "Revision": 6, "OpCodeMask": 65535, "WordCountShift": 16 }, @@ -82,7 +85,15 @@ "Geometry": 3, "Fragment": 4, "GLCompute": 5, - "Kernel": 6 + "Kernel": 6, + "TaskNV": 5267, + "MeshNV": 5268, + "RayGenerationNV": 5313, + "IntersectionNV": 5314, + "AnyHitNV": 5315, + "ClosestHitNV": 5316, + "MissNV": 5317, + "CallableNV": 5318 } }, { @@ -92,7 +103,8 @@ { "Logical": 0, "Physical32": 1, - "Physical64": 2 + "Physical64": 2, + "PhysicalStorageBuffer64EXT": 5348 } }, { @@ -102,7 +114,8 @@ { "Simple": 0, "GLSL450": 1, - "OpenCL": 2 + "OpenCL": 2, + "VulkanKHR": 3 } }, { @@ -145,8 +158,21 @@ "Finalizer": 34, "SubgroupSize": 35, "SubgroupsPerWorkgroup": 36, + "SubgroupsPerWorkgroupId": 37, + "LocalSizeId": 38, + "LocalSizeHintId": 39, "PostDepthCoverage": 4446, - "StencilRefReplacingEXT": 5027 + "DenormPreserve": 4459, + "DenormFlushToZero": 4460, + "SignedZeroInfNanPreserve": 4461, + "RoundingModeRTE": 4462, + "RoundingModeRTZ": 4463, + "StencilRefReplacingEXT": 5027, + "OutputLinesNV": 5269, + "OutputPrimitivesNV": 5270, + "DerivativeGroupQuadsNV": 5289, + "DerivativeGroupLinearNV": 5290, + "OutputTrianglesNV": 5298 } }, { @@ -166,7 +192,14 @@ "PushConstant": 9, "AtomicCounter": 10, "Image": 11, - "StorageBuffer": 12 + "StorageBuffer": 12, + "CallableDataNV": 5328, + "IncomingCallableDataNV": 5329, + "RayPayloadNV": 5338, + "HitAttributeNV": 5339, + "IncomingRayPayloadNV": 5342, + "ShaderRecordBufferNV": 5343, + "PhysicalStorageBufferEXT": 5349 } }, { @@ -314,7 +347,11 @@ "Offset": 4, "ConstOffsets": 5, "Sample": 6, - "MinLod": 7 + "MinLod": 7, + "MakeTexelAvailableKHR": 8, + "MakeTexelVisibleKHR": 9, + "NonPrivateTexelKHR": 10, + "VolatileTexelKHR": 11 } }, { @@ -423,11 +460,24 @@ "InputAttachmentIndex": 43, "Alignment": 44, "MaxByteOffset": 45, + "AlignmentId": 46, + "MaxByteOffsetId": 47, + "NoSignedWrap": 4469, + "NoUnsignedWrap": 4470, "ExplicitInterpAMD": 4999, "OverrideCoverageNV": 5248, "PassthroughNV": 5250, "ViewportRelativeNV": 5252, - "SecondaryViewportRelativeNV": 5256 + "SecondaryViewportRelativeNV": 5256, + "PerPrimitiveNV": 5271, + "PerViewNV": 5272, + "PerTaskNV": 5273, + "PerVertexNV": 5285, + "NonUniformEXT": 5300, + "RestrictPointerEXT": 5355, + "AliasedPointerEXT": 5356, + "HlslCounterBufferGOOGLE": 5634, + "HlslSemanticGOOGLE": 5635 } }, { @@ -476,10 +526,15 @@ "SubgroupLocalInvocationId": 41, "VertexIndex": 42, "InstanceIndex": 43, + "SubgroupEqMask": 4416, "SubgroupEqMaskKHR": 4416, + "SubgroupGeMask": 4417, "SubgroupGeMaskKHR": 4417, + "SubgroupGtMask": 4418, "SubgroupGtMaskKHR": 4418, + "SubgroupLeMask": 4419, "SubgroupLeMaskKHR": 4419, + "SubgroupLtMask": 4420, "SubgroupLtMaskKHR": 4420, "BaseVertex": 4424, "BaseInstance": 4425, @@ -498,7 +553,36 @@ "SecondaryPositionNV": 5257, "SecondaryViewportMaskNV": 5258, "PositionPerViewNV": 5261, - "ViewportMaskPerViewNV": 5262 + "ViewportMaskPerViewNV": 5262, + "FullyCoveredEXT": 5264, + "TaskCountNV": 5274, + "PrimitiveCountNV": 5275, + "PrimitiveIndicesNV": 5276, + "ClipDistancePerViewNV": 5277, + "CullDistancePerViewNV": 5278, + "LayerPerViewNV": 5279, + "MeshViewCountNV": 5280, + "MeshViewIndicesNV": 5281, + "BaryCoordNV": 5286, + "BaryCoordNoPerspNV": 5287, + "FragSizeEXT": 5292, + "FragmentSizeNV": 5292, + "FragInvocationCountEXT": 5293, + "InvocationsPerPixelNV": 5293, + "LaunchIdNV": 5319, + "LaunchSizeNV": 5320, + "WorldRayOriginNV": 5321, + "WorldRayDirectionNV": 5322, + "ObjectRayOriginNV": 5323, + "ObjectRayDirectionNV": 5324, + "RayTminNV": 5325, + "RayTmaxNV": 5326, + "InstanceCustomIndexNV": 5327, + "ObjectToWorldNV": 5330, + "WorldToObjectNV": 5331, + "HitTNV": 5332, + "HitKindNV": 5333, + "IncomingRayFlagsNV": 5351 } }, { @@ -546,7 +630,10 @@ "WorkgroupMemory": 8, "CrossWorkgroupMemory": 9, "AtomicCounterMemory": 10, - "ImageMemory": 11 + "ImageMemory": 11, + "OutputMemoryKHR": 12, + "MakeAvailableKHR": 13, + "MakeVisibleKHR": 14 } }, { @@ -556,7 +643,10 @@ { "Volatile": 0, "Aligned": 1, - "Nontemporal": 2 + "Nontemporal": 2, + "MakePointerAvailableKHR": 3, + "MakePointerVisibleKHR": 4, + "NonPrivatePointerKHR": 5 } }, { @@ -568,7 +658,8 @@ "Device": 1, "Workgroup": 2, "Subgroup": 3, - "Invocation": 4 + "Invocation": 4, + "QueueFamilyKHR": 5 } }, { @@ -578,7 +669,11 @@ { "Reduce": 0, "InclusiveScan": 1, - "ExclusiveScan": 2 + "ExclusiveScan": 2, + "ClusteredReduce": 3, + "PartitionedReduceNV": 6, + "PartitionedInclusiveScanNV": 7, + "PartitionedExclusiveScanNV": 8 } }, { @@ -663,6 +758,14 @@ "SubgroupDispatch": 58, "NamedBarrier": 59, "PipeStorage": 60, + "GroupNonUniform": 61, + "GroupNonUniformVote": 62, + "GroupNonUniformArithmetic": 63, + "GroupNonUniformBallot": 64, + "GroupNonUniformShuffle": 65, + "GroupNonUniformShuffleRelative": 66, + "GroupNonUniformClustered": 67, + "GroupNonUniformQuad": 68, "SubgroupBallotKHR": 4423, "DrawParameters": 4427, "SubgroupVoteKHR": 4431, @@ -678,6 +781,15 @@ "VariablePointers": 4442, "AtomicStorageOps": 4445, "SampleMaskPostDepthCoverage": 4447, + "StorageBuffer8BitAccess": 4448, + "UniformAndStorageBuffer8BitAccess": 4449, + "StoragePushConstant8": 4450, + "DenormPreserve": 4464, + "DenormFlushToZero": 4465, + "SignedZeroInfNanPreserve": 4466, + "RoundingModeRTE": 4467, + "RoundingModeRTZ": 4468, + "Float16ImageAMD": 5008, "ImageGatherBiasLodAMD": 5009, "FragmentMaskAMD": 5010, "StencilExportEXT": 5013, @@ -689,6 +801,31 @@ "ShaderViewportMaskNV": 5255, "ShaderStereoViewNV": 5259, "PerViewAttributesNV": 5260, + "FragmentFullyCoveredEXT": 5265, + "MeshShadingNV": 5266, + "ImageFootprintNV": 5282, + "FragmentBarycentricNV": 5284, + "ComputeDerivativeGroupQuadsNV": 5288, + "FragmentDensityEXT": 5291, + "ShadingRateNV": 5291, + "GroupNonUniformPartitionedNV": 5297, + "ShaderNonUniformEXT": 5301, + "RuntimeDescriptorArrayEXT": 5302, + "InputAttachmentArrayDynamicIndexingEXT": 5303, + "UniformTexelBufferArrayDynamicIndexingEXT": 5304, + "StorageTexelBufferArrayDynamicIndexingEXT": 5305, + "UniformBufferArrayNonUniformIndexingEXT": 5306, + "SampledImageArrayNonUniformIndexingEXT": 5307, + "StorageBufferArrayNonUniformIndexingEXT": 5308, + "StorageImageArrayNonUniformIndexingEXT": 5309, + "InputAttachmentArrayNonUniformIndexingEXT": 5310, + "UniformTexelBufferArrayNonUniformIndexingEXT": 5311, + "StorageTexelBufferArrayNonUniformIndexingEXT": 5312, + "RayTracingNV": 5340, + "VulkanMemoryModelKHR": 5345, + "VulkanMemoryModelDeviceScopeKHR": 5346, + "PhysicalStorageBufferAddressesEXT": 5347, + "ComputeDerivativeGroupLinearNV": 5350, "SubgroupShuffleINTEL": 5568, "SubgroupBufferBlockIOINTEL": 5569, "SubgroupImageBlockIOINTEL": 5570 @@ -1003,6 +1140,42 @@ "OpNamedBarrierInitialize": 328, "OpMemoryNamedBarrier": 329, "OpModuleProcessed": 330, + "OpExecutionModeId": 331, + "OpDecorateId": 332, + "OpGroupNonUniformElect": 333, + "OpGroupNonUniformAll": 334, + "OpGroupNonUniformAny": 335, + "OpGroupNonUniformAllEqual": 336, + "OpGroupNonUniformBroadcast": 337, + "OpGroupNonUniformBroadcastFirst": 338, + "OpGroupNonUniformBallot": 339, + "OpGroupNonUniformInverseBallot": 340, + "OpGroupNonUniformBallotBitExtract": 341, + "OpGroupNonUniformBallotBitCount": 342, + "OpGroupNonUniformBallotFindLSB": 343, + "OpGroupNonUniformBallotFindMSB": 344, + "OpGroupNonUniformShuffle": 345, + "OpGroupNonUniformShuffleXor": 346, + "OpGroupNonUniformShuffleUp": 347, + "OpGroupNonUniformShuffleDown": 348, + "OpGroupNonUniformIAdd": 349, + "OpGroupNonUniformFAdd": 350, + "OpGroupNonUniformIMul": 351, + "OpGroupNonUniformFMul": 352, + "OpGroupNonUniformSMin": 353, + "OpGroupNonUniformUMin": 354, + "OpGroupNonUniformFMin": 355, + "OpGroupNonUniformSMax": 356, + "OpGroupNonUniformUMax": 357, + "OpGroupNonUniformFMax": 358, + "OpGroupNonUniformBitwiseAnd": 359, + "OpGroupNonUniformBitwiseOr": 360, + "OpGroupNonUniformBitwiseXor": 361, + "OpGroupNonUniformLogicalAnd": 362, + "OpGroupNonUniformLogicalOr": 363, + "OpGroupNonUniformLogicalXor": 364, + "OpGroupNonUniformQuadBroadcast": 365, + "OpGroupNonUniformQuadSwap": 366, "OpSubgroupBallotKHR": 4421, "OpSubgroupFirstInvocationKHR": 4422, "OpSubgroupAllKHR": 4428, @@ -1019,6 +1192,15 @@ "OpGroupSMaxNonUniformAMD": 5007, "OpFragmentMaskFetchAMD": 5011, "OpFragmentFetchAMD": 5012, + "OpImageSampleFootprintNV": 5283, + "OpGroupNonUniformPartitionNV": 5296, + "OpWritePackedPrimitiveIndices4x8NV": 5299, + "OpReportIntersectionNV": 5334, + "OpIgnoreIntersectionNV": 5335, + "OpTerminateRayNV": 5336, + "OpTraceNV": 5337, + "OpTypeAccelerationStructureNV": 5341, + "OpExecuteCallableNV": 5344, "OpSubgroupShuffleINTEL": 5571, "OpSubgroupShuffleDownINTEL": 5572, "OpSubgroupShuffleUpINTEL": 5573, @@ -1026,7 +1208,9 @@ "OpSubgroupBlockReadINTEL": 5575, "OpSubgroupBlockWriteINTEL": 5576, "OpSubgroupImageBlockReadINTEL": 5577, - "OpSubgroupImageBlockWriteINTEL": 5578 + "OpSubgroupImageBlockWriteINTEL": 5578, + "OpDecorateStringGOOGLE": 5632, + "OpMemberDecorateStringGOOGLE": 5633 } } ] diff --git a/ext/vulkan/spirv.lua b/ext/vulkan/spirv.lua index 44688596cd..f74224f118 100644 --- a/ext/vulkan/spirv.lua +++ b/ext/vulkan/spirv.lua @@ -1,4 +1,4 @@ --- Copyright (c) 2014-2017 The Khronos Group Inc. +-- Copyright (c) 2014-2019 The Khronos Group Inc. -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and/or associated documentation files (the "Materials"), @@ -26,13 +26,16 @@ -- the Binary Section of the SPIR-V specification. -- Enumeration tokens for SPIR-V, in various styles: --- C, C++, C++11, JSON, Lua, Python +-- C, C++, C++11, JSON, Lua, Python, C#, D -- -- - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL -- - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL -- - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL -- - Lua will use tables, e.g.: spv.SourceLanguage.GLSL -- - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL'] +-- - C# will use enum classes in the Specification class located in the "Spv" namespace, +-- e.g.: Spv.Specification.SourceLanguage.GLSL +-- - D will have tokens under the "spv" module, e.g: spv.SourceLanguage.GLSL -- -- Some tokens act like mask values, which can be OR'd together, -- while others are mutually exclusive. The mask-like ones have @@ -41,8 +44,8 @@ spv = { MagicNumber = 0x07230203, - Version = 0x00010100, - Revision = 8, + Version = 0x00010300, + Revision = 6, OpCodeMask = 0xffff, WordCountShift = 16, @@ -63,18 +66,28 @@ spv = { Fragment = 4, GLCompute = 5, Kernel = 6, + TaskNV = 5267, + MeshNV = 5268, + RayGenerationNV = 5313, + IntersectionNV = 5314, + AnyHitNV = 5315, + ClosestHitNV = 5316, + MissNV = 5317, + CallableNV = 5318, }, AddressingModel = { Logical = 0, Physical32 = 1, Physical64 = 2, + PhysicalStorageBuffer64EXT = 5348, }, MemoryModel = { Simple = 0, GLSL450 = 1, OpenCL = 2, + VulkanKHR = 3, }, ExecutionMode = { @@ -113,8 +126,21 @@ spv = { Finalizer = 34, SubgroupSize = 35, SubgroupsPerWorkgroup = 36, + SubgroupsPerWorkgroupId = 37, + LocalSizeId = 38, + LocalSizeHintId = 39, PostDepthCoverage = 4446, + DenormPreserve = 4459, + DenormFlushToZero = 4460, + SignedZeroInfNanPreserve = 4461, + RoundingModeRTE = 4462, + RoundingModeRTZ = 4463, StencilRefReplacingEXT = 5027, + OutputLinesNV = 5269, + OutputPrimitivesNV = 5270, + DerivativeGroupQuadsNV = 5289, + DerivativeGroupLinearNV = 5290, + OutputTrianglesNV = 5298, }, StorageClass = { @@ -131,6 +157,13 @@ spv = { AtomicCounter = 10, Image = 11, StorageBuffer = 12, + CallableDataNV = 5328, + IncomingCallableDataNV = 5329, + RayPayloadNV = 5338, + HitAttributeNV = 5339, + IncomingRayPayloadNV = 5342, + ShaderRecordBufferNV = 5343, + PhysicalStorageBufferEXT = 5349, }, Dim = { @@ -251,6 +284,10 @@ spv = { ConstOffsets = 5, Sample = 6, MinLod = 7, + MakeTexelAvailableKHR = 8, + MakeTexelVisibleKHR = 9, + NonPrivateTexelKHR = 10, + VolatileTexelKHR = 11, }, ImageOperandsMask = { @@ -263,6 +300,10 @@ spv = { ConstOffsets = 0x00000020, Sample = 0x00000040, MinLod = 0x00000080, + MakeTexelAvailableKHR = 0x00000100, + MakeTexelVisibleKHR = 0x00000200, + NonPrivateTexelKHR = 0x00000400, + VolatileTexelKHR = 0x00000800, }, FPFastMathModeShift = { @@ -356,11 +397,24 @@ spv = { InputAttachmentIndex = 43, Alignment = 44, MaxByteOffset = 45, + AlignmentId = 46, + MaxByteOffsetId = 47, + NoSignedWrap = 4469, + NoUnsignedWrap = 4470, ExplicitInterpAMD = 4999, OverrideCoverageNV = 5248, PassthroughNV = 5250, ViewportRelativeNV = 5252, SecondaryViewportRelativeNV = 5256, + PerPrimitiveNV = 5271, + PerViewNV = 5272, + PerTaskNV = 5273, + PerVertexNV = 5285, + NonUniformEXT = 5300, + RestrictPointerEXT = 5355, + AliasedPointerEXT = 5356, + HlslCounterBufferGOOGLE = 5634, + HlslSemanticGOOGLE = 5635, }, BuiltIn = { @@ -405,10 +459,15 @@ spv = { SubgroupLocalInvocationId = 41, VertexIndex = 42, InstanceIndex = 43, + SubgroupEqMask = 4416, SubgroupEqMaskKHR = 4416, + SubgroupGeMask = 4417, SubgroupGeMaskKHR = 4417, + SubgroupGtMask = 4418, SubgroupGtMaskKHR = 4418, + SubgroupLeMask = 4419, SubgroupLeMaskKHR = 4419, + SubgroupLtMask = 4420, SubgroupLtMaskKHR = 4420, BaseVertex = 4424, BaseInstance = 4425, @@ -428,6 +487,35 @@ spv = { SecondaryViewportMaskNV = 5258, PositionPerViewNV = 5261, ViewportMaskPerViewNV = 5262, + FullyCoveredEXT = 5264, + TaskCountNV = 5274, + PrimitiveCountNV = 5275, + PrimitiveIndicesNV = 5276, + ClipDistancePerViewNV = 5277, + CullDistancePerViewNV = 5278, + LayerPerViewNV = 5279, + MeshViewCountNV = 5280, + MeshViewIndicesNV = 5281, + BaryCoordNV = 5286, + BaryCoordNoPerspNV = 5287, + FragSizeEXT = 5292, + FragmentSizeNV = 5292, + FragInvocationCountEXT = 5293, + InvocationsPerPixelNV = 5293, + LaunchIdNV = 5319, + LaunchSizeNV = 5320, + WorldRayOriginNV = 5321, + WorldRayDirectionNV = 5322, + ObjectRayOriginNV = 5323, + ObjectRayDirectionNV = 5324, + RayTminNV = 5325, + RayTmaxNV = 5326, + InstanceCustomIndexNV = 5327, + ObjectToWorldNV = 5330, + WorldToObjectNV = 5331, + HitTNV = 5332, + HitKindNV = 5333, + IncomingRayFlagsNV = 5351, }, SelectionControlShift = { @@ -482,6 +570,9 @@ spv = { CrossWorkgroupMemory = 9, AtomicCounterMemory = 10, ImageMemory = 11, + OutputMemoryKHR = 12, + MakeAvailableKHR = 13, + MakeVisibleKHR = 14, }, MemorySemanticsMask = { @@ -496,12 +587,18 @@ spv = { CrossWorkgroupMemory = 0x00000200, AtomicCounterMemory = 0x00000400, ImageMemory = 0x00000800, + OutputMemoryKHR = 0x00001000, + MakeAvailableKHR = 0x00002000, + MakeVisibleKHR = 0x00004000, }, MemoryAccessShift = { Volatile = 0, Aligned = 1, Nontemporal = 2, + MakePointerAvailableKHR = 3, + MakePointerVisibleKHR = 4, + NonPrivatePointerKHR = 5, }, MemoryAccessMask = { @@ -509,6 +606,9 @@ spv = { Volatile = 0x00000001, Aligned = 0x00000002, Nontemporal = 0x00000004, + MakePointerAvailableKHR = 0x00000008, + MakePointerVisibleKHR = 0x00000010, + NonPrivatePointerKHR = 0x00000020, }, Scope = { @@ -517,12 +617,17 @@ spv = { Workgroup = 2, Subgroup = 3, Invocation = 4, + QueueFamilyKHR = 5, }, GroupOperation = { Reduce = 0, InclusiveScan = 1, ExclusiveScan = 2, + ClusteredReduce = 3, + PartitionedReduceNV = 6, + PartitionedInclusiveScanNV = 7, + PartitionedExclusiveScanNV = 8, }, KernelEnqueueFlags = { @@ -600,6 +705,14 @@ spv = { SubgroupDispatch = 58, NamedBarrier = 59, PipeStorage = 60, + GroupNonUniform = 61, + GroupNonUniformVote = 62, + GroupNonUniformArithmetic = 63, + GroupNonUniformBallot = 64, + GroupNonUniformShuffle = 65, + GroupNonUniformShuffleRelative = 66, + GroupNonUniformClustered = 67, + GroupNonUniformQuad = 68, SubgroupBallotKHR = 4423, DrawParameters = 4427, SubgroupVoteKHR = 4431, @@ -615,6 +728,15 @@ spv = { VariablePointers = 4442, AtomicStorageOps = 4445, SampleMaskPostDepthCoverage = 4447, + StorageBuffer8BitAccess = 4448, + UniformAndStorageBuffer8BitAccess = 4449, + StoragePushConstant8 = 4450, + DenormPreserve = 4464, + DenormFlushToZero = 4465, + SignedZeroInfNanPreserve = 4466, + RoundingModeRTE = 4467, + RoundingModeRTZ = 4468, + Float16ImageAMD = 5008, ImageGatherBiasLodAMD = 5009, FragmentMaskAMD = 5010, StencilExportEXT = 5013, @@ -626,6 +748,31 @@ spv = { ShaderViewportMaskNV = 5255, ShaderStereoViewNV = 5259, PerViewAttributesNV = 5260, + FragmentFullyCoveredEXT = 5265, + MeshShadingNV = 5266, + ImageFootprintNV = 5282, + FragmentBarycentricNV = 5284, + ComputeDerivativeGroupQuadsNV = 5288, + FragmentDensityEXT = 5291, + ShadingRateNV = 5291, + GroupNonUniformPartitionedNV = 5297, + ShaderNonUniformEXT = 5301, + RuntimeDescriptorArrayEXT = 5302, + InputAttachmentArrayDynamicIndexingEXT = 5303, + UniformTexelBufferArrayDynamicIndexingEXT = 5304, + StorageTexelBufferArrayDynamicIndexingEXT = 5305, + UniformBufferArrayNonUniformIndexingEXT = 5306, + SampledImageArrayNonUniformIndexingEXT = 5307, + StorageBufferArrayNonUniformIndexingEXT = 5308, + StorageImageArrayNonUniformIndexingEXT = 5309, + InputAttachmentArrayNonUniformIndexingEXT = 5310, + UniformTexelBufferArrayNonUniformIndexingEXT = 5311, + StorageTexelBufferArrayNonUniformIndexingEXT = 5312, + RayTracingNV = 5340, + VulkanMemoryModelKHR = 5345, + VulkanMemoryModelDeviceScopeKHR = 5346, + PhysicalStorageBufferAddressesEXT = 5347, + ComputeDerivativeGroupLinearNV = 5350, SubgroupShuffleINTEL = 5568, SubgroupBufferBlockIOINTEL = 5569, SubgroupImageBlockIOINTEL = 5570, @@ -936,6 +1083,42 @@ spv = { OpNamedBarrierInitialize = 328, OpMemoryNamedBarrier = 329, OpModuleProcessed = 330, + OpExecutionModeId = 331, + OpDecorateId = 332, + OpGroupNonUniformElect = 333, + OpGroupNonUniformAll = 334, + OpGroupNonUniformAny = 335, + OpGroupNonUniformAllEqual = 336, + OpGroupNonUniformBroadcast = 337, + OpGroupNonUniformBroadcastFirst = 338, + OpGroupNonUniformBallot = 339, + OpGroupNonUniformInverseBallot = 340, + OpGroupNonUniformBallotBitExtract = 341, + OpGroupNonUniformBallotBitCount = 342, + OpGroupNonUniformBallotFindLSB = 343, + OpGroupNonUniformBallotFindMSB = 344, + OpGroupNonUniformShuffle = 345, + OpGroupNonUniformShuffleXor = 346, + OpGroupNonUniformShuffleUp = 347, + OpGroupNonUniformShuffleDown = 348, + OpGroupNonUniformIAdd = 349, + OpGroupNonUniformFAdd = 350, + OpGroupNonUniformIMul = 351, + OpGroupNonUniformFMul = 352, + OpGroupNonUniformSMin = 353, + OpGroupNonUniformUMin = 354, + OpGroupNonUniformFMin = 355, + OpGroupNonUniformSMax = 356, + OpGroupNonUniformUMax = 357, + OpGroupNonUniformFMax = 358, + OpGroupNonUniformBitwiseAnd = 359, + OpGroupNonUniformBitwiseOr = 360, + OpGroupNonUniformBitwiseXor = 361, + OpGroupNonUniformLogicalAnd = 362, + OpGroupNonUniformLogicalOr = 363, + OpGroupNonUniformLogicalXor = 364, + OpGroupNonUniformQuadBroadcast = 365, + OpGroupNonUniformQuadSwap = 366, OpSubgroupBallotKHR = 4421, OpSubgroupFirstInvocationKHR = 4422, OpSubgroupAllKHR = 4428, @@ -952,6 +1135,15 @@ spv = { OpGroupSMaxNonUniformAMD = 5007, OpFragmentMaskFetchAMD = 5011, OpFragmentFetchAMD = 5012, + OpImageSampleFootprintNV = 5283, + OpGroupNonUniformPartitionNV = 5296, + OpWritePackedPrimitiveIndices4x8NV = 5299, + OpReportIntersectionNV = 5334, + OpIgnoreIntersectionNV = 5335, + OpTerminateRayNV = 5336, + OpTraceNV = 5337, + OpTypeAccelerationStructureNV = 5341, + OpExecuteCallableNV = 5344, OpSubgroupShuffleINTEL = 5571, OpSubgroupShuffleDownINTEL = 5572, OpSubgroupShuffleUpINTEL = 5573, @@ -960,6 +1152,8 @@ spv = { OpSubgroupBlockWriteINTEL = 5576, OpSubgroupImageBlockReadINTEL = 5577, OpSubgroupImageBlockWriteINTEL = 5578, + OpDecorateStringGOOGLE = 5632, + OpMemberDecorateStringGOOGLE = 5633, }, } diff --git a/ext/vulkan/spirv.py b/ext/vulkan/spirv.py index d7d900cb1d..4b1a7eec1f 100644 --- a/ext/vulkan/spirv.py +++ b/ext/vulkan/spirv.py @@ -1,4 +1,4 @@ -# Copyright (c) 2014-2017 The Khronos Group Inc. +# Copyright (c) 2014-2019 The Khronos Group Inc. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and/or associated documentation files (the "Materials"), @@ -26,13 +26,16 @@ # the Binary Section of the SPIR-V specification. # Enumeration tokens for SPIR-V, in various styles: -# C, C++, C++11, JSON, Lua, Python +# C, C++, C++11, JSON, Lua, Python, C#, D # # - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL # - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL # - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL # - Lua will use tables, e.g.: spv.SourceLanguage.GLSL # - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL'] +# - C# will use enum classes in the Specification class located in the "Spv" namespace, +# e.g.: Spv.Specification.SourceLanguage.GLSL +# - D will have tokens under the "spv" module, e.g: spv.SourceLanguage.GLSL # # Some tokens act like mask values, which can be OR'd together, # while others are mutually exclusive. The mask-like ones have @@ -41,8 +44,8 @@ spv = { 'MagicNumber' : 0x07230203, - 'Version' : 0x00010100, - 'Revision' : 8, + 'Version' : 0x00010300, + 'Revision' : 6, 'OpCodeMask' : 0xffff, 'WordCountShift' : 16, @@ -63,18 +66,28 @@ spv = { 'Fragment' : 4, 'GLCompute' : 5, 'Kernel' : 6, + 'TaskNV' : 5267, + 'MeshNV' : 5268, + 'RayGenerationNV' : 5313, + 'IntersectionNV' : 5314, + 'AnyHitNV' : 5315, + 'ClosestHitNV' : 5316, + 'MissNV' : 5317, + 'CallableNV' : 5318, }, 'AddressingModel' : { 'Logical' : 0, 'Physical32' : 1, 'Physical64' : 2, + 'PhysicalStorageBuffer64EXT' : 5348, }, 'MemoryModel' : { 'Simple' : 0, 'GLSL450' : 1, 'OpenCL' : 2, + 'VulkanKHR' : 3, }, 'ExecutionMode' : { @@ -113,8 +126,21 @@ spv = { 'Finalizer' : 34, 'SubgroupSize' : 35, 'SubgroupsPerWorkgroup' : 36, + 'SubgroupsPerWorkgroupId' : 37, + 'LocalSizeId' : 38, + 'LocalSizeHintId' : 39, 'PostDepthCoverage' : 4446, + 'DenormPreserve' : 4459, + 'DenormFlushToZero' : 4460, + 'SignedZeroInfNanPreserve' : 4461, + 'RoundingModeRTE' : 4462, + 'RoundingModeRTZ' : 4463, 'StencilRefReplacingEXT' : 5027, + 'OutputLinesNV' : 5269, + 'OutputPrimitivesNV' : 5270, + 'DerivativeGroupQuadsNV' : 5289, + 'DerivativeGroupLinearNV' : 5290, + 'OutputTrianglesNV' : 5298, }, 'StorageClass' : { @@ -131,6 +157,13 @@ spv = { 'AtomicCounter' : 10, 'Image' : 11, 'StorageBuffer' : 12, + 'CallableDataNV' : 5328, + 'IncomingCallableDataNV' : 5329, + 'RayPayloadNV' : 5338, + 'HitAttributeNV' : 5339, + 'IncomingRayPayloadNV' : 5342, + 'ShaderRecordBufferNV' : 5343, + 'PhysicalStorageBufferEXT' : 5349, }, 'Dim' : { @@ -251,6 +284,10 @@ spv = { 'ConstOffsets' : 5, 'Sample' : 6, 'MinLod' : 7, + 'MakeTexelAvailableKHR' : 8, + 'MakeTexelVisibleKHR' : 9, + 'NonPrivateTexelKHR' : 10, + 'VolatileTexelKHR' : 11, }, 'ImageOperandsMask' : { @@ -263,6 +300,10 @@ spv = { 'ConstOffsets' : 0x00000020, 'Sample' : 0x00000040, 'MinLod' : 0x00000080, + 'MakeTexelAvailableKHR' : 0x00000100, + 'MakeTexelVisibleKHR' : 0x00000200, + 'NonPrivateTexelKHR' : 0x00000400, + 'VolatileTexelKHR' : 0x00000800, }, 'FPFastMathModeShift' : { @@ -356,11 +397,24 @@ spv = { 'InputAttachmentIndex' : 43, 'Alignment' : 44, 'MaxByteOffset' : 45, + 'AlignmentId' : 46, + 'MaxByteOffsetId' : 47, + 'NoSignedWrap' : 4469, + 'NoUnsignedWrap' : 4470, 'ExplicitInterpAMD' : 4999, 'OverrideCoverageNV' : 5248, 'PassthroughNV' : 5250, 'ViewportRelativeNV' : 5252, 'SecondaryViewportRelativeNV' : 5256, + 'PerPrimitiveNV' : 5271, + 'PerViewNV' : 5272, + 'PerTaskNV' : 5273, + 'PerVertexNV' : 5285, + 'NonUniformEXT' : 5300, + 'RestrictPointerEXT' : 5355, + 'AliasedPointerEXT' : 5356, + 'HlslCounterBufferGOOGLE' : 5634, + 'HlslSemanticGOOGLE' : 5635, }, 'BuiltIn' : { @@ -405,10 +459,15 @@ spv = { 'SubgroupLocalInvocationId' : 41, 'VertexIndex' : 42, 'InstanceIndex' : 43, + 'SubgroupEqMask' : 4416, 'SubgroupEqMaskKHR' : 4416, + 'SubgroupGeMask' : 4417, 'SubgroupGeMaskKHR' : 4417, + 'SubgroupGtMask' : 4418, 'SubgroupGtMaskKHR' : 4418, + 'SubgroupLeMask' : 4419, 'SubgroupLeMaskKHR' : 4419, + 'SubgroupLtMask' : 4420, 'SubgroupLtMaskKHR' : 4420, 'BaseVertex' : 4424, 'BaseInstance' : 4425, @@ -428,6 +487,35 @@ spv = { 'SecondaryViewportMaskNV' : 5258, 'PositionPerViewNV' : 5261, 'ViewportMaskPerViewNV' : 5262, + 'FullyCoveredEXT' : 5264, + 'TaskCountNV' : 5274, + 'PrimitiveCountNV' : 5275, + 'PrimitiveIndicesNV' : 5276, + 'ClipDistancePerViewNV' : 5277, + 'CullDistancePerViewNV' : 5278, + 'LayerPerViewNV' : 5279, + 'MeshViewCountNV' : 5280, + 'MeshViewIndicesNV' : 5281, + 'BaryCoordNV' : 5286, + 'BaryCoordNoPerspNV' : 5287, + 'FragSizeEXT' : 5292, + 'FragmentSizeNV' : 5292, + 'FragInvocationCountEXT' : 5293, + 'InvocationsPerPixelNV' : 5293, + 'LaunchIdNV' : 5319, + 'LaunchSizeNV' : 5320, + 'WorldRayOriginNV' : 5321, + 'WorldRayDirectionNV' : 5322, + 'ObjectRayOriginNV' : 5323, + 'ObjectRayDirectionNV' : 5324, + 'RayTminNV' : 5325, + 'RayTmaxNV' : 5326, + 'InstanceCustomIndexNV' : 5327, + 'ObjectToWorldNV' : 5330, + 'WorldToObjectNV' : 5331, + 'HitTNV' : 5332, + 'HitKindNV' : 5333, + 'IncomingRayFlagsNV' : 5351, }, 'SelectionControlShift' : { @@ -482,6 +570,9 @@ spv = { 'CrossWorkgroupMemory' : 9, 'AtomicCounterMemory' : 10, 'ImageMemory' : 11, + 'OutputMemoryKHR' : 12, + 'MakeAvailableKHR' : 13, + 'MakeVisibleKHR' : 14, }, 'MemorySemanticsMask' : { @@ -496,12 +587,18 @@ spv = { 'CrossWorkgroupMemory' : 0x00000200, 'AtomicCounterMemory' : 0x00000400, 'ImageMemory' : 0x00000800, + 'OutputMemoryKHR' : 0x00001000, + 'MakeAvailableKHR' : 0x00002000, + 'MakeVisibleKHR' : 0x00004000, }, 'MemoryAccessShift' : { 'Volatile' : 0, 'Aligned' : 1, 'Nontemporal' : 2, + 'MakePointerAvailableKHR' : 3, + 'MakePointerVisibleKHR' : 4, + 'NonPrivatePointerKHR' : 5, }, 'MemoryAccessMask' : { @@ -509,6 +606,9 @@ spv = { 'Volatile' : 0x00000001, 'Aligned' : 0x00000002, 'Nontemporal' : 0x00000004, + 'MakePointerAvailableKHR' : 0x00000008, + 'MakePointerVisibleKHR' : 0x00000010, + 'NonPrivatePointerKHR' : 0x00000020, }, 'Scope' : { @@ -517,12 +617,17 @@ spv = { 'Workgroup' : 2, 'Subgroup' : 3, 'Invocation' : 4, + 'QueueFamilyKHR' : 5, }, 'GroupOperation' : { 'Reduce' : 0, 'InclusiveScan' : 1, 'ExclusiveScan' : 2, + 'ClusteredReduce' : 3, + 'PartitionedReduceNV' : 6, + 'PartitionedInclusiveScanNV' : 7, + 'PartitionedExclusiveScanNV' : 8, }, 'KernelEnqueueFlags' : { @@ -600,6 +705,14 @@ spv = { 'SubgroupDispatch' : 58, 'NamedBarrier' : 59, 'PipeStorage' : 60, + 'GroupNonUniform' : 61, + 'GroupNonUniformVote' : 62, + 'GroupNonUniformArithmetic' : 63, + 'GroupNonUniformBallot' : 64, + 'GroupNonUniformShuffle' : 65, + 'GroupNonUniformShuffleRelative' : 66, + 'GroupNonUniformClustered' : 67, + 'GroupNonUniformQuad' : 68, 'SubgroupBallotKHR' : 4423, 'DrawParameters' : 4427, 'SubgroupVoteKHR' : 4431, @@ -615,6 +728,15 @@ spv = { 'VariablePointers' : 4442, 'AtomicStorageOps' : 4445, 'SampleMaskPostDepthCoverage' : 4447, + 'StorageBuffer8BitAccess' : 4448, + 'UniformAndStorageBuffer8BitAccess' : 4449, + 'StoragePushConstant8' : 4450, + 'DenormPreserve' : 4464, + 'DenormFlushToZero' : 4465, + 'SignedZeroInfNanPreserve' : 4466, + 'RoundingModeRTE' : 4467, + 'RoundingModeRTZ' : 4468, + 'Float16ImageAMD' : 5008, 'ImageGatherBiasLodAMD' : 5009, 'FragmentMaskAMD' : 5010, 'StencilExportEXT' : 5013, @@ -626,6 +748,31 @@ spv = { 'ShaderViewportMaskNV' : 5255, 'ShaderStereoViewNV' : 5259, 'PerViewAttributesNV' : 5260, + 'FragmentFullyCoveredEXT' : 5265, + 'MeshShadingNV' : 5266, + 'ImageFootprintNV' : 5282, + 'FragmentBarycentricNV' : 5284, + 'ComputeDerivativeGroupQuadsNV' : 5288, + 'FragmentDensityEXT' : 5291, + 'ShadingRateNV' : 5291, + 'GroupNonUniformPartitionedNV' : 5297, + 'ShaderNonUniformEXT' : 5301, + 'RuntimeDescriptorArrayEXT' : 5302, + 'InputAttachmentArrayDynamicIndexingEXT' : 5303, + 'UniformTexelBufferArrayDynamicIndexingEXT' : 5304, + 'StorageTexelBufferArrayDynamicIndexingEXT' : 5305, + 'UniformBufferArrayNonUniformIndexingEXT' : 5306, + 'SampledImageArrayNonUniformIndexingEXT' : 5307, + 'StorageBufferArrayNonUniformIndexingEXT' : 5308, + 'StorageImageArrayNonUniformIndexingEXT' : 5309, + 'InputAttachmentArrayNonUniformIndexingEXT' : 5310, + 'UniformTexelBufferArrayNonUniformIndexingEXT' : 5311, + 'StorageTexelBufferArrayNonUniformIndexingEXT' : 5312, + 'RayTracingNV' : 5340, + 'VulkanMemoryModelKHR' : 5345, + 'VulkanMemoryModelDeviceScopeKHR' : 5346, + 'PhysicalStorageBufferAddressesEXT' : 5347, + 'ComputeDerivativeGroupLinearNV' : 5350, 'SubgroupShuffleINTEL' : 5568, 'SubgroupBufferBlockIOINTEL' : 5569, 'SubgroupImageBlockIOINTEL' : 5570, @@ -936,6 +1083,42 @@ spv = { 'OpNamedBarrierInitialize' : 328, 'OpMemoryNamedBarrier' : 329, 'OpModuleProcessed' : 330, + 'OpExecutionModeId' : 331, + 'OpDecorateId' : 332, + 'OpGroupNonUniformElect' : 333, + 'OpGroupNonUniformAll' : 334, + 'OpGroupNonUniformAny' : 335, + 'OpGroupNonUniformAllEqual' : 336, + 'OpGroupNonUniformBroadcast' : 337, + 'OpGroupNonUniformBroadcastFirst' : 338, + 'OpGroupNonUniformBallot' : 339, + 'OpGroupNonUniformInverseBallot' : 340, + 'OpGroupNonUniformBallotBitExtract' : 341, + 'OpGroupNonUniformBallotBitCount' : 342, + 'OpGroupNonUniformBallotFindLSB' : 343, + 'OpGroupNonUniformBallotFindMSB' : 344, + 'OpGroupNonUniformShuffle' : 345, + 'OpGroupNonUniformShuffleXor' : 346, + 'OpGroupNonUniformShuffleUp' : 347, + 'OpGroupNonUniformShuffleDown' : 348, + 'OpGroupNonUniformIAdd' : 349, + 'OpGroupNonUniformFAdd' : 350, + 'OpGroupNonUniformIMul' : 351, + 'OpGroupNonUniformFMul' : 352, + 'OpGroupNonUniformSMin' : 353, + 'OpGroupNonUniformUMin' : 354, + 'OpGroupNonUniformFMin' : 355, + 'OpGroupNonUniformSMax' : 356, + 'OpGroupNonUniformUMax' : 357, + 'OpGroupNonUniformFMax' : 358, + 'OpGroupNonUniformBitwiseAnd' : 359, + 'OpGroupNonUniformBitwiseOr' : 360, + 'OpGroupNonUniformBitwiseXor' : 361, + 'OpGroupNonUniformLogicalAnd' : 362, + 'OpGroupNonUniformLogicalOr' : 363, + 'OpGroupNonUniformLogicalXor' : 364, + 'OpGroupNonUniformQuadBroadcast' : 365, + 'OpGroupNonUniformQuadSwap' : 366, 'OpSubgroupBallotKHR' : 4421, 'OpSubgroupFirstInvocationKHR' : 4422, 'OpSubgroupAllKHR' : 4428, @@ -952,6 +1135,15 @@ spv = { 'OpGroupSMaxNonUniformAMD' : 5007, 'OpFragmentMaskFetchAMD' : 5011, 'OpFragmentFetchAMD' : 5012, + 'OpImageSampleFootprintNV' : 5283, + 'OpGroupNonUniformPartitionNV' : 5296, + 'OpWritePackedPrimitiveIndices4x8NV' : 5299, + 'OpReportIntersectionNV' : 5334, + 'OpIgnoreIntersectionNV' : 5335, + 'OpTerminateRayNV' : 5336, + 'OpTraceNV' : 5337, + 'OpTypeAccelerationStructureNV' : 5341, + 'OpExecuteCallableNV' : 5344, 'OpSubgroupShuffleINTEL' : 5571, 'OpSubgroupShuffleDownINTEL' : 5572, 'OpSubgroupShuffleUpINTEL' : 5573, @@ -960,6 +1152,8 @@ spv = { 'OpSubgroupBlockWriteINTEL' : 5576, 'OpSubgroupImageBlockReadINTEL' : 5577, 'OpSubgroupImageBlockWriteINTEL' : 5578, + 'OpDecorateStringGOOGLE' : 5632, + 'OpMemberDecorateStringGOOGLE' : 5633, }, } diff --git a/ext/vulkan/vk_icd.h b/ext/vulkan/vk_icd.h index b8c7efcb6b..b935fa1786 100644 --- a/ext/vulkan/vk_icd.h +++ b/ext/vulkan/vk_icd.h @@ -44,12 +44,12 @@ #define CURRENT_LOADER_ICD_INTERFACE_VERSION 5 #define MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION 0 #define MIN_PHYS_DEV_EXTENSION_ICD_INTERFACE_VERSION 4 -typedef VkResult (VKAPI_PTR *PFN_vkNegotiateLoaderICDInterfaceVersion)(uint32_t *pVersion); +typedef VkResult(VKAPI_PTR *PFN_vkNegotiateLoaderICDInterfaceVersion)(uint32_t *pVersion); // This is defined in vk_layer.h which will be found by the loader, but if an ICD is building against this // file directly, it won't be found. #ifndef PFN_GetPhysicalDeviceProcAddr -typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName); +typedef PFN_vkVoidFunction(VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char *pName); #endif /* @@ -85,6 +85,9 @@ typedef enum { VK_ICD_WSI_PLATFORM_WIN32, VK_ICD_WSI_PLATFORM_XCB, VK_ICD_WSI_PLATFORM_XLIB, + VK_ICD_WSI_PLATFORM_ANDROID, + VK_ICD_WSI_PLATFORM_MACOS, + VK_ICD_WSI_PLATFORM_IOS, VK_ICD_WSI_PLATFORM_DISPLAY } VkIcdWsiPlatform; @@ -98,7 +101,7 @@ typedef struct { MirConnection *connection; MirSurface *mirSurface; } VkIcdSurfaceMir; -#endif // VK_USE_PLATFORM_MIR_KHR +#endif // VK_USE_PLATFORM_MIR_KHR #ifdef VK_USE_PLATFORM_WAYLAND_KHR typedef struct { @@ -106,7 +109,7 @@ typedef struct { struct wl_display *display; struct wl_surface *surface; } VkIcdSurfaceWayland; -#endif // VK_USE_PLATFORM_WAYLAND_KHR +#endif // VK_USE_PLATFORM_WAYLAND_KHR #ifdef VK_USE_PLATFORM_WIN32_KHR typedef struct { @@ -114,7 +117,7 @@ typedef struct { HINSTANCE hinstance; HWND hwnd; } VkIcdSurfaceWin32; -#endif // VK_USE_PLATFORM_WIN32_KHR +#endif // VK_USE_PLATFORM_WIN32_KHR #ifdef VK_USE_PLATFORM_XCB_KHR typedef struct { @@ -122,7 +125,7 @@ typedef struct { xcb_connection_t *connection; xcb_window_t window; } VkIcdSurfaceXcb; -#endif // VK_USE_PLATFORM_XCB_KHR +#endif // VK_USE_PLATFORM_XCB_KHR #ifdef VK_USE_PLATFORM_XLIB_KHR typedef struct { @@ -130,13 +133,28 @@ typedef struct { Display *dpy; Window window; } VkIcdSurfaceXlib; -#endif // VK_USE_PLATFORM_XLIB_KHR +#endif // VK_USE_PLATFORM_XLIB_KHR #ifdef VK_USE_PLATFORM_ANDROID_KHR typedef struct { - ANativeWindow* window; + VkIcdSurfaceBase base; + struct ANativeWindow *window; } VkIcdSurfaceAndroid; -#endif //VK_USE_PLATFORM_ANDROID_KHR +#endif // VK_USE_PLATFORM_ANDROID_KHR + +#ifdef VK_USE_PLATFORM_MACOS_MVK +typedef struct { + VkIcdSurfaceBase base; + const void *pView; +} VkIcdSurfaceMacOS; +#endif // VK_USE_PLATFORM_MACOS_MVK + +#ifdef VK_USE_PLATFORM_IOS_MVK +typedef struct { + VkIcdSurfaceBase base; + const void *pView; +} VkIcdSurfaceIOS; +#endif // VK_USE_PLATFORM_IOS_MVK typedef struct { VkIcdSurfaceBase base; @@ -149,4 +167,4 @@ typedef struct { VkExtent2D imageExtent; } VkIcdSurfaceDisplay; -#endif // VKICD_H +#endif // VKICD_H diff --git a/ext/vulkan/vk_layer.h b/ext/vulkan/vk_layer.h index e8300c37d4..823c88ab75 100644 --- a/ext/vulkan/vk_layer.h +++ b/ext/vulkan/vk_layer.h @@ -35,9 +35,6 @@ #define VK_LAYER_EXPORT #endif -// Definition for VkLayerDispatchTable and VkLayerInstanceDispatchTable now appear in externally generated header -#include "vk_layer_dispatch_table.h" - #define MAX_NUM_UNKNOWN_EXTS 250 // Loader-Layer version negotiation API. Versions add the following features: @@ -50,6 +47,9 @@ #define VK_CURRENT_CHAIN_VERSION 1 +// Typedef for use in the interfaces below +typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName); + // Version negotiation values typedef enum VkNegotiateLayerStructType { LAYER_NEGOTIATE_UNINTIALIZED = 0, diff --git a/ext/vulkan/vk_layer_dispatch_table.h b/ext/vulkan/vk_layer_dispatch_table.h deleted file mode 100644 index 572982dfd3..0000000000 --- a/ext/vulkan/vk_layer_dispatch_table.h +++ /dev/null @@ -1,507 +0,0 @@ -// *** THIS FILE IS GENERATED - DO NOT EDIT *** -// See loader_extension_generator.py for modifications - -/* - * Copyright (c) 2015-2017 The Khronos Group Inc. - * Copyright (c) 2015-2017 Valve Corporation - * Copyright (c) 2015-2017 LunarG, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Author: Mark Lobodzinski - * Author: Mark Young - */ - -#pragma once - -typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName); - -// Instance function pointer dispatch table -typedef struct VkLayerInstanceDispatchTable_ { - // Manually add in GetPhysicalDeviceProcAddr entry - PFN_GetPhysicalDeviceProcAddr GetPhysicalDeviceProcAddr; - - // ---- Core 1_0 commands - PFN_vkCreateInstance CreateInstance; - PFN_vkDestroyInstance DestroyInstance; - PFN_vkEnumeratePhysicalDevices EnumeratePhysicalDevices; - PFN_vkGetPhysicalDeviceFeatures GetPhysicalDeviceFeatures; - PFN_vkGetPhysicalDeviceFormatProperties GetPhysicalDeviceFormatProperties; - PFN_vkGetPhysicalDeviceImageFormatProperties GetPhysicalDeviceImageFormatProperties; - PFN_vkGetPhysicalDeviceProperties GetPhysicalDeviceProperties; - PFN_vkGetPhysicalDeviceQueueFamilyProperties GetPhysicalDeviceQueueFamilyProperties; - PFN_vkGetPhysicalDeviceMemoryProperties GetPhysicalDeviceMemoryProperties; - PFN_vkGetInstanceProcAddr GetInstanceProcAddr; - PFN_vkCreateDevice CreateDevice; - PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties; - PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties; - PFN_vkEnumerateInstanceLayerProperties EnumerateInstanceLayerProperties; - PFN_vkEnumerateDeviceLayerProperties EnumerateDeviceLayerProperties; - PFN_vkGetPhysicalDeviceSparseImageFormatProperties GetPhysicalDeviceSparseImageFormatProperties; - - // ---- Core 1_1 commands - PFN_vkEnumerateInstanceVersion EnumerateInstanceVersion; - PFN_vkEnumeratePhysicalDeviceGroups EnumeratePhysicalDeviceGroups; - PFN_vkGetPhysicalDeviceFeatures2 GetPhysicalDeviceFeatures2; - PFN_vkGetPhysicalDeviceProperties2 GetPhysicalDeviceProperties2; - PFN_vkGetPhysicalDeviceFormatProperties2 GetPhysicalDeviceFormatProperties2; - PFN_vkGetPhysicalDeviceImageFormatProperties2 GetPhysicalDeviceImageFormatProperties2; - PFN_vkGetPhysicalDeviceQueueFamilyProperties2 GetPhysicalDeviceQueueFamilyProperties2; - PFN_vkGetPhysicalDeviceMemoryProperties2 GetPhysicalDeviceMemoryProperties2; - PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 GetPhysicalDeviceSparseImageFormatProperties2; - PFN_vkGetPhysicalDeviceExternalBufferProperties GetPhysicalDeviceExternalBufferProperties; - PFN_vkGetPhysicalDeviceExternalFenceProperties GetPhysicalDeviceExternalFenceProperties; - PFN_vkGetPhysicalDeviceExternalSemaphoreProperties GetPhysicalDeviceExternalSemaphoreProperties; - - // ---- VK_KHR_surface extension commands - PFN_vkDestroySurfaceKHR DestroySurfaceKHR; - PFN_vkGetPhysicalDeviceSurfaceSupportKHR GetPhysicalDeviceSurfaceSupportKHR; - PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR GetPhysicalDeviceSurfaceCapabilitiesKHR; - PFN_vkGetPhysicalDeviceSurfaceFormatsKHR GetPhysicalDeviceSurfaceFormatsKHR; - PFN_vkGetPhysicalDeviceSurfacePresentModesKHR GetPhysicalDeviceSurfacePresentModesKHR; - - // ---- VK_KHR_swapchain extension commands - PFN_vkGetPhysicalDevicePresentRectanglesKHR GetPhysicalDevicePresentRectanglesKHR; - - // ---- VK_KHR_display extension commands - PFN_vkGetPhysicalDeviceDisplayPropertiesKHR GetPhysicalDeviceDisplayPropertiesKHR; - PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR GetPhysicalDeviceDisplayPlanePropertiesKHR; - PFN_vkGetDisplayPlaneSupportedDisplaysKHR GetDisplayPlaneSupportedDisplaysKHR; - PFN_vkGetDisplayModePropertiesKHR GetDisplayModePropertiesKHR; - PFN_vkCreateDisplayModeKHR CreateDisplayModeKHR; - PFN_vkGetDisplayPlaneCapabilitiesKHR GetDisplayPlaneCapabilitiesKHR; - PFN_vkCreateDisplayPlaneSurfaceKHR CreateDisplayPlaneSurfaceKHR; - - // ---- VK_KHR_xlib_surface extension commands -#ifdef VK_USE_PLATFORM_XLIB_KHR - PFN_vkCreateXlibSurfaceKHR CreateXlibSurfaceKHR; -#endif // VK_USE_PLATFORM_XLIB_KHR -#ifdef VK_USE_PLATFORM_XLIB_KHR - PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR GetPhysicalDeviceXlibPresentationSupportKHR; -#endif // VK_USE_PLATFORM_XLIB_KHR - - // ---- VK_KHR_xcb_surface extension commands -#ifdef VK_USE_PLATFORM_XCB_KHR - PFN_vkCreateXcbSurfaceKHR CreateXcbSurfaceKHR; -#endif // VK_USE_PLATFORM_XCB_KHR -#ifdef VK_USE_PLATFORM_XCB_KHR - PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR GetPhysicalDeviceXcbPresentationSupportKHR; -#endif // VK_USE_PLATFORM_XCB_KHR - - // ---- VK_KHR_wayland_surface extension commands -#ifdef VK_USE_PLATFORM_WAYLAND_KHR - PFN_vkCreateWaylandSurfaceKHR CreateWaylandSurfaceKHR; -#endif // VK_USE_PLATFORM_WAYLAND_KHR -#ifdef VK_USE_PLATFORM_WAYLAND_KHR - PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR GetPhysicalDeviceWaylandPresentationSupportKHR; -#endif // VK_USE_PLATFORM_WAYLAND_KHR - - // ---- VK_KHR_mir_surface extension commands -#ifdef VK_USE_PLATFORM_MIR_KHR - PFN_vkCreateMirSurfaceKHR CreateMirSurfaceKHR; -#endif // VK_USE_PLATFORM_MIR_KHR -#ifdef VK_USE_PLATFORM_MIR_KHR - PFN_vkGetPhysicalDeviceMirPresentationSupportKHR GetPhysicalDeviceMirPresentationSupportKHR; -#endif // VK_USE_PLATFORM_MIR_KHR - - // ---- VK_KHR_android_surface extension commands -#ifdef VK_USE_PLATFORM_ANDROID_KHR - PFN_vkCreateAndroidSurfaceKHR CreateAndroidSurfaceKHR; -#endif // VK_USE_PLATFORM_ANDROID_KHR - - // ---- VK_KHR_win32_surface extension commands -#ifdef VK_USE_PLATFORM_WIN32_KHR - PFN_vkCreateWin32SurfaceKHR CreateWin32SurfaceKHR; -#endif // VK_USE_PLATFORM_WIN32_KHR -#ifdef VK_USE_PLATFORM_WIN32_KHR - PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR GetPhysicalDeviceWin32PresentationSupportKHR; -#endif // VK_USE_PLATFORM_WIN32_KHR - - // ---- VK_KHR_get_physical_device_properties2 extension commands - PFN_vkGetPhysicalDeviceFeatures2KHR GetPhysicalDeviceFeatures2KHR; - PFN_vkGetPhysicalDeviceProperties2KHR GetPhysicalDeviceProperties2KHR; - PFN_vkGetPhysicalDeviceFormatProperties2KHR GetPhysicalDeviceFormatProperties2KHR; - PFN_vkGetPhysicalDeviceImageFormatProperties2KHR GetPhysicalDeviceImageFormatProperties2KHR; - PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR GetPhysicalDeviceQueueFamilyProperties2KHR; - PFN_vkGetPhysicalDeviceMemoryProperties2KHR GetPhysicalDeviceMemoryProperties2KHR; - PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR GetPhysicalDeviceSparseImageFormatProperties2KHR; - - // ---- VK_KHR_device_group_creation extension commands - PFN_vkEnumeratePhysicalDeviceGroupsKHR EnumeratePhysicalDeviceGroupsKHR; - - // ---- VK_KHR_external_memory_capabilities extension commands - PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR GetPhysicalDeviceExternalBufferPropertiesKHR; - - // ---- VK_KHR_external_semaphore_capabilities extension commands - PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR GetPhysicalDeviceExternalSemaphorePropertiesKHR; - - // ---- VK_KHR_external_fence_capabilities extension commands - PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR GetPhysicalDeviceExternalFencePropertiesKHR; - - // ---- VK_KHR_get_surface_capabilities2 extension commands - PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR GetPhysicalDeviceSurfaceCapabilities2KHR; - PFN_vkGetPhysicalDeviceSurfaceFormats2KHR GetPhysicalDeviceSurfaceFormats2KHR; - - // ---- VK_EXT_debug_report extension commands - PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT; - PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT; - PFN_vkDebugReportMessageEXT DebugReportMessageEXT; - - // ---- VK_NV_external_memory_capabilities extension commands - PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV GetPhysicalDeviceExternalImageFormatPropertiesNV; - - // ---- VK_NN_vi_surface extension commands -#ifdef VK_USE_PLATFORM_VI_NN - PFN_vkCreateViSurfaceNN CreateViSurfaceNN; -#endif // VK_USE_PLATFORM_VI_NN - - // ---- VK_NVX_device_generated_commands extension commands - PFN_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX GetPhysicalDeviceGeneratedCommandsPropertiesNVX; - - // ---- VK_EXT_direct_mode_display extension commands - PFN_vkReleaseDisplayEXT ReleaseDisplayEXT; - - // ---- VK_EXT_acquire_xlib_display extension commands -#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT - PFN_vkAcquireXlibDisplayEXT AcquireXlibDisplayEXT; -#endif // VK_USE_PLATFORM_XLIB_XRANDR_EXT -#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT - PFN_vkGetRandROutputDisplayEXT GetRandROutputDisplayEXT; -#endif // VK_USE_PLATFORM_XLIB_XRANDR_EXT - - // ---- VK_EXT_display_surface_counter extension commands - PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT GetPhysicalDeviceSurfaceCapabilities2EXT; - - // ---- VK_MVK_ios_surface extension commands -#ifdef VK_USE_PLATFORM_IOS_MVK - PFN_vkCreateIOSSurfaceMVK CreateIOSSurfaceMVK; -#endif // VK_USE_PLATFORM_IOS_MVK - - // ---- VK_MVK_macos_surface extension commands -#ifdef VK_USE_PLATFORM_MACOS_MVK - PFN_vkCreateMacOSSurfaceMVK CreateMacOSSurfaceMVK; -#endif // VK_USE_PLATFORM_MACOS_MVK - - // ---- VK_EXT_debug_utils extension commands - PFN_vkCreateDebugUtilsMessengerEXT CreateDebugUtilsMessengerEXT; - PFN_vkDestroyDebugUtilsMessengerEXT DestroyDebugUtilsMessengerEXT; - PFN_vkSubmitDebugUtilsMessageEXT SubmitDebugUtilsMessageEXT; - - // ---- VK_EXT_sample_locations extension commands - PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT GetPhysicalDeviceMultisamplePropertiesEXT; -} VkLayerInstanceDispatchTable; - -// Device function pointer dispatch table -typedef struct VkLayerDispatchTable_ { - - // ---- Core 1_0 commands - PFN_vkGetDeviceProcAddr GetDeviceProcAddr; - PFN_vkDestroyDevice DestroyDevice; - PFN_vkGetDeviceQueue GetDeviceQueue; - PFN_vkQueueSubmit QueueSubmit; - PFN_vkQueueWaitIdle QueueWaitIdle; - PFN_vkDeviceWaitIdle DeviceWaitIdle; - PFN_vkAllocateMemory AllocateMemory; - PFN_vkFreeMemory FreeMemory; - PFN_vkMapMemory MapMemory; - PFN_vkUnmapMemory UnmapMemory; - PFN_vkFlushMappedMemoryRanges FlushMappedMemoryRanges; - PFN_vkInvalidateMappedMemoryRanges InvalidateMappedMemoryRanges; - PFN_vkGetDeviceMemoryCommitment GetDeviceMemoryCommitment; - PFN_vkBindBufferMemory BindBufferMemory; - PFN_vkBindImageMemory BindImageMemory; - PFN_vkGetBufferMemoryRequirements GetBufferMemoryRequirements; - PFN_vkGetImageMemoryRequirements GetImageMemoryRequirements; - PFN_vkGetImageSparseMemoryRequirements GetImageSparseMemoryRequirements; - PFN_vkQueueBindSparse QueueBindSparse; - PFN_vkCreateFence CreateFence; - PFN_vkDestroyFence DestroyFence; - PFN_vkResetFences ResetFences; - PFN_vkGetFenceStatus GetFenceStatus; - PFN_vkWaitForFences WaitForFences; - PFN_vkCreateSemaphore CreateSemaphore; - PFN_vkDestroySemaphore DestroySemaphore; - PFN_vkCreateEvent CreateEvent; - PFN_vkDestroyEvent DestroyEvent; - PFN_vkGetEventStatus GetEventStatus; - PFN_vkSetEvent SetEvent; - PFN_vkResetEvent ResetEvent; - PFN_vkCreateQueryPool CreateQueryPool; - PFN_vkDestroyQueryPool DestroyQueryPool; - PFN_vkGetQueryPoolResults GetQueryPoolResults; - PFN_vkCreateBuffer CreateBuffer; - PFN_vkDestroyBuffer DestroyBuffer; - PFN_vkCreateBufferView CreateBufferView; - PFN_vkDestroyBufferView DestroyBufferView; - PFN_vkCreateImage CreateImage; - PFN_vkDestroyImage DestroyImage; - PFN_vkGetImageSubresourceLayout GetImageSubresourceLayout; - PFN_vkCreateImageView CreateImageView; - PFN_vkDestroyImageView DestroyImageView; - PFN_vkCreateShaderModule CreateShaderModule; - PFN_vkDestroyShaderModule DestroyShaderModule; - PFN_vkCreatePipelineCache CreatePipelineCache; - PFN_vkDestroyPipelineCache DestroyPipelineCache; - PFN_vkGetPipelineCacheData GetPipelineCacheData; - PFN_vkMergePipelineCaches MergePipelineCaches; - PFN_vkCreateGraphicsPipelines CreateGraphicsPipelines; - PFN_vkCreateComputePipelines CreateComputePipelines; - PFN_vkDestroyPipeline DestroyPipeline; - PFN_vkCreatePipelineLayout CreatePipelineLayout; - PFN_vkDestroyPipelineLayout DestroyPipelineLayout; - PFN_vkCreateSampler CreateSampler; - PFN_vkDestroySampler DestroySampler; - PFN_vkCreateDescriptorSetLayout CreateDescriptorSetLayout; - PFN_vkDestroyDescriptorSetLayout DestroyDescriptorSetLayout; - PFN_vkCreateDescriptorPool CreateDescriptorPool; - PFN_vkDestroyDescriptorPool DestroyDescriptorPool; - PFN_vkResetDescriptorPool ResetDescriptorPool; - PFN_vkAllocateDescriptorSets AllocateDescriptorSets; - PFN_vkFreeDescriptorSets FreeDescriptorSets; - PFN_vkUpdateDescriptorSets UpdateDescriptorSets; - PFN_vkCreateFramebuffer CreateFramebuffer; - PFN_vkDestroyFramebuffer DestroyFramebuffer; - PFN_vkCreateRenderPass CreateRenderPass; - PFN_vkDestroyRenderPass DestroyRenderPass; - PFN_vkGetRenderAreaGranularity GetRenderAreaGranularity; - PFN_vkCreateCommandPool CreateCommandPool; - PFN_vkDestroyCommandPool DestroyCommandPool; - PFN_vkResetCommandPool ResetCommandPool; - PFN_vkAllocateCommandBuffers AllocateCommandBuffers; - PFN_vkFreeCommandBuffers FreeCommandBuffers; - PFN_vkBeginCommandBuffer BeginCommandBuffer; - PFN_vkEndCommandBuffer EndCommandBuffer; - PFN_vkResetCommandBuffer ResetCommandBuffer; - PFN_vkCmdBindPipeline CmdBindPipeline; - PFN_vkCmdSetViewport CmdSetViewport; - PFN_vkCmdSetScissor CmdSetScissor; - PFN_vkCmdSetLineWidth CmdSetLineWidth; - PFN_vkCmdSetDepthBias CmdSetDepthBias; - PFN_vkCmdSetBlendConstants CmdSetBlendConstants; - PFN_vkCmdSetDepthBounds CmdSetDepthBounds; - PFN_vkCmdSetStencilCompareMask CmdSetStencilCompareMask; - PFN_vkCmdSetStencilWriteMask CmdSetStencilWriteMask; - PFN_vkCmdSetStencilReference CmdSetStencilReference; - PFN_vkCmdBindDescriptorSets CmdBindDescriptorSets; - PFN_vkCmdBindIndexBuffer CmdBindIndexBuffer; - PFN_vkCmdBindVertexBuffers CmdBindVertexBuffers; - PFN_vkCmdDraw CmdDraw; - PFN_vkCmdDrawIndexed CmdDrawIndexed; - PFN_vkCmdDrawIndirect CmdDrawIndirect; - PFN_vkCmdDrawIndexedIndirect CmdDrawIndexedIndirect; - PFN_vkCmdDispatch CmdDispatch; - PFN_vkCmdDispatchIndirect CmdDispatchIndirect; - PFN_vkCmdCopyBuffer CmdCopyBuffer; - PFN_vkCmdCopyImage CmdCopyImage; - PFN_vkCmdBlitImage CmdBlitImage; - PFN_vkCmdCopyBufferToImage CmdCopyBufferToImage; - PFN_vkCmdCopyImageToBuffer CmdCopyImageToBuffer; - PFN_vkCmdUpdateBuffer CmdUpdateBuffer; - PFN_vkCmdFillBuffer CmdFillBuffer; - PFN_vkCmdClearColorImage CmdClearColorImage; - PFN_vkCmdClearDepthStencilImage CmdClearDepthStencilImage; - PFN_vkCmdClearAttachments CmdClearAttachments; - PFN_vkCmdResolveImage CmdResolveImage; - PFN_vkCmdSetEvent CmdSetEvent; - PFN_vkCmdResetEvent CmdResetEvent; - PFN_vkCmdWaitEvents CmdWaitEvents; - PFN_vkCmdPipelineBarrier CmdPipelineBarrier; - PFN_vkCmdBeginQuery CmdBeginQuery; - PFN_vkCmdEndQuery CmdEndQuery; - PFN_vkCmdResetQueryPool CmdResetQueryPool; - PFN_vkCmdWriteTimestamp CmdWriteTimestamp; - PFN_vkCmdCopyQueryPoolResults CmdCopyQueryPoolResults; - PFN_vkCmdPushConstants CmdPushConstants; - PFN_vkCmdBeginRenderPass CmdBeginRenderPass; - PFN_vkCmdNextSubpass CmdNextSubpass; - PFN_vkCmdEndRenderPass CmdEndRenderPass; - PFN_vkCmdExecuteCommands CmdExecuteCommands; - - // ---- Core 1_1 commands - PFN_vkBindBufferMemory2 BindBufferMemory2; - PFN_vkBindImageMemory2 BindImageMemory2; - PFN_vkGetDeviceGroupPeerMemoryFeatures GetDeviceGroupPeerMemoryFeatures; - PFN_vkCmdSetDeviceMask CmdSetDeviceMask; - PFN_vkCmdDispatchBase CmdDispatchBase; - PFN_vkGetImageMemoryRequirements2 GetImageMemoryRequirements2; - PFN_vkGetBufferMemoryRequirements2 GetBufferMemoryRequirements2; - PFN_vkGetImageSparseMemoryRequirements2 GetImageSparseMemoryRequirements2; - PFN_vkTrimCommandPool TrimCommandPool; - PFN_vkGetDeviceQueue2 GetDeviceQueue2; - PFN_vkCreateSamplerYcbcrConversion CreateSamplerYcbcrConversion; - PFN_vkDestroySamplerYcbcrConversion DestroySamplerYcbcrConversion; - PFN_vkCreateDescriptorUpdateTemplate CreateDescriptorUpdateTemplate; - PFN_vkDestroyDescriptorUpdateTemplate DestroyDescriptorUpdateTemplate; - PFN_vkUpdateDescriptorSetWithTemplate UpdateDescriptorSetWithTemplate; - PFN_vkGetDescriptorSetLayoutSupport GetDescriptorSetLayoutSupport; - - // ---- VK_KHR_swapchain extension commands - PFN_vkCreateSwapchainKHR CreateSwapchainKHR; - PFN_vkDestroySwapchainKHR DestroySwapchainKHR; - PFN_vkGetSwapchainImagesKHR GetSwapchainImagesKHR; - PFN_vkAcquireNextImageKHR AcquireNextImageKHR; - PFN_vkQueuePresentKHR QueuePresentKHR; - PFN_vkGetDeviceGroupPresentCapabilitiesKHR GetDeviceGroupPresentCapabilitiesKHR; - PFN_vkGetDeviceGroupSurfacePresentModesKHR GetDeviceGroupSurfacePresentModesKHR; - PFN_vkAcquireNextImage2KHR AcquireNextImage2KHR; - - // ---- VK_KHR_display_swapchain extension commands - PFN_vkCreateSharedSwapchainsKHR CreateSharedSwapchainsKHR; - - // ---- VK_KHR_device_group extension commands - PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR GetDeviceGroupPeerMemoryFeaturesKHR; - PFN_vkCmdSetDeviceMaskKHR CmdSetDeviceMaskKHR; - PFN_vkCmdDispatchBaseKHR CmdDispatchBaseKHR; - - // ---- VK_KHR_maintenance1 extension commands - PFN_vkTrimCommandPoolKHR TrimCommandPoolKHR; - - // ---- VK_KHR_external_memory_win32 extension commands -#ifdef VK_USE_PLATFORM_WIN32_KHR - PFN_vkGetMemoryWin32HandleKHR GetMemoryWin32HandleKHR; -#endif // VK_USE_PLATFORM_WIN32_KHR -#ifdef VK_USE_PLATFORM_WIN32_KHR - PFN_vkGetMemoryWin32HandlePropertiesKHR GetMemoryWin32HandlePropertiesKHR; -#endif // VK_USE_PLATFORM_WIN32_KHR - - // ---- VK_KHR_external_memory_fd extension commands - PFN_vkGetMemoryFdKHR GetMemoryFdKHR; - PFN_vkGetMemoryFdPropertiesKHR GetMemoryFdPropertiesKHR; - - // ---- VK_KHR_external_semaphore_win32 extension commands -#ifdef VK_USE_PLATFORM_WIN32_KHR - PFN_vkImportSemaphoreWin32HandleKHR ImportSemaphoreWin32HandleKHR; -#endif // VK_USE_PLATFORM_WIN32_KHR -#ifdef VK_USE_PLATFORM_WIN32_KHR - PFN_vkGetSemaphoreWin32HandleKHR GetSemaphoreWin32HandleKHR; -#endif // VK_USE_PLATFORM_WIN32_KHR - - // ---- VK_KHR_external_semaphore_fd extension commands - PFN_vkImportSemaphoreFdKHR ImportSemaphoreFdKHR; - PFN_vkGetSemaphoreFdKHR GetSemaphoreFdKHR; - - // ---- VK_KHR_push_descriptor extension commands - PFN_vkCmdPushDescriptorSetKHR CmdPushDescriptorSetKHR; - PFN_vkCmdPushDescriptorSetWithTemplateKHR CmdPushDescriptorSetWithTemplateKHR; - - // ---- VK_KHR_descriptor_update_template extension commands - PFN_vkCreateDescriptorUpdateTemplateKHR CreateDescriptorUpdateTemplateKHR; - PFN_vkDestroyDescriptorUpdateTemplateKHR DestroyDescriptorUpdateTemplateKHR; - PFN_vkUpdateDescriptorSetWithTemplateKHR UpdateDescriptorSetWithTemplateKHR; - - // ---- VK_KHR_shared_presentable_image extension commands - PFN_vkGetSwapchainStatusKHR GetSwapchainStatusKHR; - - // ---- VK_KHR_external_fence_win32 extension commands -#ifdef VK_USE_PLATFORM_WIN32_KHR - PFN_vkImportFenceWin32HandleKHR ImportFenceWin32HandleKHR; -#endif // VK_USE_PLATFORM_WIN32_KHR -#ifdef VK_USE_PLATFORM_WIN32_KHR - PFN_vkGetFenceWin32HandleKHR GetFenceWin32HandleKHR; -#endif // VK_USE_PLATFORM_WIN32_KHR - - // ---- VK_KHR_external_fence_fd extension commands - PFN_vkImportFenceFdKHR ImportFenceFdKHR; - PFN_vkGetFenceFdKHR GetFenceFdKHR; - - // ---- VK_KHR_get_memory_requirements2 extension commands - PFN_vkGetImageMemoryRequirements2KHR GetImageMemoryRequirements2KHR; - PFN_vkGetBufferMemoryRequirements2KHR GetBufferMemoryRequirements2KHR; - PFN_vkGetImageSparseMemoryRequirements2KHR GetImageSparseMemoryRequirements2KHR; - - // ---- VK_KHR_sampler_ycbcr_conversion extension commands - PFN_vkCreateSamplerYcbcrConversionKHR CreateSamplerYcbcrConversionKHR; - PFN_vkDestroySamplerYcbcrConversionKHR DestroySamplerYcbcrConversionKHR; - - // ---- VK_KHR_bind_memory2 extension commands - PFN_vkBindBufferMemory2KHR BindBufferMemory2KHR; - PFN_vkBindImageMemory2KHR BindImageMemory2KHR; - - // ---- VK_KHR_maintenance3 extension commands - PFN_vkGetDescriptorSetLayoutSupportKHR GetDescriptorSetLayoutSupportKHR; - - // ---- VK_EXT_debug_marker extension commands - PFN_vkDebugMarkerSetObjectTagEXT DebugMarkerSetObjectTagEXT; - PFN_vkDebugMarkerSetObjectNameEXT DebugMarkerSetObjectNameEXT; - PFN_vkCmdDebugMarkerBeginEXT CmdDebugMarkerBeginEXT; - PFN_vkCmdDebugMarkerEndEXT CmdDebugMarkerEndEXT; - PFN_vkCmdDebugMarkerInsertEXT CmdDebugMarkerInsertEXT; - - // ---- VK_AMD_draw_indirect_count extension commands - PFN_vkCmdDrawIndirectCountAMD CmdDrawIndirectCountAMD; - PFN_vkCmdDrawIndexedIndirectCountAMD CmdDrawIndexedIndirectCountAMD; - - // ---- VK_AMD_shader_info extension commands - PFN_vkGetShaderInfoAMD GetShaderInfoAMD; - - // ---- VK_NV_external_memory_win32 extension commands -#ifdef VK_USE_PLATFORM_WIN32_KHR - PFN_vkGetMemoryWin32HandleNV GetMemoryWin32HandleNV; -#endif // VK_USE_PLATFORM_WIN32_KHR - - // ---- VK_NVX_device_generated_commands extension commands - PFN_vkCmdProcessCommandsNVX CmdProcessCommandsNVX; - PFN_vkCmdReserveSpaceForCommandsNVX CmdReserveSpaceForCommandsNVX; - PFN_vkCreateIndirectCommandsLayoutNVX CreateIndirectCommandsLayoutNVX; - PFN_vkDestroyIndirectCommandsLayoutNVX DestroyIndirectCommandsLayoutNVX; - PFN_vkCreateObjectTableNVX CreateObjectTableNVX; - PFN_vkDestroyObjectTableNVX DestroyObjectTableNVX; - PFN_vkRegisterObjectsNVX RegisterObjectsNVX; - PFN_vkUnregisterObjectsNVX UnregisterObjectsNVX; - - // ---- VK_NV_clip_space_w_scaling extension commands - PFN_vkCmdSetViewportWScalingNV CmdSetViewportWScalingNV; - - // ---- VK_EXT_display_control extension commands - PFN_vkDisplayPowerControlEXT DisplayPowerControlEXT; - PFN_vkRegisterDeviceEventEXT RegisterDeviceEventEXT; - PFN_vkRegisterDisplayEventEXT RegisterDisplayEventEXT; - PFN_vkGetSwapchainCounterEXT GetSwapchainCounterEXT; - - // ---- VK_GOOGLE_display_timing extension commands - PFN_vkGetRefreshCycleDurationGOOGLE GetRefreshCycleDurationGOOGLE; - PFN_vkGetPastPresentationTimingGOOGLE GetPastPresentationTimingGOOGLE; - - // ---- VK_EXT_discard_rectangles extension commands - PFN_vkCmdSetDiscardRectangleEXT CmdSetDiscardRectangleEXT; - - // ---- VK_EXT_hdr_metadata extension commands - PFN_vkSetHdrMetadataEXT SetHdrMetadataEXT; - - // ---- VK_EXT_debug_utils extension commands - PFN_vkSetDebugUtilsObjectNameEXT SetDebugUtilsObjectNameEXT; - PFN_vkSetDebugUtilsObjectTagEXT SetDebugUtilsObjectTagEXT; - PFN_vkQueueBeginDebugUtilsLabelEXT QueueBeginDebugUtilsLabelEXT; - PFN_vkQueueEndDebugUtilsLabelEXT QueueEndDebugUtilsLabelEXT; - PFN_vkQueueInsertDebugUtilsLabelEXT QueueInsertDebugUtilsLabelEXT; - PFN_vkCmdBeginDebugUtilsLabelEXT CmdBeginDebugUtilsLabelEXT; - PFN_vkCmdEndDebugUtilsLabelEXT CmdEndDebugUtilsLabelEXT; - PFN_vkCmdInsertDebugUtilsLabelEXT CmdInsertDebugUtilsLabelEXT; - - // ---- VK_EXT_sample_locations extension commands - PFN_vkCmdSetSampleLocationsEXT CmdSetSampleLocationsEXT; - - // ---- VK_EXT_validation_cache extension commands - PFN_vkCreateValidationCacheEXT CreateValidationCacheEXT; - PFN_vkDestroyValidationCacheEXT DestroyValidationCacheEXT; - PFN_vkMergeValidationCachesEXT MergeValidationCachesEXT; - PFN_vkGetValidationCacheDataEXT GetValidationCacheDataEXT; - - // ---- VK_EXT_external_memory_host extension commands - PFN_vkGetMemoryHostPointerPropertiesEXT GetMemoryHostPointerPropertiesEXT; - - // ---- VK_AMD_buffer_marker extension commands - PFN_vkCmdWriteBufferMarkerAMD CmdWriteBufferMarkerAMD; -} VkLayerDispatchTable; - - diff --git a/ext/vulkan/vulkan.h b/ext/vulkan/vulkan.h index d05c8490a5..a3be4af6c4 100644 --- a/ext/vulkan/vulkan.h +++ b/ext/vulkan/vulkan.h @@ -2,7 +2,7 @@ #define VULKAN_H_ 1 /* -** Copyright (c) 2015-2018 The Khronos Group Inc. +** Copyright (c) 2015-2019 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -24,6 +24,10 @@ #include "vulkan_android.h" #endif +#ifdef VK_USE_PLATFORM_FUCHSIA +#include +#include "vulkan_fuchsia.h" +#endif #ifdef VK_USE_PLATFORM_IOS_MVK #include "vulkan_ios.h" @@ -35,12 +39,6 @@ #endif -#ifdef VK_USE_PLATFORM_MIR_KHR -#include -#include "vulkan_mir.h" -#endif - - #ifdef VK_USE_PLATFORM_VI_NN #include "vulkan_vi.h" #endif diff --git a/ext/vulkan/vulkan_android.h b/ext/vulkan/vulkan_android.h index 5e61c0531a..e70376c886 100644 --- a/ext/vulkan/vulkan_android.h +++ b/ext/vulkan/vulkan_android.h @@ -6,7 +6,7 @@ extern "C" { #endif /* -** Copyright (c) 2015-2018 The Khronos Group Inc. +** Copyright (c) 2015-2019 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -53,6 +53,72 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateAndroidSurfaceKHR( VkSurfaceKHR* pSurface); #endif +#define VK_ANDROID_external_memory_android_hardware_buffer 1 +struct AHardwareBuffer; + +#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION 3 +#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME "VK_ANDROID_external_memory_android_hardware_buffer" + +typedef struct VkAndroidHardwareBufferUsageANDROID { + VkStructureType sType; + void* pNext; + uint64_t androidHardwareBufferUsage; +} VkAndroidHardwareBufferUsageANDROID; + +typedef struct VkAndroidHardwareBufferPropertiesANDROID { + VkStructureType sType; + void* pNext; + VkDeviceSize allocationSize; + uint32_t memoryTypeBits; +} VkAndroidHardwareBufferPropertiesANDROID; + +typedef struct VkAndroidHardwareBufferFormatPropertiesANDROID { + VkStructureType sType; + void* pNext; + VkFormat format; + uint64_t externalFormat; + VkFormatFeatureFlags formatFeatures; + VkComponentMapping samplerYcbcrConversionComponents; + VkSamplerYcbcrModelConversion suggestedYcbcrModel; + VkSamplerYcbcrRange suggestedYcbcrRange; + VkChromaLocation suggestedXChromaOffset; + VkChromaLocation suggestedYChromaOffset; +} VkAndroidHardwareBufferFormatPropertiesANDROID; + +typedef struct VkImportAndroidHardwareBufferInfoANDROID { + VkStructureType sType; + const void* pNext; + struct AHardwareBuffer* buffer; +} VkImportAndroidHardwareBufferInfoANDROID; + +typedef struct VkMemoryGetAndroidHardwareBufferInfoANDROID { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; +} VkMemoryGetAndroidHardwareBufferInfoANDROID; + +typedef struct VkExternalFormatANDROID { + VkStructureType sType; + void* pNext; + uint64_t externalFormat; +} VkExternalFormatANDROID; + + +typedef VkResult (VKAPI_PTR *PFN_vkGetAndroidHardwareBufferPropertiesANDROID)(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryAndroidHardwareBufferANDROID)(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, struct AHardwareBuffer** pBuffer); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetAndroidHardwareBufferPropertiesANDROID( + VkDevice device, + const struct AHardwareBuffer* buffer, + VkAndroidHardwareBufferPropertiesANDROID* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryAndroidHardwareBufferANDROID( + VkDevice device, + const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, + struct AHardwareBuffer** pBuffer); +#endif + #ifdef __cplusplus } #endif diff --git a/ext/vulkan/vulkan_core.h b/ext/vulkan/vulkan_core.h index c115fa6616..caeecd9bed 100644 --- a/ext/vulkan/vulkan_core.h +++ b/ext/vulkan/vulkan_core.h @@ -6,7 +6,7 @@ extern "C" { #endif /* -** Copyright (c) 2015-2018 The Khronos Group Inc. +** Copyright (c) 2015-2019 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -43,11 +43,10 @@ extern "C" { #define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff) #define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff) // Version of this file -#define VK_HEADER_VERSION 70 +#define VK_HEADER_VERSION 97 #define VK_NULL_HANDLE 0 - #define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; @@ -60,7 +59,6 @@ extern "C" { #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; #endif #endif - typedef uint32_t VkFlags; @@ -147,7 +145,10 @@ typedef enum VkResult { VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001, VK_ERROR_VALIDATION_FAILED_EXT = -1000011001, VK_ERROR_INVALID_SHADER_NV = -1000012000, + VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT = -1000158000, + VK_ERROR_FRAGMENTATION_EXT = -1000161000, VK_ERROR_NOT_PERMITTED_EXT = -1000174001, + VK_ERROR_INVALID_DEVICE_ADDRESS_EXT = -1000244000, VK_ERROR_OUT_OF_POOL_MEMORY_KHR = VK_ERROR_OUT_OF_POOL_MEMORY, VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR = VK_ERROR_INVALID_EXTERNAL_HANDLE, VK_RESULT_BEGIN_RANGE = VK_ERROR_FRAGMENTED_POOL, @@ -285,7 +286,6 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000, VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000, VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, - VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000, VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000, VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000, @@ -296,7 +296,11 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000, VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001, VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT = 1000028000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT = 1000028001, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT = 1000028002, VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV = 1000050000, VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000, VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV = 1000056001, VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057000, @@ -304,6 +308,8 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV = 1000058000, VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000, VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000, + VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT = 1000067000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT = 1000067001, VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073000, VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073001, VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR = 1000073002, @@ -319,6 +325,10 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR = 1000079000, VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR = 1000079001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = 1000080000, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT = 1000081000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT = 1000081001, + VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT = 1000081002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR = 1000082000, VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR = 1000084000, VK_STRUCTURE_TYPE_OBJECT_TABLE_CREATE_INFO_NVX = 1000086000, VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NVX = 1000086001, @@ -340,6 +350,13 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT = 1000101000, VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT = 1000101001, VK_STRUCTURE_TYPE_HDR_METADATA_EXT = 1000105000, + VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR = 1000109000, + VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR = 1000109001, + VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR = 1000109002, + VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR = 1000109003, + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR = 1000109004, + VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR = 1000109005, + VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR = 1000109006, VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR = 1000111000, VK_STRUCTURE_TYPE_IMPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114000, VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114001, @@ -349,6 +366,11 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR = 1000119000, VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR = 1000119001, VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR = 1000119002, + VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR = 1000121000, + VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR = 1000121001, + VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR = 1000121002, + VK_STRUCTURE_TYPE_DISPLAY_PLANE_INFO_2_KHR = 1000121003, + VK_STRUCTURE_TYPE_DISPLAY_PLANE_CAPABILITIES_2_KHR = 1000121004, VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK = 1000122000, VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000, VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT = 1000128000, @@ -356,8 +378,18 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT = 1000128002, VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT = 1000128003, VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT = 1000128004, + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID = 1000129000, + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID = 1000129001, + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID = 1000129002, + VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129003, + VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129004, + VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID = 1000129005, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = 1000130000, VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = 1000130001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT = 1000138000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT = 1000138001, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT = 1000138002, + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT = 1000138003, VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT = 1000143000, VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT = 1000143001, VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT = 1000143002, @@ -369,14 +401,77 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT = 1000148002, VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000, VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000, + VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT = 1000158000, + VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT = 1000158002, + VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT = 1000158003, + VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT = 1000158004, + VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158005, VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000, VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT = 1000161000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT = 1000161001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT = 1000161002, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT = 1000161003, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT_EXT = 1000161004, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SHADING_RATE_IMAGE_STATE_CREATE_INFO_NV = 1000164000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV = 1000164001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV = 1000164002, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV = 1000164005, + VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV = 1000165000, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV = 1000165001, + VK_STRUCTURE_TYPE_GEOMETRY_NV = 1000165003, + VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV = 1000165004, + VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV = 1000165005, + VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV = 1000165006, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV = 1000165007, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV = 1000165008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV = 1000165009, + VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV = 1000165011, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV = 1000165012, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV = 1000166000, + VK_STRUCTURE_TYPE_PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_INFO_NV = 1000166001, VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT = 1000174000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR = 1000177000, VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT = 1000178000, VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT = 1000178001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT = 1000178002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = 1000180000, + VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT = 1000184000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000, + VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD = 1000189000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000, VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = 1000196000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR = 1000197000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR = 1000199000, + VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR = 1000199001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV = 1000201000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV = 1000202000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV = 1000202001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_NV = 1000203000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV = 1000204000, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_EXCLUSIVE_SCISSOR_STATE_CREATE_INFO_NV = 1000205000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV = 1000205002, + VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV = 1000206000, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV = 1000206001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = 1000211000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT = 1000212000, + VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA = 1000214000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT = 1000218000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT = 1000218001, + VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT = 1000218002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT = 1000221000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT = 1000237000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT = 1000238000, + VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT = 1000238001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT = 1000244000, + VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_EXT = 1000244001, + VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT = 1000244002, + VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO_EXT = 1000246000, + VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT = 1000247000, + VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES, @@ -411,6 +506,7 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES, VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO, + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES, VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO, @@ -743,6 +839,7 @@ typedef enum VkImageType { typedef enum VkImageTiling { VK_IMAGE_TILING_OPTIMAL = 0, VK_IMAGE_TILING_LINEAR = 1, + VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT = 1000158000, VK_IMAGE_TILING_BEGIN_RANGE = VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_TILING_END_RANGE = VK_IMAGE_TILING_LINEAR, VK_IMAGE_TILING_RANGE_SIZE = (VK_IMAGE_TILING_LINEAR - VK_IMAGE_TILING_OPTIMAL + 1), @@ -765,6 +862,8 @@ typedef enum VkQueryType { VK_QUERY_TYPE_OCCLUSION = 0, VK_QUERY_TYPE_PIPELINE_STATISTICS = 1, VK_QUERY_TYPE_TIMESTAMP = 2, + VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT = 1000028004, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV = 1000165000, VK_QUERY_TYPE_BEGIN_RANGE = VK_QUERY_TYPE_OCCLUSION, VK_QUERY_TYPE_END_RANGE = VK_QUERY_TYPE_TIMESTAMP, VK_QUERY_TYPE_RANGE_SIZE = (VK_QUERY_TYPE_TIMESTAMP - VK_QUERY_TYPE_OCCLUSION + 1), @@ -794,6 +893,8 @@ typedef enum VkImageLayout { VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL = 1000117001, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002, VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR = 1000111000, + VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV = 1000164003, + VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT = 1000218000, VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_BEGIN_RANGE = VK_IMAGE_LAYOUT_UNDEFINED, @@ -1027,6 +1128,9 @@ typedef enum VkDynamicState { VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV = 1000087000, VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT = 1000099000, VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT = 1000143000, + VK_DYNAMIC_STATE_VIEWPORT_SHADING_RATE_PALETTE_NV = 1000164004, + VK_DYNAMIC_STATE_VIEWPORT_COARSE_SAMPLE_ORDER_NV = 1000164006, + VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV = 1000205001, VK_DYNAMIC_STATE_BEGIN_RANGE = VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_END_RANGE = VK_DYNAMIC_STATE_STENCIL_REFERENCE, VK_DYNAMIC_STATE_RANGE_SIZE = (VK_DYNAMIC_STATE_STENCIL_REFERENCE - VK_DYNAMIC_STATE_VIEWPORT + 1), @@ -1089,6 +1193,8 @@ typedef enum VkDescriptorType { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 8, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10, + VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = 1000138000, + VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, VK_DESCRIPTOR_TYPE_BEGIN_RANGE = VK_DESCRIPTOR_TYPE_SAMPLER, VK_DESCRIPTOR_TYPE_END_RANGE = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, VK_DESCRIPTOR_TYPE_RANGE_SIZE = (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT - VK_DESCRIPTOR_TYPE_SAMPLER + 1), @@ -1117,6 +1223,7 @@ typedef enum VkAttachmentStoreOp { typedef enum VkPipelineBindPoint { VK_PIPELINE_BIND_POINT_GRAPHICS = 0, VK_PIPELINE_BIND_POINT_COMPUTE = 1, + VK_PIPELINE_BIND_POINT_RAY_TRACING_NV = 1000165000, VK_PIPELINE_BIND_POINT_BEGIN_RANGE = VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_END_RANGE = VK_PIPELINE_BIND_POINT_COMPUTE, VK_PIPELINE_BIND_POINT_RANGE_SIZE = (VK_PIPELINE_BIND_POINT_COMPUTE - VK_PIPELINE_BIND_POINT_GRAPHICS + 1), @@ -1135,6 +1242,7 @@ typedef enum VkCommandBufferLevel { typedef enum VkIndexType { VK_INDEX_TYPE_UINT16 = 0, VK_INDEX_TYPE_UINT32 = 1, + VK_INDEX_TYPE_NONE_NV = 1000165000, VK_INDEX_TYPE_BEGIN_RANGE = VK_INDEX_TYPE_UINT16, VK_INDEX_TYPE_END_RANGE = VK_INDEX_TYPE_UINT32, VK_INDEX_TYPE_RANGE_SIZE = (VK_INDEX_TYPE_UINT32 - VK_INDEX_TYPE_UINT16 + 1), @@ -1188,6 +1296,7 @@ typedef enum VkObjectType { VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX = 1000086001, VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000128000, VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000, + VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE, VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR = VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION, VK_OBJECT_TYPE_BEGIN_RANGE = VK_OBJECT_TYPE_UNKNOWN, @@ -1196,6 +1305,16 @@ typedef enum VkObjectType { VK_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF } VkObjectType; +typedef enum VkVendorId { + VK_VENDOR_ID_VIV = 0x10001, + VK_VENDOR_ID_VSI = 0x10002, + VK_VENDOR_ID_KAZAN = 0x10003, + VK_VENDOR_ID_BEGIN_RANGE = VK_VENDOR_ID_VIV, + VK_VENDOR_ID_END_RANGE = VK_VENDOR_ID_KAZAN, + VK_VENDOR_ID_RANGE_SIZE = (VK_VENDOR_ID_KAZAN - VK_VENDOR_ID_VIV + 1), + VK_VENDOR_ID_MAX_ENUM = 0x7FFFFFFF +} VkVendorId; + typedef VkFlags VkInstanceCreateFlags; typedef enum VkFormatFeatureFlagBits { @@ -1223,6 +1342,7 @@ typedef enum VkFormatFeatureFlagBits { VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT = 0x00800000, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT_EXT = 0x00010000, + VK_FORMAT_FEATURE_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x01000000, VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT, VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR = VK_FORMAT_FEATURE_TRANSFER_DST_BIT, VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR = VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT, @@ -1245,6 +1365,8 @@ typedef enum VkImageUsageFlagBits { VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000020, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 0x00000040, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 0x00000080, + VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV = 0x00000100, + VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x00000200, VK_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkImageUsageFlagBits; typedef VkFlags VkImageUsageFlags; @@ -1262,7 +1384,9 @@ typedef enum VkImageCreateFlagBits { VK_IMAGE_CREATE_EXTENDED_USAGE_BIT = 0x00000100, VK_IMAGE_CREATE_PROTECTED_BIT = 0x00000800, VK_IMAGE_CREATE_DISJOINT_BIT = 0x00000200, + VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV = 0x00002000, VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT = 0x00001000, + VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT = 0x00004000, VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT, VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT, VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR = VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT, @@ -1339,7 +1463,15 @@ typedef enum VkPipelineStageFlagBits { VK_PIPELINE_STAGE_HOST_BIT = 0x00004000, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000, + VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000, + VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00040000, VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX = 0x00020000, + VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV = 0x00400000, + VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV = 0x00200000, + VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV = 0x02000000, + VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV = 0x00080000, + VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV = 0x00100000, + VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT = 0x00800000, VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkPipelineStageFlagBits; typedef VkFlags VkPipelineStageFlags; @@ -1353,6 +1485,10 @@ typedef enum VkImageAspectFlagBits { VK_IMAGE_ASPECT_PLANE_0_BIT = 0x00000010, VK_IMAGE_ASPECT_PLANE_1_BIT = 0x00000020, VK_IMAGE_ASPECT_PLANE_2_BIT = 0x00000040, + VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT = 0x00000080, + VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT = 0x00000100, + VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT = 0x00000200, + VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT = 0x00000400, VK_IMAGE_ASPECT_PLANE_0_BIT_KHR = VK_IMAGE_ASPECT_PLANE_0_BIT, VK_IMAGE_ASPECT_PLANE_1_BIT_KHR = VK_IMAGE_ASPECT_PLANE_1_BIT, VK_IMAGE_ASPECT_PLANE_2_BIT_KHR = VK_IMAGE_ASPECT_PLANE_2_BIT, @@ -1413,6 +1549,7 @@ typedef enum VkBufferCreateFlagBits { VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004, VK_BUFFER_CREATE_PROTECTED_BIT = 0x00000008, + VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT = 0x00000010, VK_BUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkBufferCreateFlagBits; typedef VkFlags VkBufferCreateFlags; @@ -1427,10 +1564,20 @@ typedef enum VkBufferUsageFlagBits { VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100, + VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT = 0x00000800, + VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT = 0x00001000, + VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00000200, + VK_BUFFER_USAGE_RAY_TRACING_BIT_NV = 0x00000400, + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT = 0x00020000, VK_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkBufferUsageFlagBits; typedef VkFlags VkBufferUsageFlags; typedef VkFlags VkBufferViewCreateFlags; + +typedef enum VkImageViewCreateFlagBits { + VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT = 0x00000001, + VK_IMAGE_VIEW_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkImageViewCreateFlagBits; typedef VkFlags VkImageViewCreateFlags; typedef VkFlags VkShaderModuleCreateFlags; typedef VkFlags VkPipelineCacheCreateFlags; @@ -1441,6 +1588,7 @@ typedef enum VkPipelineCreateFlagBits { VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004, VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 0x00000008, VK_PIPELINE_CREATE_DISPATCH_BASE = 0x00000010, + VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV = 0x00000020, VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT, VK_PIPELINE_CREATE_DISPATCH_BASE_KHR = VK_PIPELINE_CREATE_DISPATCH_BASE, VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF @@ -1457,6 +1605,14 @@ typedef enum VkShaderStageFlagBits { VK_SHADER_STAGE_COMPUTE_BIT = 0x00000020, VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F, VK_SHADER_STAGE_ALL = 0x7FFFFFFF, + VK_SHADER_STAGE_RAYGEN_BIT_NV = 0x00000100, + VK_SHADER_STAGE_ANY_HIT_BIT_NV = 0x00000200, + VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV = 0x00000400, + VK_SHADER_STAGE_MISS_BIT_NV = 0x00000800, + VK_SHADER_STAGE_INTERSECTION_BIT_NV = 0x00001000, + VK_SHADER_STAGE_CALLABLE_BIT_NV = 0x00002000, + VK_SHADER_STAGE_TASK_BIT_NV = 0x00000040, + VK_SHADER_STAGE_MESH_BIT_NV = 0x00000080, VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkShaderStageFlagBits; typedef VkFlags VkPipelineVertexInputStateCreateFlags; @@ -1488,16 +1644,24 @@ typedef VkFlags VkColorComponentFlags; typedef VkFlags VkPipelineDynamicStateCreateFlags; typedef VkFlags VkPipelineLayoutCreateFlags; typedef VkFlags VkShaderStageFlags; + +typedef enum VkSamplerCreateFlagBits { + VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT = 0x00000001, + VK_SAMPLER_CREATE_SUBSAMPLED_COARSE_RECONSTRUCTION_BIT_EXT = 0x00000002, + VK_SAMPLER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSamplerCreateFlagBits; typedef VkFlags VkSamplerCreateFlags; typedef enum VkDescriptorSetLayoutCreateFlagBits { VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR = 0x00000001, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT = 0x00000002, VK_DESCRIPTOR_SET_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkDescriptorSetLayoutCreateFlagBits; typedef VkFlags VkDescriptorSetLayoutCreateFlags; typedef enum VkDescriptorPoolCreateFlagBits { VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 0x00000001, + VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT = 0x00000002, VK_DESCRIPTOR_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkDescriptorPoolCreateFlagBits; typedef VkFlags VkDescriptorPoolCreateFlags; @@ -1536,9 +1700,17 @@ typedef enum VkAccessFlagBits { VK_ACCESS_HOST_WRITE_BIT = 0x00004000, VK_ACCESS_MEMORY_READ_BIT = 0x00008000, VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000, + VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000, + VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000, + VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000, + VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT = 0x00100000, VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX = 0x00020000, VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX = 0x00040000, VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000, + VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV = 0x00800000, + VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV = 0x00200000, + VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV = 0x00400000, + VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT = 0x01000000, VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkAccessFlagBits; typedef VkFlags VkAccessFlags; @@ -2700,6 +2872,16 @@ typedef struct VkDrawIndirectCommand { uint32_t firstInstance; } VkDrawIndirectCommand; +typedef struct VkBaseOutStructure { + VkStructureType sType; + struct VkBaseOutStructure* pNext; +} VkBaseOutStructure; + +typedef struct VkBaseInStructure { + VkStructureType sType; + const struct VkBaseInStructure* pNext; +} VkBaseInStructure; + typedef VkResult (VKAPI_PTR *PFN_vkCreateInstance)(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance); typedef void (VKAPI_PTR *PFN_vkDestroyInstance)(VkInstance instance, const VkAllocationCallbacks* pAllocator); @@ -3732,6 +3914,7 @@ typedef enum VkSubgroupFeatureFlagBits { VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 0x00000020, VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040, VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080, + VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV = 0x00000100, VK_SUBGROUP_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSubgroupFeatureFlagBits; typedef VkFlags VkSubgroupFeatureFlags; @@ -3767,6 +3950,7 @@ typedef enum VkExternalMemoryHandleTypeFlagBits { VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT = 0x00000020, VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT = 0x00000040, VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT = 0x00000200, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID = 0x00000400, VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT = 0x00000080, VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT = 0x00000100, VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, @@ -3993,6 +4177,8 @@ typedef struct VkMemoryRequirements2 { VkMemoryRequirements memoryRequirements; } VkMemoryRequirements2; +typedef VkMemoryRequirements2 VkMemoryRequirements2KHR; + typedef struct VkSparseImageMemoryRequirements2 { VkStructureType sType; void* pNext; @@ -4205,7 +4391,7 @@ typedef struct VkDescriptorUpdateTemplateEntry { typedef struct VkDescriptorUpdateTemplateCreateInfo { VkStructureType sType; - void* pNext; + const void* pNext; VkDescriptorUpdateTemplateCreateFlags flags; uint32_t descriptorUpdateEntryCount; const VkDescriptorUpdateTemplateEntry* pDescriptorUpdateEntries; @@ -4517,7 +4703,6 @@ VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) #define VK_KHR_SURFACE_SPEC_VERSION 25 #define VK_KHR_SURFACE_EXTENSION_NAME "VK_KHR_surface" -#define VK_COLORSPACE_SRGB_NONLINEAR_KHR VK_COLOR_SPACE_SRGB_NONLINEAR_KHR typedef enum VkColorSpaceKHR { @@ -4536,6 +4721,7 @@ typedef enum VkColorSpaceKHR { VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012, VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013, VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014, + VK_COLORSPACE_SRGB_NONLINEAR_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, VK_COLOR_SPACE_BEGIN_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, VK_COLOR_SPACE_END_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, VK_COLOR_SPACE_RANGE_SIZE_KHR = (VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + 1), @@ -4644,6 +4830,7 @@ VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR) typedef enum VkSwapchainCreateFlagBitsKHR { VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = 0x00000001, VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR = 0x00000002, + VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR = 0x00000004, VK_SWAPCHAIN_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkSwapchainCreateFlagBitsKHR; typedef VkFlags VkSwapchainCreateFlagsKHR; @@ -5090,7 +5277,7 @@ VKAPI_ATTR void VKAPI_CALL vkCmdDispatchBaseKHR( #define VK_KHR_maintenance1 1 -#define VK_KHR_MAINTENANCE1_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE1_SPEC_VERSION 2 #define VK_KHR_MAINTENANCE1_EXTENSION_NAME "VK_KHR_maintenance1" typedef VkCommandPoolTrimFlags VkCommandPoolTrimFlagsKHR; @@ -5320,6 +5507,19 @@ VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetWithTemplateKHR( const void* pData); #endif +#define VK_KHR_shader_float16_int8 1 +#define VK_KHR_SHADER_FLOAT16_INT8_SPEC_VERSION 1 +#define VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME "VK_KHR_shader_float16_int8" + +typedef struct VkPhysicalDeviceFloat16Int8FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 shaderFloat16; + VkBool32 shaderInt8; +} VkPhysicalDeviceFloat16Int8FeaturesKHR; + + + #define VK_KHR_16bit_storage 1 #define VK_KHR_16BIT_STORAGE_SPEC_VERSION 1 #define VK_KHR_16BIT_STORAGE_EXTENSION_NAME "VK_KHR_16bit_storage" @@ -5393,6 +5593,114 @@ VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSetWithTemplateKHR( const void* pData); #endif +#define VK_KHR_create_renderpass2 1 +#define VK_KHR_CREATE_RENDERPASS_2_SPEC_VERSION 1 +#define VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME "VK_KHR_create_renderpass2" + +typedef struct VkAttachmentDescription2KHR { + VkStructureType sType; + const void* pNext; + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; +} VkAttachmentDescription2KHR; + +typedef struct VkAttachmentReference2KHR { + VkStructureType sType; + const void* pNext; + uint32_t attachment; + VkImageLayout layout; + VkImageAspectFlags aspectMask; +} VkAttachmentReference2KHR; + +typedef struct VkSubpassDescription2KHR { + VkStructureType sType; + const void* pNext; + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t viewMask; + uint32_t inputAttachmentCount; + const VkAttachmentReference2KHR* pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference2KHR* pColorAttachments; + const VkAttachmentReference2KHR* pResolveAttachments; + const VkAttachmentReference2KHR* pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t* pPreserveAttachments; +} VkSubpassDescription2KHR; + +typedef struct VkSubpassDependency2KHR { + VkStructureType sType; + const void* pNext; + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; + int32_t viewOffset; +} VkSubpassDependency2KHR; + +typedef struct VkRenderPassCreateInfo2KHR { + VkStructureType sType; + const void* pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription2KHR* pAttachments; + uint32_t subpassCount; + const VkSubpassDescription2KHR* pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency2KHR* pDependencies; + uint32_t correlatedViewMaskCount; + const uint32_t* pCorrelatedViewMasks; +} VkRenderPassCreateInfo2KHR; + +typedef struct VkSubpassBeginInfoKHR { + VkStructureType sType; + const void* pNext; + VkSubpassContents contents; +} VkSubpassBeginInfoKHR; + +typedef struct VkSubpassEndInfoKHR { + VkStructureType sType; + const void* pNext; +} VkSubpassEndInfoKHR; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass2KHR)(VkDevice device, const VkRenderPassCreateInfo2KHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); +typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfoKHR* pSubpassBeginInfo); +typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfoKHR* pSubpassBeginInfo, const VkSubpassEndInfoKHR* pSubpassEndInfo); +typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassEndInfoKHR* pSubpassEndInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass2KHR( + VkDevice device, + const VkRenderPassCreateInfo2KHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkRenderPass* pRenderPass); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass2KHR( + VkCommandBuffer commandBuffer, + const VkRenderPassBeginInfo* pRenderPassBegin, + const VkSubpassBeginInfoKHR* pSubpassBeginInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass2KHR( + VkCommandBuffer commandBuffer, + const VkSubpassBeginInfoKHR* pSubpassBeginInfo, + const VkSubpassEndInfoKHR* pSubpassEndInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass2KHR( + VkCommandBuffer commandBuffer, + const VkSubpassEndInfoKHR* pSubpassEndInfo); +#endif + #define VK_KHR_shared_presentable_image 1 #define VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION 1 #define VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME "VK_KHR_shared_presentable_image" @@ -5555,6 +5863,70 @@ typedef VkPhysicalDeviceVariablePointerFeatures VkPhysicalDeviceVariablePointerF +#define VK_KHR_get_display_properties2 1 +#define VK_KHR_GET_DISPLAY_PROPERTIES_2_SPEC_VERSION 1 +#define VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_display_properties2" + +typedef struct VkDisplayProperties2KHR { + VkStructureType sType; + void* pNext; + VkDisplayPropertiesKHR displayProperties; +} VkDisplayProperties2KHR; + +typedef struct VkDisplayPlaneProperties2KHR { + VkStructureType sType; + void* pNext; + VkDisplayPlanePropertiesKHR displayPlaneProperties; +} VkDisplayPlaneProperties2KHR; + +typedef struct VkDisplayModeProperties2KHR { + VkStructureType sType; + void* pNext; + VkDisplayModePropertiesKHR displayModeProperties; +} VkDisplayModeProperties2KHR; + +typedef struct VkDisplayPlaneInfo2KHR { + VkStructureType sType; + const void* pNext; + VkDisplayModeKHR mode; + uint32_t planeIndex; +} VkDisplayPlaneInfo2KHR; + +typedef struct VkDisplayPlaneCapabilities2KHR { + VkStructureType sType; + void* pNext; + VkDisplayPlaneCapabilitiesKHR capabilities; +} VkDisplayPlaneCapabilities2KHR; + + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayProperties2KHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPlaneProperties2KHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayModeProperties2KHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t* pPropertyCount, VkDisplayModeProperties2KHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneCapabilities2KHR)(VkPhysicalDevice physicalDevice, const VkDisplayPlaneInfo2KHR* pDisplayPlaneInfo, VkDisplayPlaneCapabilities2KHR* pCapabilities); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayProperties2KHR( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkDisplayProperties2KHR* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPlaneProperties2KHR( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkDisplayPlaneProperties2KHR* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayModeProperties2KHR( + VkPhysicalDevice physicalDevice, + VkDisplayKHR display, + uint32_t* pPropertyCount, + VkDisplayModeProperties2KHR* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneCapabilities2KHR( + VkPhysicalDevice physicalDevice, + const VkDisplayPlaneInfo2KHR* pDisplayPlaneInfo, + VkDisplayPlaneCapabilities2KHR* pCapabilities); +#endif + #define VK_KHR_dedicated_allocation 1 #define VK_KHR_DEDICATED_ALLOCATION_SPEC_VERSION 3 #define VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_KHR_dedicated_allocation" @@ -5585,8 +5957,6 @@ typedef VkImageMemoryRequirementsInfo2 VkImageMemoryRequirementsInfo2KHR; typedef VkImageSparseMemoryRequirementsInfo2 VkImageSparseMemoryRequirementsInfo2KHR; -typedef VkMemoryRequirements2 VkMemoryRequirements2KHR; - typedef VkSparseImageMemoryRequirements2 VkSparseImageMemoryRequirements2KHR; @@ -5710,13 +6080,187 @@ VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutSupportKHR( VkDescriptorSetLayoutSupport* pSupport); #endif +#define VK_KHR_draw_indirect_count 1 +#define VK_KHR_DRAW_INDIRECT_COUNT_SPEC_VERSION 1 +#define VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_KHR_draw_indirect_count" + +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCountKHR)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCountKHR)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectCountKHR( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCountKHR( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); +#endif + +#define VK_KHR_8bit_storage 1 +#define VK_KHR_8BIT_STORAGE_SPEC_VERSION 1 +#define VK_KHR_8BIT_STORAGE_EXTENSION_NAME "VK_KHR_8bit_storage" + +typedef struct VkPhysicalDevice8BitStorageFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 storageBuffer8BitAccess; + VkBool32 uniformAndStorageBuffer8BitAccess; + VkBool32 storagePushConstant8; +} VkPhysicalDevice8BitStorageFeaturesKHR; + + + +#define VK_KHR_shader_atomic_int64 1 +#define VK_KHR_SHADER_ATOMIC_INT64_SPEC_VERSION 1 +#define VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME "VK_KHR_shader_atomic_int64" + +typedef struct VkPhysicalDeviceShaderAtomicInt64FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 shaderBufferInt64Atomics; + VkBool32 shaderSharedInt64Atomics; +} VkPhysicalDeviceShaderAtomicInt64FeaturesKHR; + + + +#define VK_KHR_driver_properties 1 +#define VK_MAX_DRIVER_NAME_SIZE_KHR 256 +#define VK_MAX_DRIVER_INFO_SIZE_KHR 256 +#define VK_KHR_DRIVER_PROPERTIES_SPEC_VERSION 1 +#define VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME "VK_KHR_driver_properties" + + +typedef enum VkDriverIdKHR { + VK_DRIVER_ID_AMD_PROPRIETARY_KHR = 1, + VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR = 2, + VK_DRIVER_ID_MESA_RADV_KHR = 3, + VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR = 4, + VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR = 5, + VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA_KHR = 6, + VK_DRIVER_ID_IMAGINATION_PROPRIETARY_KHR = 7, + VK_DRIVER_ID_QUALCOMM_PROPRIETARY_KHR = 8, + VK_DRIVER_ID_ARM_PROPRIETARY_KHR = 9, + VK_DRIVER_ID_GOOGLE_PASTEL_KHR = 10, + VK_DRIVER_ID_BEGIN_RANGE_KHR = VK_DRIVER_ID_AMD_PROPRIETARY_KHR, + VK_DRIVER_ID_END_RANGE_KHR = VK_DRIVER_ID_GOOGLE_PASTEL_KHR, + VK_DRIVER_ID_RANGE_SIZE_KHR = (VK_DRIVER_ID_GOOGLE_PASTEL_KHR - VK_DRIVER_ID_AMD_PROPRIETARY_KHR + 1), + VK_DRIVER_ID_MAX_ENUM_KHR = 0x7FFFFFFF +} VkDriverIdKHR; + +typedef struct VkConformanceVersionKHR { + uint8_t major; + uint8_t minor; + uint8_t subminor; + uint8_t patch; +} VkConformanceVersionKHR; + +typedef struct VkPhysicalDeviceDriverPropertiesKHR { + VkStructureType sType; + void* pNext; + VkDriverIdKHR driverID; + char driverName[VK_MAX_DRIVER_NAME_SIZE_KHR]; + char driverInfo[VK_MAX_DRIVER_INFO_SIZE_KHR]; + VkConformanceVersionKHR conformanceVersion; +} VkPhysicalDeviceDriverPropertiesKHR; + + + +#define VK_KHR_shader_float_controls 1 +#define VK_KHR_SHADER_FLOAT_CONTROLS_SPEC_VERSION 1 +#define VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME "VK_KHR_shader_float_controls" + +typedef struct VkPhysicalDeviceFloatControlsPropertiesKHR { + VkStructureType sType; + void* pNext; + VkBool32 separateDenormSettings; + VkBool32 separateRoundingModeSettings; + VkBool32 shaderSignedZeroInfNanPreserveFloat16; + VkBool32 shaderSignedZeroInfNanPreserveFloat32; + VkBool32 shaderSignedZeroInfNanPreserveFloat64; + VkBool32 shaderDenormPreserveFloat16; + VkBool32 shaderDenormPreserveFloat32; + VkBool32 shaderDenormPreserveFloat64; + VkBool32 shaderDenormFlushToZeroFloat16; + VkBool32 shaderDenormFlushToZeroFloat32; + VkBool32 shaderDenormFlushToZeroFloat64; + VkBool32 shaderRoundingModeRTEFloat16; + VkBool32 shaderRoundingModeRTEFloat32; + VkBool32 shaderRoundingModeRTEFloat64; + VkBool32 shaderRoundingModeRTZFloat16; + VkBool32 shaderRoundingModeRTZFloat32; + VkBool32 shaderRoundingModeRTZFloat64; +} VkPhysicalDeviceFloatControlsPropertiesKHR; + + + +#define VK_KHR_depth_stencil_resolve 1 +#define VK_KHR_DEPTH_STENCIL_RESOLVE_SPEC_VERSION 1 +#define VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME "VK_KHR_depth_stencil_resolve" + + +typedef enum VkResolveModeFlagBitsKHR { + VK_RESOLVE_MODE_NONE_KHR = 0, + VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR = 0x00000001, + VK_RESOLVE_MODE_AVERAGE_BIT_KHR = 0x00000002, + VK_RESOLVE_MODE_MIN_BIT_KHR = 0x00000004, + VK_RESOLVE_MODE_MAX_BIT_KHR = 0x00000008, + VK_RESOLVE_MODE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkResolveModeFlagBitsKHR; +typedef VkFlags VkResolveModeFlagsKHR; + +typedef struct VkSubpassDescriptionDepthStencilResolveKHR { + VkStructureType sType; + const void* pNext; + VkResolveModeFlagBitsKHR depthResolveMode; + VkResolveModeFlagBitsKHR stencilResolveMode; + const VkAttachmentReference2KHR* pDepthStencilResolveAttachment; +} VkSubpassDescriptionDepthStencilResolveKHR; + +typedef struct VkPhysicalDeviceDepthStencilResolvePropertiesKHR { + VkStructureType sType; + void* pNext; + VkResolveModeFlagsKHR supportedDepthResolveModes; + VkResolveModeFlagsKHR supportedStencilResolveModes; + VkBool32 independentResolveNone; + VkBool32 independentResolve; +} VkPhysicalDeviceDepthStencilResolvePropertiesKHR; + + + +#define VK_KHR_swapchain_mutable_format 1 +#define VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_SPEC_VERSION 1 +#define VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME "VK_KHR_swapchain_mutable_format" + + +#define VK_KHR_vulkan_memory_model 1 +#define VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION 2 +#define VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME "VK_KHR_vulkan_memory_model" + +typedef struct VkPhysicalDeviceVulkanMemoryModelFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 vulkanMemoryModel; + VkBool32 vulkanMemoryModelDeviceScope; +} VkPhysicalDeviceVulkanMemoryModelFeaturesKHR; + + + #define VK_EXT_debug_report 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT) #define VK_EXT_DEBUG_REPORT_SPEC_VERSION 9 #define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report" -#define VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT -#define VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT typedef enum VkDebugReportObjectTypeEXT { @@ -5756,6 +6300,9 @@ typedef enum VkDebugReportObjectTypeEXT { VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT = 33, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT = 1000156000, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT = 1000085000, + VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT = 1000165000, + VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, @@ -5955,6 +6502,95 @@ typedef struct VkDedicatedAllocationMemoryAllocateInfoNV { +#define VK_EXT_transform_feedback 1 +#define VK_EXT_TRANSFORM_FEEDBACK_SPEC_VERSION 1 +#define VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME "VK_EXT_transform_feedback" + +typedef VkFlags VkPipelineRasterizationStateStreamCreateFlagsEXT; + +typedef struct VkPhysicalDeviceTransformFeedbackFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 transformFeedback; + VkBool32 geometryStreams; +} VkPhysicalDeviceTransformFeedbackFeaturesEXT; + +typedef struct VkPhysicalDeviceTransformFeedbackPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxTransformFeedbackStreams; + uint32_t maxTransformFeedbackBuffers; + VkDeviceSize maxTransformFeedbackBufferSize; + uint32_t maxTransformFeedbackStreamDataSize; + uint32_t maxTransformFeedbackBufferDataSize; + uint32_t maxTransformFeedbackBufferDataStride; + VkBool32 transformFeedbackQueries; + VkBool32 transformFeedbackStreamsLinesTriangles; + VkBool32 transformFeedbackRasterizationStreamSelect; + VkBool32 transformFeedbackDraw; +} VkPhysicalDeviceTransformFeedbackPropertiesEXT; + +typedef struct VkPipelineRasterizationStateStreamCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkPipelineRasterizationStateStreamCreateFlagsEXT flags; + uint32_t rasterizationStream; +} VkPipelineRasterizationStateStreamCreateInfoEXT; + + +typedef void (VKAPI_PTR *PFN_vkCmdBindTransformFeedbackBuffersEXT)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets, const VkDeviceSize* pSizes); +typedef void (VKAPI_PTR *PFN_vkCmdBeginTransformFeedbackEXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer* pCounterBuffers, const VkDeviceSize* pCounterBufferOffsets); +typedef void (VKAPI_PTR *PFN_vkCmdEndTransformFeedbackEXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer* pCounterBuffers, const VkDeviceSize* pCounterBufferOffsets); +typedef void (VKAPI_PTR *PFN_vkCmdBeginQueryIndexedEXT)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags, uint32_t index); +typedef void (VKAPI_PTR *PFN_vkCmdEndQueryIndexedEXT)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, uint32_t index); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectByteCountEXT)(VkCommandBuffer commandBuffer, uint32_t instanceCount, uint32_t firstInstance, VkBuffer counterBuffer, VkDeviceSize counterBufferOffset, uint32_t counterOffset, uint32_t vertexStride); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindTransformFeedbackBuffersEXT( + VkCommandBuffer commandBuffer, + uint32_t firstBinding, + uint32_t bindingCount, + const VkBuffer* pBuffers, + const VkDeviceSize* pOffsets, + const VkDeviceSize* pSizes); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginTransformFeedbackEXT( + VkCommandBuffer commandBuffer, + uint32_t firstCounterBuffer, + uint32_t counterBufferCount, + const VkBuffer* pCounterBuffers, + const VkDeviceSize* pCounterBufferOffsets); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndTransformFeedbackEXT( + VkCommandBuffer commandBuffer, + uint32_t firstCounterBuffer, + uint32_t counterBufferCount, + const VkBuffer* pCounterBuffers, + const VkDeviceSize* pCounterBufferOffsets); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginQueryIndexedEXT( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t query, + VkQueryControlFlags flags, + uint32_t index); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndQueryIndexedEXT( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t query, + uint32_t index); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectByteCountEXT( + VkCommandBuffer commandBuffer, + uint32_t instanceCount, + uint32_t firstInstance, + VkBuffer counterBuffer, + VkDeviceSize counterBufferOffset, + uint32_t counterOffset, + uint32_t vertexStride); +#endif + #define VK_AMD_draw_indirect_count 1 #define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 1 #define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count" @@ -6060,6 +6696,18 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetShaderInfoAMD( #define VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_EXTENSION_NAME "VK_AMD_shader_image_load_store_lod" +#define VK_NV_corner_sampled_image 1 +#define VK_NV_CORNER_SAMPLED_IMAGE_SPEC_VERSION 2 +#define VK_NV_CORNER_SAMPLED_IMAGE_EXTENSION_NAME "VK_NV_corner_sampled_image" + +typedef struct VkPhysicalDeviceCornerSampledImageFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 cornerSampledImage; +} VkPhysicalDeviceCornerSampledImageFeaturesNV; + + + #define VK_IMG_format_pvrtc 1 #define VK_IMG_FORMAT_PVRTC_SPEC_VERSION 1 #define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc" @@ -6142,10 +6790,10 @@ typedef enum VkValidationCheckEXT { } VkValidationCheckEXT; typedef struct VkValidationFlagsEXT { - VkStructureType sType; - const void* pNext; - uint32_t disabledValidationCheckCount; - VkValidationCheckEXT* pDisabledValidationChecks; + VkStructureType sType; + const void* pNext; + uint32_t disabledValidationCheckCount; + const VkValidationCheckEXT* pDisabledValidationChecks; } VkValidationFlagsEXT; @@ -6160,6 +6808,69 @@ typedef struct VkValidationFlagsEXT { #define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote" +#define VK_EXT_astc_decode_mode 1 +#define VK_EXT_ASTC_DECODE_MODE_SPEC_VERSION 1 +#define VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME "VK_EXT_astc_decode_mode" + +typedef struct VkImageViewASTCDecodeModeEXT { + VkStructureType sType; + const void* pNext; + VkFormat decodeMode; +} VkImageViewASTCDecodeModeEXT; + +typedef struct VkPhysicalDeviceASTCDecodeFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 decodeModeSharedExponent; +} VkPhysicalDeviceASTCDecodeFeaturesEXT; + + + +#define VK_EXT_conditional_rendering 1 +#define VK_EXT_CONDITIONAL_RENDERING_SPEC_VERSION 1 +#define VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME "VK_EXT_conditional_rendering" + + +typedef enum VkConditionalRenderingFlagBitsEXT { + VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT = 0x00000001, + VK_CONDITIONAL_RENDERING_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkConditionalRenderingFlagBitsEXT; +typedef VkFlags VkConditionalRenderingFlagsEXT; + +typedef struct VkConditionalRenderingBeginInfoEXT { + VkStructureType sType; + const void* pNext; + VkBuffer buffer; + VkDeviceSize offset; + VkConditionalRenderingFlagsEXT flags; +} VkConditionalRenderingBeginInfoEXT; + +typedef struct VkPhysicalDeviceConditionalRenderingFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 conditionalRendering; + VkBool32 inheritedConditionalRendering; +} VkPhysicalDeviceConditionalRenderingFeaturesEXT; + +typedef struct VkCommandBufferInheritanceConditionalRenderingInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 conditionalRenderingEnable; +} VkCommandBufferInheritanceConditionalRenderingInfoEXT; + + +typedef void (VKAPI_PTR *PFN_vkCmdBeginConditionalRenderingEXT)(VkCommandBuffer commandBuffer, const VkConditionalRenderingBeginInfoEXT* pConditionalRenderingBegin); +typedef void (VKAPI_PTR *PFN_vkCmdEndConditionalRenderingEXT)(VkCommandBuffer commandBuffer); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBeginConditionalRenderingEXT( + VkCommandBuffer commandBuffer, + const VkConditionalRenderingBeginInfoEXT* pConditionalRenderingBegin); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndConditionalRenderingEXT( + VkCommandBuffer commandBuffer); +#endif + #define VK_NVX_device_generated_commands 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkObjectTableNVX) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNVX) @@ -6430,7 +7141,6 @@ VKAPI_ATTR VkResult VKAPI_CALL vkReleaseDisplayEXT( #define VK_EXT_display_surface_counter 1 #define VK_EXT_DISPLAY_SURFACE_COUNTER_SPEC_VERSION 1 #define VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME "VK_EXT_display_surface_counter" -#define VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT typedef enum VkSurfaceCounterFlagBitsEXT { @@ -6854,16 +7564,16 @@ typedef struct VkDebugUtilsMessengerCallbackDataEXT { int32_t messageIdNumber; const char* pMessage; uint32_t queueLabelCount; - VkDebugUtilsLabelEXT* pQueueLabels; + const VkDebugUtilsLabelEXT* pQueueLabels; uint32_t cmdBufLabelCount; - VkDebugUtilsLabelEXT* pCmdBufLabels; + const VkDebugUtilsLabelEXT* pCmdBufLabels; uint32_t objectCount; - VkDebugUtilsObjectNameInfoEXT* pObjects; + const VkDebugUtilsObjectNameInfoEXT* pObjects; } VkDebugUtilsMessengerCallbackDataEXT; typedef VkBool32 (VKAPI_PTR *PFN_vkDebugUtilsMessengerCallbackEXT)( VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageType, + VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData); @@ -6984,6 +7694,42 @@ typedef struct VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT { #define VK_AMD_SHADER_FRAGMENT_MASK_EXTENSION_NAME "VK_AMD_shader_fragment_mask" +#define VK_EXT_inline_uniform_block 1 +#define VK_EXT_INLINE_UNIFORM_BLOCK_SPEC_VERSION 1 +#define VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME "VK_EXT_inline_uniform_block" + +typedef struct VkPhysicalDeviceInlineUniformBlockFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 inlineUniformBlock; + VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind; +} VkPhysicalDeviceInlineUniformBlockFeaturesEXT; + +typedef struct VkPhysicalDeviceInlineUniformBlockPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxInlineUniformBlockSize; + uint32_t maxPerStageDescriptorInlineUniformBlocks; + uint32_t maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks; + uint32_t maxDescriptorSetInlineUniformBlocks; + uint32_t maxDescriptorSetUpdateAfterBindInlineUniformBlocks; +} VkPhysicalDeviceInlineUniformBlockPropertiesEXT; + +typedef struct VkWriteDescriptorSetInlineUniformBlockEXT { + VkStructureType sType; + const void* pNext; + uint32_t dataSize; + const void* pData; +} VkWriteDescriptorSetInlineUniformBlockEXT; + +typedef struct VkDescriptorPoolInlineUniformBlockCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t maxInlineUniformBlockBindings; +} VkDescriptorPoolInlineUniformBlockCreateInfoEXT; + + + #define VK_EXT_shader_stencil_export 1 #define VK_EXT_SHADER_STENCIL_EXPORT_SPEC_VERSION 1 #define VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME "VK_EXT_shader_stencil_export" @@ -7162,12 +7908,68 @@ typedef struct VkPipelineCoverageModulationStateCreateInfoNV { #define VK_EXT_POST_DEPTH_COVERAGE_EXTENSION_NAME "VK_EXT_post_depth_coverage" +#define VK_EXT_image_drm_format_modifier 1 +#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION 1 +#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME "VK_EXT_image_drm_format_modifier" + +typedef struct VkDrmFormatModifierPropertiesEXT { + uint64_t drmFormatModifier; + uint32_t drmFormatModifierPlaneCount; + VkFormatFeatureFlags drmFormatModifierTilingFeatures; +} VkDrmFormatModifierPropertiesEXT; + +typedef struct VkDrmFormatModifierPropertiesListEXT { + VkStructureType sType; + void* pNext; + uint32_t drmFormatModifierCount; + VkDrmFormatModifierPropertiesEXT* pDrmFormatModifierProperties; +} VkDrmFormatModifierPropertiesListEXT; + +typedef struct VkPhysicalDeviceImageDrmFormatModifierInfoEXT { + VkStructureType sType; + const void* pNext; + uint64_t drmFormatModifier; + VkSharingMode sharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t* pQueueFamilyIndices; +} VkPhysicalDeviceImageDrmFormatModifierInfoEXT; + +typedef struct VkImageDrmFormatModifierListCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t drmFormatModifierCount; + const uint64_t* pDrmFormatModifiers; +} VkImageDrmFormatModifierListCreateInfoEXT; + +typedef struct VkImageDrmFormatModifierExplicitCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint64_t drmFormatModifier; + uint32_t drmFormatModifierPlaneCount; + const VkSubresourceLayout* pPlaneLayouts; +} VkImageDrmFormatModifierExplicitCreateInfoEXT; + +typedef struct VkImageDrmFormatModifierPropertiesEXT { + VkStructureType sType; + void* pNext; + uint64_t drmFormatModifier; +} VkImageDrmFormatModifierPropertiesEXT; + + +typedef VkResult (VKAPI_PTR *PFN_vkGetImageDrmFormatModifierPropertiesEXT)(VkDevice device, VkImage image, VkImageDrmFormatModifierPropertiesEXT* pProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetImageDrmFormatModifierPropertiesEXT( + VkDevice device, + VkImage image, + VkImageDrmFormatModifierPropertiesEXT* pProperties); +#endif + #define VK_EXT_validation_cache 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkValidationCacheEXT) #define VK_EXT_VALIDATION_CACHE_SPEC_VERSION 1 #define VK_EXT_VALIDATION_CACHE_EXTENSION_NAME "VK_EXT_validation_cache" -#define VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT typedef enum VkValidationCacheHeaderVersionEXT { @@ -7225,11 +8027,530 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetValidationCacheDataEXT( void* pData); #endif +#define VK_EXT_descriptor_indexing 1 +#define VK_EXT_DESCRIPTOR_INDEXING_SPEC_VERSION 2 +#define VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME "VK_EXT_descriptor_indexing" + + +typedef enum VkDescriptorBindingFlagBitsEXT { + VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT = 0x00000001, + VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT = 0x00000002, + VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT = 0x00000004, + VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT = 0x00000008, + VK_DESCRIPTOR_BINDING_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDescriptorBindingFlagBitsEXT; +typedef VkFlags VkDescriptorBindingFlagsEXT; + +typedef struct VkDescriptorSetLayoutBindingFlagsCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t bindingCount; + const VkDescriptorBindingFlagsEXT* pBindingFlags; +} VkDescriptorSetLayoutBindingFlagsCreateInfoEXT; + +typedef struct VkPhysicalDeviceDescriptorIndexingFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderInputAttachmentArrayDynamicIndexing; + VkBool32 shaderUniformTexelBufferArrayDynamicIndexing; + VkBool32 shaderStorageTexelBufferArrayDynamicIndexing; + VkBool32 shaderUniformBufferArrayNonUniformIndexing; + VkBool32 shaderSampledImageArrayNonUniformIndexing; + VkBool32 shaderStorageBufferArrayNonUniformIndexing; + VkBool32 shaderStorageImageArrayNonUniformIndexing; + VkBool32 shaderInputAttachmentArrayNonUniformIndexing; + VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing; + VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing; + VkBool32 descriptorBindingUniformBufferUpdateAfterBind; + VkBool32 descriptorBindingSampledImageUpdateAfterBind; + VkBool32 descriptorBindingStorageImageUpdateAfterBind; + VkBool32 descriptorBindingStorageBufferUpdateAfterBind; + VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingUpdateUnusedWhilePending; + VkBool32 descriptorBindingPartiallyBound; + VkBool32 descriptorBindingVariableDescriptorCount; + VkBool32 runtimeDescriptorArray; +} VkPhysicalDeviceDescriptorIndexingFeaturesEXT; + +typedef struct VkPhysicalDeviceDescriptorIndexingPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxUpdateAfterBindDescriptorsInAllPools; + VkBool32 shaderUniformBufferArrayNonUniformIndexingNative; + VkBool32 shaderSampledImageArrayNonUniformIndexingNative; + VkBool32 shaderStorageBufferArrayNonUniformIndexingNative; + VkBool32 shaderStorageImageArrayNonUniformIndexingNative; + VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative; + VkBool32 robustBufferAccessUpdateAfterBind; + VkBool32 quadDivergentImplicitLod; + uint32_t maxPerStageDescriptorUpdateAfterBindSamplers; + uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages; + uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments; + uint32_t maxPerStageUpdateAfterBindResources; + uint32_t maxDescriptorSetUpdateAfterBindSamplers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindSampledImages; + uint32_t maxDescriptorSetUpdateAfterBindStorageImages; + uint32_t maxDescriptorSetUpdateAfterBindInputAttachments; +} VkPhysicalDeviceDescriptorIndexingPropertiesEXT; + +typedef struct VkDescriptorSetVariableDescriptorCountAllocateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t descriptorSetCount; + const uint32_t* pDescriptorCounts; +} VkDescriptorSetVariableDescriptorCountAllocateInfoEXT; + +typedef struct VkDescriptorSetVariableDescriptorCountLayoutSupportEXT { + VkStructureType sType; + void* pNext; + uint32_t maxVariableDescriptorCount; +} VkDescriptorSetVariableDescriptorCountLayoutSupportEXT; + + + #define VK_EXT_shader_viewport_index_layer 1 #define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_SPEC_VERSION 1 #define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME "VK_EXT_shader_viewport_index_layer" +#define VK_NV_shading_rate_image 1 +#define VK_NV_SHADING_RATE_IMAGE_SPEC_VERSION 3 +#define VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME "VK_NV_shading_rate_image" + + +typedef enum VkShadingRatePaletteEntryNV { + VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV = 0, + VK_SHADING_RATE_PALETTE_ENTRY_16_INVOCATIONS_PER_PIXEL_NV = 1, + VK_SHADING_RATE_PALETTE_ENTRY_8_INVOCATIONS_PER_PIXEL_NV = 2, + VK_SHADING_RATE_PALETTE_ENTRY_4_INVOCATIONS_PER_PIXEL_NV = 3, + VK_SHADING_RATE_PALETTE_ENTRY_2_INVOCATIONS_PER_PIXEL_NV = 4, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_PIXEL_NV = 5, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X1_PIXELS_NV = 6, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV = 7, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X2_PIXELS_NV = 8, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X2_PIXELS_NV = 9, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X4_PIXELS_NV = 10, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV = 11, + VK_SHADING_RATE_PALETTE_ENTRY_BEGIN_RANGE_NV = VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV, + VK_SHADING_RATE_PALETTE_ENTRY_END_RANGE_NV = VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV, + VK_SHADING_RATE_PALETTE_ENTRY_RANGE_SIZE_NV = (VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV - VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV + 1), + VK_SHADING_RATE_PALETTE_ENTRY_MAX_ENUM_NV = 0x7FFFFFFF +} VkShadingRatePaletteEntryNV; + +typedef enum VkCoarseSampleOrderTypeNV { + VK_COARSE_SAMPLE_ORDER_TYPE_DEFAULT_NV = 0, + VK_COARSE_SAMPLE_ORDER_TYPE_CUSTOM_NV = 1, + VK_COARSE_SAMPLE_ORDER_TYPE_PIXEL_MAJOR_NV = 2, + VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV = 3, + VK_COARSE_SAMPLE_ORDER_TYPE_BEGIN_RANGE_NV = VK_COARSE_SAMPLE_ORDER_TYPE_DEFAULT_NV, + VK_COARSE_SAMPLE_ORDER_TYPE_END_RANGE_NV = VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV, + VK_COARSE_SAMPLE_ORDER_TYPE_RANGE_SIZE_NV = (VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV - VK_COARSE_SAMPLE_ORDER_TYPE_DEFAULT_NV + 1), + VK_COARSE_SAMPLE_ORDER_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkCoarseSampleOrderTypeNV; + +typedef struct VkShadingRatePaletteNV { + uint32_t shadingRatePaletteEntryCount; + const VkShadingRatePaletteEntryNV* pShadingRatePaletteEntries; +} VkShadingRatePaletteNV; + +typedef struct VkPipelineViewportShadingRateImageStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 shadingRateImageEnable; + uint32_t viewportCount; + const VkShadingRatePaletteNV* pShadingRatePalettes; +} VkPipelineViewportShadingRateImageStateCreateInfoNV; + +typedef struct VkPhysicalDeviceShadingRateImageFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 shadingRateImage; + VkBool32 shadingRateCoarseSampleOrder; +} VkPhysicalDeviceShadingRateImageFeaturesNV; + +typedef struct VkPhysicalDeviceShadingRateImagePropertiesNV { + VkStructureType sType; + void* pNext; + VkExtent2D shadingRateTexelSize; + uint32_t shadingRatePaletteSize; + uint32_t shadingRateMaxCoarseSamples; +} VkPhysicalDeviceShadingRateImagePropertiesNV; + +typedef struct VkCoarseSampleLocationNV { + uint32_t pixelX; + uint32_t pixelY; + uint32_t sample; +} VkCoarseSampleLocationNV; + +typedef struct VkCoarseSampleOrderCustomNV { + VkShadingRatePaletteEntryNV shadingRate; + uint32_t sampleCount; + uint32_t sampleLocationCount; + const VkCoarseSampleLocationNV* pSampleLocations; +} VkCoarseSampleOrderCustomNV; + +typedef struct VkPipelineViewportCoarseSampleOrderStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkCoarseSampleOrderTypeNV sampleOrderType; + uint32_t customSampleOrderCount; + const VkCoarseSampleOrderCustomNV* pCustomSampleOrders; +} VkPipelineViewportCoarseSampleOrderStateCreateInfoNV; + + +typedef void (VKAPI_PTR *PFN_vkCmdBindShadingRateImageNV)(VkCommandBuffer commandBuffer, VkImageView imageView, VkImageLayout imageLayout); +typedef void (VKAPI_PTR *PFN_vkCmdSetViewportShadingRatePaletteNV)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkShadingRatePaletteNV* pShadingRatePalettes); +typedef void (VKAPI_PTR *PFN_vkCmdSetCoarseSampleOrderNV)(VkCommandBuffer commandBuffer, VkCoarseSampleOrderTypeNV sampleOrderType, uint32_t customSampleOrderCount, const VkCoarseSampleOrderCustomNV* pCustomSampleOrders); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindShadingRateImageNV( + VkCommandBuffer commandBuffer, + VkImageView imageView, + VkImageLayout imageLayout); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetViewportShadingRatePaletteNV( + VkCommandBuffer commandBuffer, + uint32_t firstViewport, + uint32_t viewportCount, + const VkShadingRatePaletteNV* pShadingRatePalettes); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetCoarseSampleOrderNV( + VkCommandBuffer commandBuffer, + VkCoarseSampleOrderTypeNV sampleOrderType, + uint32_t customSampleOrderCount, + const VkCoarseSampleOrderCustomNV* pCustomSampleOrders); +#endif + +#define VK_NV_ray_tracing 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureNV) + +#define VK_NV_RAY_TRACING_SPEC_VERSION 3 +#define VK_NV_RAY_TRACING_EXTENSION_NAME "VK_NV_ray_tracing" +#define VK_SHADER_UNUSED_NV (~0U) + + +typedef enum VkRayTracingShaderGroupTypeNV { + VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV = 0, + VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV = 1, + VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV = 2, + VK_RAY_TRACING_SHADER_GROUP_TYPE_BEGIN_RANGE_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV, + VK_RAY_TRACING_SHADER_GROUP_TYPE_END_RANGE_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV, + VK_RAY_TRACING_SHADER_GROUP_TYPE_RANGE_SIZE_NV = (VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV - VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV + 1), + VK_RAY_TRACING_SHADER_GROUP_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkRayTracingShaderGroupTypeNV; + +typedef enum VkGeometryTypeNV { + VK_GEOMETRY_TYPE_TRIANGLES_NV = 0, + VK_GEOMETRY_TYPE_AABBS_NV = 1, + VK_GEOMETRY_TYPE_BEGIN_RANGE_NV = VK_GEOMETRY_TYPE_TRIANGLES_NV, + VK_GEOMETRY_TYPE_END_RANGE_NV = VK_GEOMETRY_TYPE_AABBS_NV, + VK_GEOMETRY_TYPE_RANGE_SIZE_NV = (VK_GEOMETRY_TYPE_AABBS_NV - VK_GEOMETRY_TYPE_TRIANGLES_NV + 1), + VK_GEOMETRY_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkGeometryTypeNV; + +typedef enum VkAccelerationStructureTypeNV { + VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV = 0, + VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV = 1, + VK_ACCELERATION_STRUCTURE_TYPE_BEGIN_RANGE_NV = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV, + VK_ACCELERATION_STRUCTURE_TYPE_END_RANGE_NV = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV, + VK_ACCELERATION_STRUCTURE_TYPE_RANGE_SIZE_NV = (VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV - VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV + 1), + VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkAccelerationStructureTypeNV; + +typedef enum VkCopyAccelerationStructureModeNV { + VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV = 0, + VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV = 1, + VK_COPY_ACCELERATION_STRUCTURE_MODE_BEGIN_RANGE_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV, + VK_COPY_ACCELERATION_STRUCTURE_MODE_END_RANGE_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV, + VK_COPY_ACCELERATION_STRUCTURE_MODE_RANGE_SIZE_NV = (VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV - VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV + 1), + VK_COPY_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_NV = 0x7FFFFFFF +} VkCopyAccelerationStructureModeNV; + +typedef enum VkAccelerationStructureMemoryRequirementsTypeNV { + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV = 0, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV = 1, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV = 2, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BEGIN_RANGE_NV = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_END_RANGE_NV = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_RANGE_SIZE_NV = (VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV + 1), + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkAccelerationStructureMemoryRequirementsTypeNV; + + +typedef enum VkGeometryFlagBitsNV { + VK_GEOMETRY_OPAQUE_BIT_NV = 0x00000001, + VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NV = 0x00000002, + VK_GEOMETRY_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkGeometryFlagBitsNV; +typedef VkFlags VkGeometryFlagsNV; + +typedef enum VkGeometryInstanceFlagBitsNV { + VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV = 0x00000001, + VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_NV = 0x00000002, + VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NV = 0x00000004, + VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NV = 0x00000008, + VK_GEOMETRY_INSTANCE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkGeometryInstanceFlagBitsNV; +typedef VkFlags VkGeometryInstanceFlagsNV; + +typedef enum VkBuildAccelerationStructureFlagBitsNV { + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV = 0x00000001, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV = 0x00000002, + VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV = 0x00000004, + VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV = 0x00000008, + VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV = 0x00000010, + VK_BUILD_ACCELERATION_STRUCTURE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkBuildAccelerationStructureFlagBitsNV; +typedef VkFlags VkBuildAccelerationStructureFlagsNV; + +typedef struct VkRayTracingShaderGroupCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkRayTracingShaderGroupTypeNV type; + uint32_t generalShader; + uint32_t closestHitShader; + uint32_t anyHitShader; + uint32_t intersectionShader; +} VkRayTracingShaderGroupCreateInfoNV; + +typedef struct VkRayTracingPipelineCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo* pStages; + uint32_t groupCount; + const VkRayTracingShaderGroupCreateInfoNV* pGroups; + uint32_t maxRecursionDepth; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkRayTracingPipelineCreateInfoNV; + +typedef struct VkGeometryTrianglesNV { + VkStructureType sType; + const void* pNext; + VkBuffer vertexData; + VkDeviceSize vertexOffset; + uint32_t vertexCount; + VkDeviceSize vertexStride; + VkFormat vertexFormat; + VkBuffer indexData; + VkDeviceSize indexOffset; + uint32_t indexCount; + VkIndexType indexType; + VkBuffer transformData; + VkDeviceSize transformOffset; +} VkGeometryTrianglesNV; + +typedef struct VkGeometryAABBNV { + VkStructureType sType; + const void* pNext; + VkBuffer aabbData; + uint32_t numAABBs; + uint32_t stride; + VkDeviceSize offset; +} VkGeometryAABBNV; + +typedef struct VkGeometryDataNV { + VkGeometryTrianglesNV triangles; + VkGeometryAABBNV aabbs; +} VkGeometryDataNV; + +typedef struct VkGeometryNV { + VkStructureType sType; + const void* pNext; + VkGeometryTypeNV geometryType; + VkGeometryDataNV geometry; + VkGeometryFlagsNV flags; +} VkGeometryNV; + +typedef struct VkAccelerationStructureInfoNV { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureTypeNV type; + VkBuildAccelerationStructureFlagsNV flags; + uint32_t instanceCount; + uint32_t geometryCount; + const VkGeometryNV* pGeometries; +} VkAccelerationStructureInfoNV; + +typedef struct VkAccelerationStructureCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkDeviceSize compactedSize; + VkAccelerationStructureInfoNV info; +} VkAccelerationStructureCreateInfoNV; + +typedef struct VkBindAccelerationStructureMemoryInfoNV { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureNV accelerationStructure; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + uint32_t deviceIndexCount; + const uint32_t* pDeviceIndices; +} VkBindAccelerationStructureMemoryInfoNV; + +typedef struct VkWriteDescriptorSetAccelerationStructureNV { + VkStructureType sType; + const void* pNext; + uint32_t accelerationStructureCount; + const VkAccelerationStructureNV* pAccelerationStructures; +} VkWriteDescriptorSetAccelerationStructureNV; + +typedef struct VkAccelerationStructureMemoryRequirementsInfoNV { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureMemoryRequirementsTypeNV type; + VkAccelerationStructureNV accelerationStructure; +} VkAccelerationStructureMemoryRequirementsInfoNV; + +typedef struct VkPhysicalDeviceRayTracingPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t shaderGroupHandleSize; + uint32_t maxRecursionDepth; + uint32_t maxShaderGroupStride; + uint32_t shaderGroupBaseAlignment; + uint64_t maxGeometryCount; + uint64_t maxInstanceCount; + uint64_t maxTriangleCount; + uint32_t maxDescriptorSetAccelerationStructures; +} VkPhysicalDeviceRayTracingPropertiesNV; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateAccelerationStructureNV)(VkDevice device, const VkAccelerationStructureCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkAccelerationStructureNV* pAccelerationStructure); +typedef void (VKAPI_PTR *PFN_vkDestroyAccelerationStructureNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureMemoryRequirementsNV)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements); +typedef VkResult (VKAPI_PTR *PFN_vkBindAccelerationStructureMemoryNV)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoNV* pBindInfos); +typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureNV)(VkCommandBuffer commandBuffer, const VkAccelerationStructureInfoNV* pInfo, VkBuffer instanceData, VkDeviceSize instanceOffset, VkBool32 update, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkBuffer scratch, VkDeviceSize scratchOffset); +typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureNV)(VkCommandBuffer commandBuffer, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkCopyAccelerationStructureModeNV mode); +typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysNV)(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, VkBuffer callableShaderBindingTableBuffer, VkDeviceSize callableShaderBindingOffset, VkDeviceSize callableShaderBindingStride, uint32_t width, uint32_t height, uint32_t depth); +typedef VkResult (VKAPI_PTR *PFN_vkCreateRayTracingPipelinesNV)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoNV* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +typedef VkResult (VKAPI_PTR *PFN_vkGetRayTracingShaderGroupHandlesNV)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkGetAccelerationStructureHandleNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, size_t dataSize, void* pData); +typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructuresPropertiesNV)(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureNV* pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); +typedef VkResult (VKAPI_PTR *PFN_vkCompileDeferredNV)(VkDevice device, VkPipeline pipeline, uint32_t shader); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateAccelerationStructureNV( + VkDevice device, + const VkAccelerationStructureCreateInfoNV* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkAccelerationStructureNV* pAccelerationStructure); + +VKAPI_ATTR void VKAPI_CALL vkDestroyAccelerationStructureNV( + VkDevice device, + VkAccelerationStructureNV accelerationStructure, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkGetAccelerationStructureMemoryRequirementsNV( + VkDevice device, + const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo, + VkMemoryRequirements2KHR* pMemoryRequirements); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindAccelerationStructureMemoryNV( + VkDevice device, + uint32_t bindInfoCount, + const VkBindAccelerationStructureMemoryInfoNV* pBindInfos); + +VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructureNV( + VkCommandBuffer commandBuffer, + const VkAccelerationStructureInfoNV* pInfo, + VkBuffer instanceData, + VkDeviceSize instanceOffset, + VkBool32 update, + VkAccelerationStructureNV dst, + VkAccelerationStructureNV src, + VkBuffer scratch, + VkDeviceSize scratchOffset); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureNV( + VkCommandBuffer commandBuffer, + VkAccelerationStructureNV dst, + VkAccelerationStructureNV src, + VkCopyAccelerationStructureModeNV mode); + +VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysNV( + VkCommandBuffer commandBuffer, + VkBuffer raygenShaderBindingTableBuffer, + VkDeviceSize raygenShaderBindingOffset, + VkBuffer missShaderBindingTableBuffer, + VkDeviceSize missShaderBindingOffset, + VkDeviceSize missShaderBindingStride, + VkBuffer hitShaderBindingTableBuffer, + VkDeviceSize hitShaderBindingOffset, + VkDeviceSize hitShaderBindingStride, + VkBuffer callableShaderBindingTableBuffer, + VkDeviceSize callableShaderBindingOffset, + VkDeviceSize callableShaderBindingStride, + uint32_t width, + uint32_t height, + uint32_t depth); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateRayTracingPipelinesNV( + VkDevice device, + VkPipelineCache pipelineCache, + uint32_t createInfoCount, + const VkRayTracingPipelineCreateInfoNV* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkPipeline* pPipelines); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetRayTracingShaderGroupHandlesNV( + VkDevice device, + VkPipeline pipeline, + uint32_t firstGroup, + uint32_t groupCount, + size_t dataSize, + void* pData); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetAccelerationStructureHandleNV( + VkDevice device, + VkAccelerationStructureNV accelerationStructure, + size_t dataSize, + void* pData); + +VKAPI_ATTR void VKAPI_CALL vkCmdWriteAccelerationStructuresPropertiesNV( + VkCommandBuffer commandBuffer, + uint32_t accelerationStructureCount, + const VkAccelerationStructureNV* pAccelerationStructures, + VkQueryType queryType, + VkQueryPool queryPool, + uint32_t firstQuery); + +VKAPI_ATTR VkResult VKAPI_CALL vkCompileDeferredNV( + VkDevice device, + VkPipeline pipeline, + uint32_t shader); +#endif + +#define VK_NV_representative_fragment_test 1 +#define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_SPEC_VERSION 1 +#define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_EXTENSION_NAME "VK_NV_representative_fragment_test" + +typedef struct VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 representativeFragmentTest; +} VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV; + +typedef struct VkPipelineRepresentativeFragmentTestStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 representativeFragmentTestEnable; +} VkPipelineRepresentativeFragmentTestStateCreateInfoNV; + + + #define VK_EXT_global_priority 1 #define VK_EXT_GLOBAL_PRIORITY_SPEC_VERSION 2 #define VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME "VK_EXT_global_priority" @@ -7303,8 +8624,96 @@ VKAPI_ATTR void VKAPI_CALL vkCmdWriteBufferMarkerAMD( uint32_t marker); #endif +#define VK_EXT_calibrated_timestamps 1 +#define VK_EXT_CALIBRATED_TIMESTAMPS_SPEC_VERSION 1 +#define VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME "VK_EXT_calibrated_timestamps" + + +typedef enum VkTimeDomainEXT { + VK_TIME_DOMAIN_DEVICE_EXT = 0, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT = 1, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT = 2, + VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT = 3, + VK_TIME_DOMAIN_BEGIN_RANGE_EXT = VK_TIME_DOMAIN_DEVICE_EXT, + VK_TIME_DOMAIN_END_RANGE_EXT = VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT, + VK_TIME_DOMAIN_RANGE_SIZE_EXT = (VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT - VK_TIME_DOMAIN_DEVICE_EXT + 1), + VK_TIME_DOMAIN_MAX_ENUM_EXT = 0x7FFFFFFF +} VkTimeDomainEXT; + +typedef struct VkCalibratedTimestampInfoEXT { + VkStructureType sType; + const void* pNext; + VkTimeDomainEXT timeDomain; +} VkCalibratedTimestampInfoEXT; + + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)(VkPhysicalDevice physicalDevice, uint32_t* pTimeDomainCount, VkTimeDomainEXT* pTimeDomains); +typedef VkResult (VKAPI_PTR *PFN_vkGetCalibratedTimestampsEXT)(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoEXT* pTimestampInfos, uint64_t* pTimestamps, uint64_t* pMaxDeviation); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceCalibrateableTimeDomainsEXT( + VkPhysicalDevice physicalDevice, + uint32_t* pTimeDomainCount, + VkTimeDomainEXT* pTimeDomains); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetCalibratedTimestampsEXT( + VkDevice device, + uint32_t timestampCount, + const VkCalibratedTimestampInfoEXT* pTimestampInfos, + uint64_t* pTimestamps, + uint64_t* pMaxDeviation); +#endif + +#define VK_AMD_shader_core_properties 1 +#define VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION 1 +#define VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_AMD_shader_core_properties" + +typedef struct VkPhysicalDeviceShaderCorePropertiesAMD { + VkStructureType sType; + void* pNext; + uint32_t shaderEngineCount; + uint32_t shaderArraysPerEngineCount; + uint32_t computeUnitsPerShaderArray; + uint32_t simdPerComputeUnit; + uint32_t wavefrontsPerSimd; + uint32_t wavefrontSize; + uint32_t sgprsPerSimd; + uint32_t minSgprAllocation; + uint32_t maxSgprAllocation; + uint32_t sgprAllocationGranularity; + uint32_t vgprsPerSimd; + uint32_t minVgprAllocation; + uint32_t maxVgprAllocation; + uint32_t vgprAllocationGranularity; +} VkPhysicalDeviceShaderCorePropertiesAMD; + + + +#define VK_AMD_memory_overallocation_behavior 1 +#define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_SPEC_VERSION 1 +#define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_EXTENSION_NAME "VK_AMD_memory_overallocation_behavior" + + +typedef enum VkMemoryOverallocationBehaviorAMD { + VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD = 0, + VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD = 1, + VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD = 2, + VK_MEMORY_OVERALLOCATION_BEHAVIOR_BEGIN_RANGE_AMD = VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD, + VK_MEMORY_OVERALLOCATION_BEHAVIOR_END_RANGE_AMD = VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD, + VK_MEMORY_OVERALLOCATION_BEHAVIOR_RANGE_SIZE_AMD = (VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD - VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD + 1), + VK_MEMORY_OVERALLOCATION_BEHAVIOR_MAX_ENUM_AMD = 0x7FFFFFFF +} VkMemoryOverallocationBehaviorAMD; + +typedef struct VkDeviceMemoryOverallocationCreateInfoAMD { + VkStructureType sType; + const void* pNext; + VkMemoryOverallocationBehaviorAMD overallocationBehavior; +} VkDeviceMemoryOverallocationCreateInfoAMD; + + + #define VK_EXT_vertex_attribute_divisor 1 -#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 1 +#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 3 #define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor" typedef struct VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT { @@ -7325,6 +8734,359 @@ typedef struct VkPipelineVertexInputDivisorStateCreateInfoEXT { const VkVertexInputBindingDivisorDescriptionEXT* pVertexBindingDivisors; } VkPipelineVertexInputDivisorStateCreateInfoEXT; +typedef struct VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 vertexAttributeInstanceRateDivisor; + VkBool32 vertexAttributeInstanceRateZeroDivisor; +} VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT; + + + +#define VK_NV_shader_subgroup_partitioned 1 +#define VK_NV_SHADER_SUBGROUP_PARTITIONED_SPEC_VERSION 1 +#define VK_NV_SHADER_SUBGROUP_PARTITIONED_EXTENSION_NAME "VK_NV_shader_subgroup_partitioned" + + +#define VK_NV_compute_shader_derivatives 1 +#define VK_NV_COMPUTE_SHADER_DERIVATIVES_SPEC_VERSION 1 +#define VK_NV_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME "VK_NV_compute_shader_derivatives" + +typedef struct VkPhysicalDeviceComputeShaderDerivativesFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 computeDerivativeGroupQuads; + VkBool32 computeDerivativeGroupLinear; +} VkPhysicalDeviceComputeShaderDerivativesFeaturesNV; + + + +#define VK_NV_mesh_shader 1 +#define VK_NV_MESH_SHADER_SPEC_VERSION 1 +#define VK_NV_MESH_SHADER_EXTENSION_NAME "VK_NV_mesh_shader" + +typedef struct VkPhysicalDeviceMeshShaderFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 taskShader; + VkBool32 meshShader; +} VkPhysicalDeviceMeshShaderFeaturesNV; + +typedef struct VkPhysicalDeviceMeshShaderPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t maxDrawMeshTasksCount; + uint32_t maxTaskWorkGroupInvocations; + uint32_t maxTaskWorkGroupSize[3]; + uint32_t maxTaskTotalMemorySize; + uint32_t maxTaskOutputCount; + uint32_t maxMeshWorkGroupInvocations; + uint32_t maxMeshWorkGroupSize[3]; + uint32_t maxMeshTotalMemorySize; + uint32_t maxMeshOutputVertices; + uint32_t maxMeshOutputPrimitives; + uint32_t maxMeshMultiviewViewCount; + uint32_t meshOutputPerVertexGranularity; + uint32_t meshOutputPerPrimitiveGranularity; +} VkPhysicalDeviceMeshShaderPropertiesNV; + +typedef struct VkDrawMeshTasksIndirectCommandNV { + uint32_t taskCount; + uint32_t firstTask; +} VkDrawMeshTasksIndirectCommandNV; + + +typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksNV)(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask); +typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksIndirectNV)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksIndirectCountNV)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksNV( + VkCommandBuffer commandBuffer, + uint32_t taskCount, + uint32_t firstTask); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksIndirectNV( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + uint32_t drawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksIndirectCountNV( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); +#endif + +#define VK_NV_fragment_shader_barycentric 1 +#define VK_NV_FRAGMENT_SHADER_BARYCENTRIC_SPEC_VERSION 1 +#define VK_NV_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME "VK_NV_fragment_shader_barycentric" + +typedef struct VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 fragmentShaderBarycentric; +} VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV; + + + +#define VK_NV_shader_image_footprint 1 +#define VK_NV_SHADER_IMAGE_FOOTPRINT_SPEC_VERSION 1 +#define VK_NV_SHADER_IMAGE_FOOTPRINT_EXTENSION_NAME "VK_NV_shader_image_footprint" + +typedef struct VkPhysicalDeviceShaderImageFootprintFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 imageFootprint; +} VkPhysicalDeviceShaderImageFootprintFeaturesNV; + + + +#define VK_NV_scissor_exclusive 1 +#define VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION 1 +#define VK_NV_SCISSOR_EXCLUSIVE_EXTENSION_NAME "VK_NV_scissor_exclusive" + +typedef struct VkPipelineViewportExclusiveScissorStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + uint32_t exclusiveScissorCount; + const VkRect2D* pExclusiveScissors; +} VkPipelineViewportExclusiveScissorStateCreateInfoNV; + +typedef struct VkPhysicalDeviceExclusiveScissorFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 exclusiveScissor; +} VkPhysicalDeviceExclusiveScissorFeaturesNV; + + +typedef void (VKAPI_PTR *PFN_vkCmdSetExclusiveScissorNV)(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor, uint32_t exclusiveScissorCount, const VkRect2D* pExclusiveScissors); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetExclusiveScissorNV( + VkCommandBuffer commandBuffer, + uint32_t firstExclusiveScissor, + uint32_t exclusiveScissorCount, + const VkRect2D* pExclusiveScissors); +#endif + +#define VK_NV_device_diagnostic_checkpoints 1 +#define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_SPEC_VERSION 2 +#define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME "VK_NV_device_diagnostic_checkpoints" + +typedef struct VkQueueFamilyCheckpointPropertiesNV { + VkStructureType sType; + void* pNext; + VkPipelineStageFlags checkpointExecutionStageMask; +} VkQueueFamilyCheckpointPropertiesNV; + +typedef struct VkCheckpointDataNV { + VkStructureType sType; + void* pNext; + VkPipelineStageFlagBits stage; + void* pCheckpointMarker; +} VkCheckpointDataNV; + + +typedef void (VKAPI_PTR *PFN_vkCmdSetCheckpointNV)(VkCommandBuffer commandBuffer, const void* pCheckpointMarker); +typedef void (VKAPI_PTR *PFN_vkGetQueueCheckpointDataNV)(VkQueue queue, uint32_t* pCheckpointDataCount, VkCheckpointDataNV* pCheckpointData); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetCheckpointNV( + VkCommandBuffer commandBuffer, + const void* pCheckpointMarker); + +VKAPI_ATTR void VKAPI_CALL vkGetQueueCheckpointDataNV( + VkQueue queue, + uint32_t* pCheckpointDataCount, + VkCheckpointDataNV* pCheckpointData); +#endif + +#define VK_EXT_pci_bus_info 1 +#define VK_EXT_PCI_BUS_INFO_SPEC_VERSION 2 +#define VK_EXT_PCI_BUS_INFO_EXTENSION_NAME "VK_EXT_pci_bus_info" + +typedef struct VkPhysicalDevicePCIBusInfoPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t pciDomain; + uint32_t pciBus; + uint32_t pciDevice; + uint32_t pciFunction; +} VkPhysicalDevicePCIBusInfoPropertiesEXT; + + + +#define VK_EXT_fragment_density_map 1 +#define VK_EXT_FRAGMENT_DENSITY_MAP_SPEC_VERSION 1 +#define VK_EXT_FRAGMENT_DENSITY_MAP_EXTENSION_NAME "VK_EXT_fragment_density_map" + +typedef struct VkPhysicalDeviceFragmentDensityMapFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 fragmentDensityMap; + VkBool32 fragmentDensityMapDynamic; + VkBool32 fragmentDensityMapNonSubsampledImages; +} VkPhysicalDeviceFragmentDensityMapFeaturesEXT; + +typedef struct VkPhysicalDeviceFragmentDensityMapPropertiesEXT { + VkStructureType sType; + void* pNext; + VkExtent2D minFragmentDensityTexelSize; + VkExtent2D maxFragmentDensityTexelSize; + VkBool32 fragmentDensityInvocations; +} VkPhysicalDeviceFragmentDensityMapPropertiesEXT; + +typedef struct VkRenderPassFragmentDensityMapCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkAttachmentReference fragmentDensityMapAttachment; +} VkRenderPassFragmentDensityMapCreateInfoEXT; + + + +#define VK_EXT_scalar_block_layout 1 +#define VK_EXT_SCALAR_BLOCK_LAYOUT_SPEC_VERSION 1 +#define VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME "VK_EXT_scalar_block_layout" + +typedef struct VkPhysicalDeviceScalarBlockLayoutFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 scalarBlockLayout; +} VkPhysicalDeviceScalarBlockLayoutFeaturesEXT; + + + +#define VK_GOOGLE_hlsl_functionality1 1 +#define VK_GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION 1 +#define VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME "VK_GOOGLE_hlsl_functionality1" + + +#define VK_GOOGLE_decorate_string 1 +#define VK_GOOGLE_DECORATE_STRING_SPEC_VERSION 1 +#define VK_GOOGLE_DECORATE_STRING_EXTENSION_NAME "VK_GOOGLE_decorate_string" + + +#define VK_EXT_memory_budget 1 +#define VK_EXT_MEMORY_BUDGET_SPEC_VERSION 1 +#define VK_EXT_MEMORY_BUDGET_EXTENSION_NAME "VK_EXT_memory_budget" + +typedef struct VkPhysicalDeviceMemoryBudgetPropertiesEXT { + VkStructureType sType; + void* pNext; + VkDeviceSize heapBudget[VK_MAX_MEMORY_HEAPS]; + VkDeviceSize heapUsage[VK_MAX_MEMORY_HEAPS]; +} VkPhysicalDeviceMemoryBudgetPropertiesEXT; + + + +#define VK_EXT_memory_priority 1 +#define VK_EXT_MEMORY_PRIORITY_SPEC_VERSION 1 +#define VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME "VK_EXT_memory_priority" + +typedef struct VkPhysicalDeviceMemoryPriorityFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 memoryPriority; +} VkPhysicalDeviceMemoryPriorityFeaturesEXT; + +typedef struct VkMemoryPriorityAllocateInfoEXT { + VkStructureType sType; + const void* pNext; + float priority; +} VkMemoryPriorityAllocateInfoEXT; + + + +#define VK_EXT_buffer_device_address 1 +typedef uint64_t VkDeviceAddress; + +#define VK_EXT_BUFFER_DEVICE_ADDRESS_SPEC_VERSION 2 +#define VK_EXT_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME "VK_EXT_buffer_device_address" + +typedef struct VkPhysicalDeviceBufferAddressFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; +} VkPhysicalDeviceBufferAddressFeaturesEXT; + +typedef struct VkBufferDeviceAddressInfoEXT { + VkStructureType sType; + const void* pNext; + VkBuffer buffer; +} VkBufferDeviceAddressInfoEXT; + +typedef struct VkBufferDeviceAddressCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkDeviceSize deviceAddress; +} VkBufferDeviceAddressCreateInfoEXT; + + +typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetBufferDeviceAddressEXT)(VkDevice device, const VkBufferDeviceAddressInfoEXT* pInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkDeviceAddress VKAPI_CALL vkGetBufferDeviceAddressEXT( + VkDevice device, + const VkBufferDeviceAddressInfoEXT* pInfo); +#endif + +#define VK_EXT_separate_stencil_usage 1 +#define VK_EXT_SEPARATE_STENCIL_USAGE_SPEC_VERSION 1 +#define VK_EXT_SEPARATE_STENCIL_USAGE_EXTENSION_NAME "VK_EXT_separate_stencil_usage" + +typedef struct VkImageStencilUsageCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkImageUsageFlags stencilUsage; +} VkImageStencilUsageCreateInfoEXT; + + + +#define VK_EXT_validation_features 1 +#define VK_EXT_VALIDATION_FEATURES_SPEC_VERSION 1 +#define VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME "VK_EXT_validation_features" + + +typedef enum VkValidationFeatureEnableEXT { + VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT = 0, + VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT = 1, + VK_VALIDATION_FEATURE_ENABLE_BEGIN_RANGE_EXT = VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT, + VK_VALIDATION_FEATURE_ENABLE_END_RANGE_EXT = VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT, + VK_VALIDATION_FEATURE_ENABLE_RANGE_SIZE_EXT = (VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT - VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT + 1), + VK_VALIDATION_FEATURE_ENABLE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationFeatureEnableEXT; + +typedef enum VkValidationFeatureDisableEXT { + VK_VALIDATION_FEATURE_DISABLE_ALL_EXT = 0, + VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT = 1, + VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT = 2, + VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT = 3, + VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT = 4, + VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT = 5, + VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT = 6, + VK_VALIDATION_FEATURE_DISABLE_BEGIN_RANGE_EXT = VK_VALIDATION_FEATURE_DISABLE_ALL_EXT, + VK_VALIDATION_FEATURE_DISABLE_END_RANGE_EXT = VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT, + VK_VALIDATION_FEATURE_DISABLE_RANGE_SIZE_EXT = (VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT - VK_VALIDATION_FEATURE_DISABLE_ALL_EXT + 1), + VK_VALIDATION_FEATURE_DISABLE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationFeatureDisableEXT; + +typedef struct VkValidationFeaturesEXT { + VkStructureType sType; + const void* pNext; + uint32_t enabledValidationFeatureCount; + const VkValidationFeatureEnableEXT* pEnabledValidationFeatures; + uint32_t disabledValidationFeatureCount; + const VkValidationFeatureDisableEXT* pDisabledValidationFeatures; +} VkValidationFeaturesEXT; + #ifdef __cplusplus diff --git a/ext/vulkan/vulkan_fuchsia.h b/ext/vulkan/vulkan_fuchsia.h new file mode 100644 index 0000000000..1c335fd386 --- /dev/null +++ b/ext/vulkan/vulkan_fuchsia.h @@ -0,0 +1,58 @@ +#ifndef VULKAN_FUCHSIA_H_ +#define VULKAN_FUCHSIA_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Copyright (c) 2015-2019 The Khronos Group Inc. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#define VK_FUCHSIA_imagepipe_surface 1 +#define VK_FUCHSIA_IMAGEPIPE_SURFACE_SPEC_VERSION 1 +#define VK_FUCHSIA_IMAGEPIPE_SURFACE_EXTENSION_NAME "VK_FUCHSIA_imagepipe_surface" + +typedef VkFlags VkImagePipeSurfaceCreateFlagsFUCHSIA; + +typedef struct VkImagePipeSurfaceCreateInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + VkImagePipeSurfaceCreateFlagsFUCHSIA flags; + zx_handle_t imagePipeHandle; +} VkImagePipeSurfaceCreateInfoFUCHSIA; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateImagePipeSurfaceFUCHSIA)(VkInstance instance, const VkImagePipeSurfaceCreateInfoFUCHSIA* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateImagePipeSurfaceFUCHSIA( + VkInstance instance, + const VkImagePipeSurfaceCreateInfoFUCHSIA* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/vulkan/vulkan_ios.h b/ext/vulkan/vulkan_ios.h index a0924816d5..d221a9baad 100644 --- a/ext/vulkan/vulkan_ios.h +++ b/ext/vulkan/vulkan_ios.h @@ -6,7 +6,7 @@ extern "C" { #endif /* -** Copyright (c) 2015-2018 The Khronos Group Inc. +** Copyright (c) 2015-2019 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/ext/vulkan/vulkan_macos.h b/ext/vulkan/vulkan_macos.h index ff0b701801..5d6b6aeb9a 100644 --- a/ext/vulkan/vulkan_macos.h +++ b/ext/vulkan/vulkan_macos.h @@ -6,7 +6,7 @@ extern "C" { #endif /* -** Copyright (c) 2015-2018 The Khronos Group Inc. +** Copyright (c) 2015-2019 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/ext/vulkan/vulkan_vi.h b/ext/vulkan/vulkan_vi.h index 015166bfc6..3e37bab69a 100644 --- a/ext/vulkan/vulkan_vi.h +++ b/ext/vulkan/vulkan_vi.h @@ -6,7 +6,7 @@ extern "C" { #endif /* -** Copyright (c) 2015-2018 The Khronos Group Inc. +** Copyright (c) 2015-2019 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/ext/vulkan/vulkan_wayland.h b/ext/vulkan/vulkan_wayland.h index 5ba0827aa3..33a22de3bd 100644 --- a/ext/vulkan/vulkan_wayland.h +++ b/ext/vulkan/vulkan_wayland.h @@ -6,7 +6,7 @@ extern "C" { #endif /* -** Copyright (c) 2015-2018 The Khronos Group Inc. +** Copyright (c) 2015-2019 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/ext/vulkan/vulkan_win32.h b/ext/vulkan/vulkan_win32.h index 6a85409ebe..b9d63d47f4 100644 --- a/ext/vulkan/vulkan_win32.h +++ b/ext/vulkan/vulkan_win32.h @@ -6,7 +6,7 @@ extern "C" { #endif /* -** Copyright (c) 2015-2018 The Khronos Group Inc. +** Copyright (c) 2015-2019 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/ext/vulkan/vulkan_xcb.h b/ext/vulkan/vulkan_xcb.h index ba03600602..f21290974a 100644 --- a/ext/vulkan/vulkan_xcb.h +++ b/ext/vulkan/vulkan_xcb.h @@ -6,7 +6,7 @@ extern "C" { #endif /* -** Copyright (c) 2015-2018 The Khronos Group Inc. +** Copyright (c) 2015-2019 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/ext/vulkan/vulkan_xlib.h b/ext/vulkan/vulkan_xlib.h index e1d967e018..ce3d36ddcf 100644 --- a/ext/vulkan/vulkan_xlib.h +++ b/ext/vulkan/vulkan_xlib.h @@ -6,7 +6,7 @@ extern "C" { #endif /* -** Copyright (c) 2015-2018 The Khronos Group Inc. +** Copyright (c) 2015-2019 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/ext/vulkan/vulkan_xlib_xrandr.h b/ext/vulkan/vulkan_xlib_xrandr.h index 117d01799e..25efb077f7 100644 --- a/ext/vulkan/vulkan_xlib_xrandr.h +++ b/ext/vulkan/vulkan_xlib_xrandr.h @@ -6,7 +6,7 @@ extern "C" { #endif /* -** Copyright (c) 2015-2018 The Khronos Group Inc. +** Copyright (c) 2015-2019 The Khronos Group Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. From 992cea10825c589fb543de83c553d824c2daee1d Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 31 Jan 2019 13:53:27 +0100 Subject: [PATCH 303/347] Load a function from VK_EXT_external_memory_host --- Common/Vulkan/VulkanLoader.cpp | 3 +++ Common/Vulkan/VulkanLoader.h | 3 +++ GPU/Vulkan/GPU_Vulkan.cpp | 1 + 3 files changed, 7 insertions(+) diff --git a/Common/Vulkan/VulkanLoader.cpp b/Common/Vulkan/VulkanLoader.cpp index 81d141b778..3dfb3882bd 100644 --- a/Common/Vulkan/VulkanLoader.cpp +++ b/Common/Vulkan/VulkanLoader.cpp @@ -196,6 +196,8 @@ PFN_vkQueuePresentKHR vkQueuePresentKHR; PFN_vkCreateDebugReportCallbackEXT dyn_vkCreateDebugReportCallbackEXT; PFN_vkDestroyDebugReportCallbackEXT dyn_vkDestroyDebugReportCallbackEXT; +PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT; + #ifdef _WIN32 static HINSTANCE vulkanLibrary; @@ -583,6 +585,7 @@ void VulkanLoadDeviceFunctions(VkDevice device) { LOAD_DEVICE_FUNC(device, vkGetSwapchainImagesKHR); LOAD_DEVICE_FUNC(device, vkAcquireNextImageKHR); LOAD_DEVICE_FUNC(device, vkQueuePresentKHR); + LOAD_DEVICE_FUNC(device, vkGetMemoryHostPointerPropertiesEXT); } void VulkanFree() { diff --git a/Common/Vulkan/VulkanLoader.h b/Common/Vulkan/VulkanLoader.h index 680fbe46ac..990f330c0e 100644 --- a/Common/Vulkan/VulkanLoader.h +++ b/Common/Vulkan/VulkanLoader.h @@ -200,6 +200,9 @@ extern PFN_vkQueuePresentKHR vkQueuePresentKHR; extern PFN_vkCreateDebugReportCallbackEXT dyn_vkCreateDebugReportCallbackEXT; extern PFN_vkDestroyDebugReportCallbackEXT dyn_vkDestroyDebugReportCallbackEXT; +// Assorted other extensions. +extern PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT; + // Way to do a quick check before even attempting to load. bool VulkanMayBeAvailable(); diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 286195898b..216b1300d0 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -249,6 +249,7 @@ void GPU_Vulkan::CheckGPUFeatures() { else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) { features |= GPU_ROUND_DEPTH_TO_16BIT; } + gstate_c.featureFlags = features; } From f339a0c15b904afe28994601e2d1a616f01f0be6 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 31 Jan 2019 14:09:21 +0100 Subject: [PATCH 304/347] VK: Minor cleanup, turn off unfinished and probably wrong use of dedicated allocation feature --- Common/Vulkan/VulkanContext.cpp | 5 ++--- Common/Vulkan/VulkanContext.h | 3 ++- Windows/GPU/WindowsVulkanContext.cpp | 3 --- Windows/GPU/WindowsVulkanContext.h | 1 - ext/native/thin3d/VulkanRenderManager.cpp | 2 ++ 5 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index 9df43d902b..3a62f176a9 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -588,9 +588,8 @@ VkResult VulkanContext::CreateDevice() { } assert(found); - if (EnableDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME)) { - deviceExtensionsLookup_.DEDICATED_ALLOCATION = EnableDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); - } + deviceExtensionsLookup_.KHR_dedicated_allocation = EnableDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); + deviceExtensionsLookup_.EXT_external_memory_host = EnableDeviceExtension(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME); VkDeviceCreateInfo device_info{ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; device_info.queueCreateInfoCount = 1; diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index 9cd169a71c..22a1eb13d6 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -103,7 +103,8 @@ private: // For fast extension-enabled checks. struct VulkanDeviceExtensions { - bool DEDICATED_ALLOCATION; + bool KHR_dedicated_allocation; + bool EXT_external_memory_host; }; // Useful for debugging on ARM Mali. This eliminates transaction elimination diff --git a/Windows/GPU/WindowsVulkanContext.cpp b/Windows/GPU/WindowsVulkanContext.cpp index 541d435ec9..3c9bf4e724 100644 --- a/Windows/GPU/WindowsVulkanContext.cpp +++ b/Windows/GPU/WindowsVulkanContext.cpp @@ -117,9 +117,6 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m g_Config.sVulkanDevice = g_Vulkan->GetPhysicalDeviceProperties(deviceNum).deviceName; } g_Vulkan->ChooseDevice(deviceNum); - if (g_Vulkan->EnableDeviceExtension(VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME)) { - supportsDedicatedAlloc_ = true; - } if (g_Vulkan->CreateDevice() != VK_SUCCESS) { *error_message = g_Vulkan->InitError(); delete g_Vulkan; diff --git a/Windows/GPU/WindowsVulkanContext.h b/Windows/GPU/WindowsVulkanContext.h index 6c9f0f42dd..0a00dfeab8 100644 --- a/Windows/GPU/WindowsVulkanContext.h +++ b/Windows/GPU/WindowsVulkanContext.h @@ -35,6 +35,5 @@ public: Draw::DrawContext *GetDrawContext() override { return draw_; } private: Draw::DrawContext *draw_; - bool supportsDedicatedAlloc_; }; diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index 185968d6c7..55bf1daec1 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -47,6 +47,7 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int VkMemoryAllocateInfo alloc{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; alloc.allocationSize = memreq.size; + /* // Hint to the driver that this allocation is image-specific. Some drivers benefit. // We only bother supporting the KHR extension, not the old NV one. VkMemoryDedicatedAllocateInfoKHR dedicated{ VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR }; @@ -54,6 +55,7 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int alloc.pNext = &dedicated; dedicated.image = img.image; } + */ vulkan->MemoryTypeFromProperties(memreq.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &alloc.memoryTypeIndex); VkResult res = vkAllocateMemory(vulkan->GetDevice(), &alloc, nullptr, &img.memory); From b143e47fb62e227a3982b4c125c425446b850adf Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 31 Jan 2019 14:18:13 +0100 Subject: [PATCH 305/347] VK: Load the dedicated allocation extension properly (but don't use it yet). --- Common/Vulkan/VulkanContext.cpp | 5 ++++- Common/Vulkan/VulkanContext.h | 1 + Common/Vulkan/VulkanLoader.cpp | 6 +++++- Common/Vulkan/VulkanLoader.h | 2 ++ 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index 3a62f176a9..6b9284ef29 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -588,7 +588,10 @@ VkResult VulkanContext::CreateDevice() { } assert(found); - deviceExtensionsLookup_.KHR_dedicated_allocation = EnableDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); + if (EnableDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME)) { + deviceExtensionsLookup_.KHR_get_memory_requirements2 = true; + deviceExtensionsLookup_.KHR_dedicated_allocation = EnableDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); + } deviceExtensionsLookup_.EXT_external_memory_host = EnableDeviceExtension(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME); VkDeviceCreateInfo device_info{ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index 22a1eb13d6..ae1687a3ce 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -103,6 +103,7 @@ private: // For fast extension-enabled checks. struct VulkanDeviceExtensions { + bool KHR_get_memory_requirements2; bool KHR_dedicated_allocation; bool EXT_external_memory_host; }; diff --git a/Common/Vulkan/VulkanLoader.cpp b/Common/Vulkan/VulkanLoader.cpp index 3dfb3882bd..132394018e 100644 --- a/Common/Vulkan/VulkanLoader.cpp +++ b/Common/Vulkan/VulkanLoader.cpp @@ -197,7 +197,8 @@ PFN_vkCreateDebugReportCallbackEXT dyn_vkCreateDebugReportCallbackEXT; PFN_vkDestroyDebugReportCallbackEXT dyn_vkDestroyDebugReportCallbackEXT; PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT; - +PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; +PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; #ifdef _WIN32 static HINSTANCE vulkanLibrary; @@ -586,6 +587,9 @@ void VulkanLoadDeviceFunctions(VkDevice device) { LOAD_DEVICE_FUNC(device, vkAcquireNextImageKHR); LOAD_DEVICE_FUNC(device, vkQueuePresentKHR); LOAD_DEVICE_FUNC(device, vkGetMemoryHostPointerPropertiesEXT); + LOAD_DEVICE_FUNC(device, vkGetBufferMemoryRequirements2KHR); + LOAD_DEVICE_FUNC(device, vkGetImageMemoryRequirements2KHR); + } void VulkanFree() { diff --git a/Common/Vulkan/VulkanLoader.h b/Common/Vulkan/VulkanLoader.h index 990f330c0e..6d5aad6ddc 100644 --- a/Common/Vulkan/VulkanLoader.h +++ b/Common/Vulkan/VulkanLoader.h @@ -201,6 +201,8 @@ extern PFN_vkCreateDebugReportCallbackEXT dyn_vkCreateDebugReportCallbackEXT; extern PFN_vkDestroyDebugReportCallbackEXT dyn_vkDestroyDebugReportCallbackEXT; // Assorted other extensions. +extern PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; +extern PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; extern PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT; From 46649a218e0ac346143ff3b84b5393ebadd871b3 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 3 Feb 2019 13:58:24 -0800 Subject: [PATCH 306/347] Core: Add flags to disable jit features. Not actually disabling yet, just setup. --- Core/Config.cpp | 1 + Core/Config.h | 1 + Core/MIPS/IR/IRInst.h | 1 + Core/MIPS/IR/IRJit.cpp | 3 ++- Core/MIPS/JitCommon/JitState.cpp | 21 ++++++++++++++------- Core/MIPS/JitCommon/JitState.h | 31 +++++++++++++++++++++++++++++++ 6 files changed, 50 insertions(+), 8 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index aeb37ff61e..8326658d1d 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -466,6 +466,7 @@ static ConfigSetting cpuSettings[] = { ConfigSetting("HideSlowWarnings", &g_Config.bHideSlowWarnings, false, true, false), ConfigSetting("HideStateWarnings", &g_Config.bHideStateWarnings, false, true, false), ConfigSetting("PreloadFunctions", &g_Config.bPreloadFunctions, false, true, true), + ConfigSetting("JitDisableFlags", &g_Config.uJitDisableFlags, (uint32_t)0, true, true), ReportedConfigSetting("CPUSpeed", &g_Config.iLockedCPUSpeed, 0, true, true), ConfigSetting(false), diff --git a/Core/Config.h b/Core/Config.h index d0c8598d8f..c5cf22f545 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -93,6 +93,7 @@ public: bool bHideSlowWarnings; bool bHideStateWarnings; bool bPreloadFunctions; + uint32_t uJitDisableFlags; bool bSeparateSASThread; bool bSeparateIOThread; diff --git a/Core/MIPS/IR/IRInst.h b/Core/MIPS/IR/IRInst.h index cccc1ba55b..a5ec8a8434 100644 --- a/Core/MIPS/IR/IRInst.h +++ b/Core/MIPS/IR/IRInst.h @@ -369,6 +369,7 @@ private: }; struct IROptions { + uint32_t disableFlags; bool unalignedLoadStore; }; diff --git a/Core/MIPS/IR/IRJit.cpp b/Core/MIPS/IR/IRJit.cpp index 63114371e4..ec9a2fdabb 100644 --- a/Core/MIPS/IR/IRJit.cpp +++ b/Core/MIPS/IR/IRJit.cpp @@ -44,7 +44,8 @@ IRJit::IRJit(MIPSState *mips) : frontend_(mips->HasDefaultPrefix()), mips_(mips) InitIR(); IROptions opts{}; - opts.unalignedLoadStore = true; + opts.disableFlags = g_Config.uJitDisableFlags; + opts.unalignedLoadStore = opts.disableFlags & (uint32_t)JitDisable::LSU_UNALIGNED; frontend_.SetOptions(opts); } diff --git a/Core/MIPS/JitCommon/JitState.cpp b/Core/MIPS/JitCommon/JitState.cpp index 7a603daf50..895589cadf 100644 --- a/Core/MIPS/JitCommon/JitState.cpp +++ b/Core/MIPS/JitCommon/JitState.cpp @@ -16,35 +16,38 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "Common/CPUDetect.h" +#include "Core/Config.h" #include "Core/MIPS/JitCommon/JitState.h" #include "Common/MemoryUtil.h" namespace MIPSComp { JitOptions::JitOptions() { + disableFlags = g_Config.uJitDisableFlags; + // x86 - enableVFPUSIMD = true; + enableVFPUSIMD = !Disabled(JitDisable::SIMD); // Set by Asm if needed. reserveR15ForAsm = false; // ARM/ARM64 useBackJump = false; useForwardJump = false; - cachePointers = true; + cachePointers = !Disabled(JitDisable::CACHE_POINTERS); // ARM only downcountInRegister = true; useNEONVFPU = false; // true - if (!cpu_info.bNEON) + if (!cpu_info.bNEON || Disabled(JitDisable::SIMD)) useNEONVFPU = false; //ARM64 - useASIMDVFPU = false; // true + useASIMDVFPU = false; // !Disabled(JitDisable::SIMD); // Common // We can get block linking to work with W^X by doing even more unprotect/re-protect, but let's try without first. // enableBlocklink = !PlatformIsWXExclusive(); // Revert to this line if block linking is slow in W^X mode - enableBlocklink = true; + enableBlocklink = !Disabled(JitDisable::BLOCKLINK); immBranches = false; continueBranches = false; continueJumps = false; @@ -53,9 +56,13 @@ namespace MIPSComp { useStaticAlloc = false; enablePointerify = false; #if PPSSPP_ARCH(ARM64) - useStaticAlloc = true; + useStaticAlloc = !Disabled(JitDisable::STATIC_ALLOC); // iOS/etc. may disable at runtime if Memory::base is not nicely aligned. - enablePointerify = true; + enablePointerify = !Disabled(JitDisable::POINTERIFY); #endif } + + bool JitOptions::Disabled(JitDisable bit) { + return (disableFlags & (uint32_t)bit) != 0; + } } diff --git a/Core/MIPS/JitCommon/JitState.h b/Core/MIPS/JitCommon/JitState.h index 6d2c8d0937..c4b31274f3 100644 --- a/Core/MIPS/JitCommon/JitState.h +++ b/Core/MIPS/JitCommon/JitState.h @@ -173,9 +173,40 @@ namespace MIPSComp { } }; + enum class JitDisable { + ALU = 0x0001, + ALU_IMM = 0x0002, + ALU_BIT = 0x0004, + MULDIV = 0x0008, + + FPU = 0x0010, + FPU_COMP = 0x0040, + FPU_XFER = 0x0080, + + VFPU_VEC = 0x0100, + VFPU_MTX = 0x0200, + VFPU_COMP = 0x0400, + VFPU_XFER = 0x0800, + + LSU = 0x1000, + LSU_UNALIGNED = 0x2000, + LSU_FPU = 0x4000, + LSU_VFPU = 0x8000, + + SIMD = 0x00100000, + BLOCKLINK = 0x00200000, + POINTERIFY = 0x00400000, + STATIC_ALLOC = 0x00800000, + CACHE_POINTERS = 0x01000000, + }; + struct JitOptions { JitOptions(); + bool Disabled(JitDisable bit); + + uint32_t disableFlags; + // x86 bool enableVFPUSIMD; bool reserveR15ForAsm; From 419c1fbd7311e59082231b2a9623a58482a248b3 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 3 Feb 2019 14:01:51 -0800 Subject: [PATCH 307/347] Jit: Respect flags for jit types and features. Left some free space for more. --- Core/MIPS/ARM/ArmCompALU.cpp | 18 +++--- Core/MIPS/ARM/ArmCompFPU.cpp | 12 ++-- Core/MIPS/ARM/ArmCompLoadStore.cpp | 8 +-- Core/MIPS/ARM/ArmCompVFPU.cpp | 66 +++++++++++----------- Core/MIPS/ARM/ArmCompVFPUNEON.cpp | 55 ++++++++++--------- Core/MIPS/ARM64/Arm64CompALU.cpp | 18 +++--- Core/MIPS/ARM64/Arm64CompFPU.cpp | 12 ++-- Core/MIPS/ARM64/Arm64CompLoadStore.cpp | 8 +-- Core/MIPS/ARM64/Arm64CompVFPU.cpp | 61 +++++++++++---------- Core/MIPS/IR/IRCompALU.cpp | 18 +++--- Core/MIPS/IR/IRCompFPU.cpp | 12 ++-- Core/MIPS/IR/IRCompLoadStore.cpp | 6 +- Core/MIPS/IR/IRCompVFPU.cpp | 76 +++++++++++++------------- Core/MIPS/x86/CompALU.cpp | 20 +++---- Core/MIPS/x86/CompFPU.cpp | 12 ++-- Core/MIPS/x86/CompLoadStore.cpp | 20 +++---- Core/MIPS/x86/CompVFPU.cpp | 72 ++++++++++++------------ 17 files changed, 248 insertions(+), 246 deletions(-) diff --git a/Core/MIPS/ARM/ArmCompALU.cpp b/Core/MIPS/ARM/ArmCompALU.cpp index 13788a5d93..66d12ed8a9 100644 --- a/Core/MIPS/ARM/ArmCompALU.cpp +++ b/Core/MIPS/ARM/ArmCompALU.cpp @@ -43,7 +43,7 @@ using namespace MIPSAnalyst; // Currently known non working ones should have DISABLE. // #define CONDITIONAL_DISABLE { Comp_Generic(op); return; } -#define CONDITIONAL_DISABLE ; +#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; } #define DISABLE { Comp_Generic(op); return; } namespace MIPSComp @@ -72,7 +72,7 @@ namespace MIPSComp void ArmJit::Comp_IType(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU_IMM); s32 simm = (s32)(s16)(op & 0xFFFF); // sign extension u32 uimm = op & 0xFFFF; u32 suimm = (u32)(s32)simm; @@ -150,7 +150,7 @@ namespace MIPSComp void ArmJit::Comp_RType2(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU_BIT); MIPSGPReg rs = _RS; MIPSGPReg rd = _RD; @@ -234,7 +234,7 @@ namespace MIPSComp void ArmJit::Comp_RType3(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU); MIPSGPReg rt = _RT; MIPSGPReg rs = _RS; MIPSGPReg rd = _RD; @@ -502,7 +502,7 @@ namespace MIPSComp void ArmJit::Comp_ShiftType(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU); MIPSGPReg rs = _RS; MIPSGPReg rd = _RD; int fd = _FD; @@ -529,7 +529,7 @@ namespace MIPSComp void ArmJit::Comp_Special3(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU_BIT); MIPSGPReg rs = _RS; MIPSGPReg rt = _RT; @@ -591,7 +591,7 @@ namespace MIPSComp void ArmJit::Comp_Allegrex(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU_BIT); MIPSGPReg rt = _RT; MIPSGPReg rd = _RD; // Don't change $zr. @@ -645,7 +645,7 @@ namespace MIPSComp void ArmJit::Comp_Allegrex2(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU_BIT); MIPSGPReg rt = _RT; MIPSGPReg rd = _RD; // Don't change $zr. @@ -677,7 +677,7 @@ namespace MIPSComp void ArmJit::Comp_MulDivType(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(MULDIV); MIPSGPReg rt = _RT; MIPSGPReg rs = _RS; MIPSGPReg rd = _RD; diff --git a/Core/MIPS/ARM/ArmCompFPU.cpp b/Core/MIPS/ARM/ArmCompFPU.cpp index f4ec293382..cc49148d61 100644 --- a/Core/MIPS/ARM/ArmCompFPU.cpp +++ b/Core/MIPS/ARM/ArmCompFPU.cpp @@ -44,7 +44,7 @@ // Currently known non working ones should have DISABLE. // #define CONDITIONAL_DISABLE { Comp_Generic(op); return; } -#define CONDITIONAL_DISABLE ; +#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; } #define DISABLE { Comp_Generic(op); return; } namespace MIPSComp @@ -54,7 +54,7 @@ namespace MIPSComp void ArmJit::Comp_FPU3op(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(FPU); int ft = _FT; int fs = _FS; @@ -92,7 +92,7 @@ extern int logBlocks; void ArmJit::Comp_FPULS(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU_FPU); CheckMemoryBreakpoint(); s32 offset = (s16)(op & 0xFFFF); @@ -193,7 +193,7 @@ void ArmJit::Comp_FPULS(MIPSOpcode op) } void ArmJit::Comp_FPUComp(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(FPU_COMP); int opc = op & 0xF; if (opc >= 8) opc -= 8; // alias @@ -258,7 +258,7 @@ void ArmJit::Comp_FPUComp(MIPSOpcode op) { } void ArmJit::Comp_FPU2op(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(FPU); int fs = _FS; int fd = _FD; @@ -350,7 +350,7 @@ void ArmJit::Comp_FPU2op(MIPSOpcode op) { void ArmJit::Comp_mxc1(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(FPU_XFER); int fs = _FS; MIPSGPReg rt = _RT; diff --git a/Core/MIPS/ARM/ArmCompLoadStore.cpp b/Core/MIPS/ARM/ArmCompLoadStore.cpp index 16a3753fd2..bc81e33116 100644 --- a/Core/MIPS/ARM/ArmCompLoadStore.cpp +++ b/Core/MIPS/ARM/ArmCompLoadStore.cpp @@ -42,7 +42,7 @@ // Currently known non working ones should have DISABLE. // #define CONDITIONAL_DISABLE { Comp_Generic(op); return; } -#define CONDITIONAL_DISABLE ; +#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; } #define DISABLE { Comp_Generic(op); return; } namespace MIPSComp @@ -111,14 +111,14 @@ namespace MIPSComp } void ArmJit::Comp_ITypeMemLR(MIPSOpcode op, bool load) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU); CheckMemoryBreakpoint(); int offset = (signed short)(op & 0xFFFF); MIPSGPReg rt = _RT; MIPSGPReg rs = _RS; int o = op >> 26; - if (!js.inDelaySlot) { + if (!js.inDelaySlot && !jo.Disabled(JitDisable::LSU_UNALIGNED)) { // Optimisation: Combine to single unaligned load/store bool isLeft = (o == 34 || o == 42); CheckMemoryBreakpoint(1); @@ -260,7 +260,7 @@ namespace MIPSComp void ArmJit::Comp_ITypeMem(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU); CheckMemoryBreakpoint(); int offset = (signed short)(op&0xFFFF); bool load = false; diff --git a/Core/MIPS/ARM/ArmCompVFPU.cpp b/Core/MIPS/ARM/ArmCompVFPU.cpp index c171424075..9d2bcfe611 100644 --- a/Core/MIPS/ARM/ArmCompVFPU.cpp +++ b/Core/MIPS/ARM/ArmCompVFPU.cpp @@ -40,7 +40,7 @@ // Currently known non working ones should have DISABLE. // #define CONDITIONAL_DISABLE { fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; } -#define CONDITIONAL_DISABLE ; +#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; } #define DISABLE { fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; } #define NEON_IF_AVAILABLE(func) { if (jo.useNEONVFPU) { func(op); return; } } @@ -87,7 +87,7 @@ namespace MIPSComp void ArmJit::Comp_VPFX(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); int data = op & 0xFFFFF; int regnum = (op >> 24) & 3; switch (regnum) { @@ -225,7 +225,7 @@ namespace MIPSComp void ArmJit::Comp_SV(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_SV); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU_VFPU); CheckMemoryBreakpoint(); s32 offset = (signed short)(op & 0xFFFC); @@ -332,7 +332,7 @@ namespace MIPSComp void ArmJit::Comp_SVQ(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_SVQ); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU_VFPU); CheckMemoryBreakpoint(); int imm = (signed short)(op&0xFFFC); @@ -478,7 +478,7 @@ namespace MIPSComp void ArmJit::Comp_VVectorInit(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_VVectorInit); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); // WARNING: No prefix support! if (js.HasUnknownPrefix()) { DISABLE; @@ -515,7 +515,7 @@ namespace MIPSComp void ArmJit::Comp_VIdt(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_VIdt); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) { DISABLE; } @@ -553,7 +553,7 @@ namespace MIPSComp void ArmJit::Comp_VMatrixInit(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_VMatrixInit); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) { // Don't think matrix init ops care about prefixes. // DISABLE; @@ -601,7 +601,7 @@ namespace MIPSComp void ArmJit::Comp_VHdp(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_VHdp); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -644,7 +644,7 @@ namespace MIPSComp void ArmJit::Comp_Vhoriz(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_Vhoriz); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -687,7 +687,7 @@ namespace MIPSComp void ArmJit::Comp_VDot(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_VDot); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -724,7 +724,7 @@ namespace MIPSComp void ArmJit::Comp_VecDo3(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_VecDo3); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -884,7 +884,7 @@ namespace MIPSComp void ArmJit::Comp_VV2Op(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_VV2Op); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1077,7 +1077,7 @@ namespace MIPSComp void ArmJit::Comp_Vi2f(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_Vi2f); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1124,7 +1124,7 @@ namespace MIPSComp void ArmJit::Comp_Vh2f(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_Vh2f); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1186,7 +1186,7 @@ namespace MIPSComp void ArmJit::Comp_Vf2i(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_Vf2i); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; @@ -1256,7 +1256,7 @@ namespace MIPSComp void ArmJit::Comp_Mftv(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_Mftv); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); int imm = op & 0xFF; MIPSGPReg rt = _RT; @@ -1331,7 +1331,7 @@ namespace MIPSComp void ArmJit::Comp_Vmfvc(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_Vmtvc); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); int vs = _VS; int imm = op & 0xFF; @@ -1350,7 +1350,7 @@ namespace MIPSComp void ArmJit::Comp_Vmtvc(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_Vmtvc); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); int vs = _VS; int imm = op & 0xFF; @@ -1377,7 +1377,7 @@ namespace MIPSComp void ArmJit::Comp_Vmmov(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_Vmmov); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_MTX); // This probably ignores prefixes for all sane intents and purposes. if (_VS == _VD) { @@ -1415,7 +1415,7 @@ namespace MIPSComp void ArmJit::Comp_VScl(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_VScl); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1464,7 +1464,7 @@ namespace MIPSComp } void ArmJit::Comp_Vmmul(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_MTX); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1513,7 +1513,7 @@ namespace MIPSComp void ArmJit::Comp_Vtfm(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_Vtfm); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_MTX); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1584,7 +1584,7 @@ namespace MIPSComp void ArmJit::Comp_Vi2x(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_Vi2x); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1662,7 +1662,7 @@ namespace MIPSComp void ArmJit::Comp_Vx2i(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_Vx2i); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1751,7 +1751,7 @@ namespace MIPSComp void ArmJit::Comp_VCrossQuat(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_VCrossQuat); // This op does not support prefixes anyway. - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -1831,7 +1831,7 @@ namespace MIPSComp void ArmJit::Comp_Vcmp(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_Vcmp); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_COMP); if (js.HasUnknownPrefix()) DISABLE; @@ -2019,7 +2019,7 @@ namespace MIPSComp void ArmJit::Comp_Vcmov(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_Vcmov); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_COMP); if (js.HasUnknownPrefix()) { DISABLE; } @@ -2070,7 +2070,7 @@ namespace MIPSComp void ArmJit::Comp_Viim(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_Viim); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) { DISABLE; } @@ -2088,7 +2088,7 @@ namespace MIPSComp void ArmJit::Comp_Vfim(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_Vfim); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) { DISABLE; } @@ -2108,7 +2108,7 @@ namespace MIPSComp void ArmJit::Comp_Vcst(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_Vcst); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) { DISABLE; } @@ -2178,7 +2178,7 @@ namespace MIPSComp void ArmJit::Comp_VRot(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_VRot); // VRot probably doesn't accept prefixes anyway. - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -2244,7 +2244,7 @@ namespace MIPSComp void ArmJit::Comp_Vsgn(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_Vsgn); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -2293,7 +2293,7 @@ namespace MIPSComp void ArmJit::Comp_Vocp(MIPSOpcode op) { NEON_IF_AVAILABLE(CompNEON_Vocp); - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } diff --git a/Core/MIPS/ARM/ArmCompVFPUNEON.cpp b/Core/MIPS/ARM/ArmCompVFPUNEON.cpp index 9f04436bf4..945d993849 100644 --- a/Core/MIPS/ARM/ArmCompVFPUNEON.cpp +++ b/Core/MIPS/ARM/ArmCompVFPUNEON.cpp @@ -53,7 +53,7 @@ // Currently known non working ones should have DISABLE. // #define CONDITIONAL_DISABLE { fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; } -#define CONDITIONAL_DISABLE ; +#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; } #define DISABLE { fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; } #define DISABLE_UNKNOWN_PREFIX { WLOG("DISABLE: Unknown Prefix in %s", __FUNCTION__); fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; } @@ -82,7 +82,7 @@ static const float zero = 0.0f; void ArmJit::CompNEON_VecDo3(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE_UNKNOWN_PREFIX; } @@ -158,7 +158,7 @@ void ArmJit::CompNEON_VecDo3(MIPSOpcode op) { // #define CONDITIONAL_DISABLE { fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; } void ArmJit::CompNEON_SV(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU_VFPU); CheckMemoryBreakpoint(); // Remember to use single lane stores here and not VLDR/VSTR - switching usage @@ -276,7 +276,7 @@ inline int MIPS_GET_VQVT(u32 op) { } void ArmJit::CompNEON_SVQ(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU_VFPU); CheckMemoryBreakpoint(); int offset = (signed short)(op & 0xFFFC); @@ -425,7 +425,7 @@ void ArmJit::CompNEON_SVQ(MIPSOpcode op) { } void ArmJit::CompNEON_VVectorInit(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); // WARNING: No prefix support! if (js.HasUnknownPrefix()) { DISABLE_UNKNOWN_PREFIX; @@ -450,7 +450,7 @@ void ArmJit::CompNEON_VVectorInit(MIPSOpcode op) { } void ArmJit::CompNEON_VDot(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE_UNKNOWN_PREFIX; } @@ -484,7 +484,7 @@ void ArmJit::CompNEON_VDot(MIPSOpcode op) { void ArmJit::CompNEON_VHdp(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE_UNKNOWN_PREFIX; } @@ -496,7 +496,7 @@ void ArmJit::CompNEON_VHdp(MIPSOpcode op) { } void ArmJit::CompNEON_VScl(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE_UNKNOWN_PREFIX; } @@ -515,7 +515,7 @@ void ArmJit::CompNEON_VScl(MIPSOpcode op) { } void ArmJit::CompNEON_VV2Op(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE_UNKNOWN_PREFIX; } @@ -666,7 +666,7 @@ void ArmJit::CompNEON_VV2Op(MIPSOpcode op) { } void ArmJit::CompNEON_Mftv(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); int imm = op & 0xFF; MIPSGPReg rt = _RT; switch ((op >> 21) & 0x1f) { @@ -746,7 +746,7 @@ void ArmJit::CompNEON_Vmfvc(MIPSOpcode op) { } void ArmJit::CompNEON_Vmtvc(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); int vs = _VS; int imm = op & 0xFF; @@ -767,7 +767,7 @@ void ArmJit::CompNEON_Vmtvc(MIPSOpcode op) { } void ArmJit::CompNEON_VMatrixInit(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); MatrixSize msz = GetMtxSize(op); int n = GetMatrixSide(msz); @@ -828,7 +828,7 @@ void ArmJit::CompNEON_VMatrixInit(MIPSOpcode op) { } void ArmJit::CompNEON_Vmmov(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_MTX); if (_VS == _VD) { // A lot of these no-op matrix moves in Wipeout... Just drop the instruction entirely. return; @@ -856,7 +856,7 @@ void ArmJit::CompNEON_Vmmov(MIPSOpcode op) { } void ArmJit::CompNEON_Vmmul(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_MTX); MatrixSize msz = GetMtxSize(op); int n = GetMatrixSide(msz); @@ -895,7 +895,7 @@ void ArmJit::CompNEON_Vmmul(MIPSOpcode op) { } void ArmJit::CompNEON_Vmscl(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_MTX); MatrixSize msz = GetMtxSize(op); @@ -920,7 +920,7 @@ void ArmJit::CompNEON_Vmscl(MIPSOpcode op) { } void ArmJit::CompNEON_Vtfm(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_MTX); if (js.HasUnknownPrefix()) { DISABLE; } @@ -986,7 +986,7 @@ void ArmJit::CompNEON_Vf2i(MIPSOpcode op) { } void ArmJit::CompNEON_Vi2f(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1012,6 +1012,7 @@ void ArmJit::CompNEON_Vi2f(MIPSOpcode op) { } void ArmJit::CompNEON_Vh2f(MIPSOpcode op) { + CONDITIONAL_DISABLE(VFPU_VEC); if (!cpu_info.bHalf) { // No hardware support for half-to-float, fallback to interpreter // TODO: Translate the fast SSE solution to standard integer/VFP stuff @@ -1045,7 +1046,7 @@ void ArmJit::CompNEON_Vh2f(MIPSOpcode op) { } void ArmJit::CompNEON_Vcst(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) { DISABLE_UNKNOWN_PREFIX; } @@ -1063,7 +1064,7 @@ void ArmJit::CompNEON_Vcst(MIPSOpcode op) { } void ArmJit::CompNEON_Vhoriz(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE_UNKNOWN_PREFIX; } @@ -1102,7 +1103,7 @@ void ArmJit::CompNEON_Vhoriz(MIPSOpcode op) { } void ArmJit::CompNEON_VRot(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE_UNKNOWN_PREFIX; @@ -1121,7 +1122,7 @@ void ArmJit::CompNEON_VRot(MIPSOpcode op) { } void ArmJit::CompNEON_VIdt(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) { DISABLE_UNKNOWN_PREFIX; } @@ -1167,7 +1168,7 @@ void ArmJit::CompNEON_VIdt(MIPSOpcode op) { } void ArmJit::CompNEON_Vcmp(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_COMP); if (js.HasUnknownPrefix()) DISABLE; @@ -1298,7 +1299,7 @@ void ArmJit::CompNEON_Vcmp(MIPSOpcode op) { } void ArmJit::CompNEON_Vcmov(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_COMP); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1341,7 +1342,7 @@ void ArmJit::CompNEON_Vcmov(MIPSOpcode op) { } void ArmJit::CompNEON_Viim(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1358,7 +1359,7 @@ void ArmJit::CompNEON_Viim(MIPSOpcode op) { } void ArmJit::CompNEON_Vfim(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1379,7 +1380,7 @@ void ArmJit::CompNEON_Vfim(MIPSOpcode op) { // https://code.google.com/p/bullet/source/browse/branches/PhysicsEffects/include/vecmath/neon/vectormath_neon_assembly_implementations.S?r=2488 void ArmJit::CompNEON_VCrossQuat(MIPSOpcode op) { // This op does not support prefixes anyway. - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE_UNKNOWN_PREFIX; } @@ -1427,7 +1428,7 @@ void ArmJit::CompNEON_Vsgn(MIPSOpcode op) { } void ArmJit::CompNEON_Vocp(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } diff --git a/Core/MIPS/ARM64/Arm64CompALU.cpp b/Core/MIPS/ARM64/Arm64CompALU.cpp index 48572f3d96..aa3ffb577e 100644 --- a/Core/MIPS/ARM64/Arm64CompALU.cpp +++ b/Core/MIPS/ARM64/Arm64CompALU.cpp @@ -44,7 +44,7 @@ using namespace MIPSAnalyst; // Currently known non working ones should have DISABLE. // #define CONDITIONAL_DISABLE { Comp_Generic(op); return; } -#define CONDITIONAL_DISABLE ; +#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; } #define DISABLE { Comp_Generic(op); return; } namespace MIPSComp { @@ -70,7 +70,7 @@ void Arm64Jit::CompImmLogic(MIPSGPReg rs, MIPSGPReg rt, u32 uimm, void (ARM64XEm } void Arm64Jit::Comp_IType(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU_IMM); s32 simm = (s32)(s16)(op & 0xFFFF); // sign extension u32 uimm = op & 0xFFFF; u32 suimm = (u32)(s32)simm; @@ -146,7 +146,7 @@ void Arm64Jit::Comp_IType(MIPSOpcode op) { } void Arm64Jit::Comp_RType2(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU_BIT); MIPSGPReg rs = _RS; MIPSGPReg rd = _RD; @@ -234,7 +234,7 @@ void Arm64Jit::CompType3(MIPSGPReg rd, MIPSGPReg rs, MIPSGPReg rt, void (ARM64XE } void Arm64Jit::Comp_RType3(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU); MIPSGPReg rt = _RT; MIPSGPReg rs = _RS; @@ -406,7 +406,7 @@ void Arm64Jit::CompShiftVar(MIPSOpcode op, Arm64Gen::ShiftType shiftType) { } void Arm64Jit::Comp_ShiftType(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU); MIPSGPReg rs = _RS; MIPSGPReg rd = _RD; int fd = _FD; @@ -431,7 +431,7 @@ void Arm64Jit::Comp_ShiftType(MIPSOpcode op) { } void Arm64Jit::Comp_Special3(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU_BIT); MIPSGPReg rs = _RS; MIPSGPReg rt = _RT; @@ -479,7 +479,7 @@ void Arm64Jit::Comp_Special3(MIPSOpcode op) { } void Arm64Jit::Comp_Allegrex(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU_BIT); MIPSGPReg rt = _RT; MIPSGPReg rd = _RD; // Don't change $zr. @@ -529,7 +529,7 @@ void Arm64Jit::Comp_Allegrex(MIPSOpcode op) { } void Arm64Jit::Comp_Allegrex2(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU_BIT); MIPSGPReg rt = _RT; MIPSGPReg rd = _RD; // Don't change $zr. @@ -560,7 +560,7 @@ void Arm64Jit::Comp_Allegrex2(MIPSOpcode op) { } void Arm64Jit::Comp_MulDivType(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(MULDIV); MIPSGPReg rt = _RT; MIPSGPReg rs = _RS; MIPSGPReg rd = _RD; diff --git a/Core/MIPS/ARM64/Arm64CompFPU.cpp b/Core/MIPS/ARM64/Arm64CompFPU.cpp index 55298ae577..98121615b1 100644 --- a/Core/MIPS/ARM64/Arm64CompFPU.cpp +++ b/Core/MIPS/ARM64/Arm64CompFPU.cpp @@ -52,7 +52,7 @@ // Currently known non working ones should have DISABLE. // #define CONDITIONAL_DISABLE { Comp_Generic(op); return; } -#define CONDITIONAL_DISABLE ; +#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; } #define DISABLE { Comp_Generic(op); return; } namespace MIPSComp { @@ -60,7 +60,7 @@ namespace MIPSComp { using namespace Arm64JitConstants; void Arm64Jit::Comp_FPU3op(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(FPU); int ft = _FT; int fs = _FS; @@ -80,7 +80,7 @@ void Arm64Jit::Comp_FPU3op(MIPSOpcode op) { void Arm64Jit::Comp_FPULS(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU_FPU); CheckMemoryBreakpoint(); // Surprisingly, these work fine alraedy. @@ -152,7 +152,7 @@ void Arm64Jit::Comp_FPULS(MIPSOpcode op) } void Arm64Jit::Comp_FPUComp(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(FPU_COMP); int opc = op & 0xF; if (opc >= 8) opc -= 8; // alias @@ -198,7 +198,7 @@ void Arm64Jit::Comp_FPUComp(MIPSOpcode op) { } void Arm64Jit::Comp_FPU2op(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(FPU); int fs = _FS; int fd = _FD; @@ -301,7 +301,7 @@ void Arm64Jit::Comp_FPU2op(MIPSOpcode op) { void Arm64Jit::Comp_mxc1(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(FPU_XFER); int fs = _FS; MIPSGPReg rt = _RT; diff --git a/Core/MIPS/ARM64/Arm64CompLoadStore.cpp b/Core/MIPS/ARM64/Arm64CompLoadStore.cpp index 7b962f0e95..f28074c2e9 100644 --- a/Core/MIPS/ARM64/Arm64CompLoadStore.cpp +++ b/Core/MIPS/ARM64/Arm64CompLoadStore.cpp @@ -42,7 +42,7 @@ // Currently known non working ones should have DISABLE. // #define CONDITIONAL_DISABLE { Comp_Generic(op); return; } -#define CONDITIONAL_DISABLE ; +#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; } #define DISABLE { Comp_Generic(op); return; } namespace MIPSComp { @@ -110,14 +110,14 @@ namespace MIPSComp { } void Arm64Jit::Comp_ITypeMemLR(MIPSOpcode op, bool load) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU); CheckMemoryBreakpoint(); int offset = (signed short)(op & 0xFFFF); MIPSGPReg rt = _RT; MIPSGPReg rs = _RS; int o = op >> 26; - if (!js.inDelaySlot) { + if (!js.inDelaySlot && !jo.Disabled(JitDisable::LSU_UNALIGNED)) { // Optimisation: Combine to single unaligned load/store bool isLeft = (o == 34 || o == 42); CheckMemoryBreakpoint(1); @@ -256,7 +256,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_ITypeMem(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU); CheckMemoryBreakpoint(); int offset = (signed short)(op & 0xFFFF); diff --git a/Core/MIPS/ARM64/Arm64CompVFPU.cpp b/Core/MIPS/ARM64/Arm64CompVFPU.cpp index 7799dfbfa4..88ba5df94a 100644 --- a/Core/MIPS/ARM64/Arm64CompVFPU.cpp +++ b/Core/MIPS/ARM64/Arm64CompVFPU.cpp @@ -38,7 +38,7 @@ // Currently known non working ones should have DISABLE. // #define CONDITIONAL_DISABLE { fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; } -#define CONDITIONAL_DISABLE ; +#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; } #define DISABLE { fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; } #define _RS MIPS_GET_RS(op) @@ -80,7 +80,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_VPFX(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); int data = op & 0xFFFFF; int regnum = (op >> 24) & 3; switch (regnum) { @@ -201,7 +201,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_SV(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU_VFPU); CheckMemoryBreakpoint(); s32 offset = (signed short)(op & 0xFFFC); @@ -275,7 +275,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_SVQ(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU_VFPU); CheckMemoryBreakpoint(); int imm = (signed short)(op&0xFFFC); @@ -359,7 +359,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_VVectorInit(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); // WARNING: No prefix support! if (js.HasUnknownPrefix()) { DISABLE; @@ -393,7 +393,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_VIdt(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) { DISABLE; } @@ -428,7 +428,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_VMatrixInit(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) { // Don't think matrix init ops care about prefixes. // DISABLE; @@ -475,7 +475,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_VHdp(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -517,7 +517,7 @@ namespace MIPSComp { alignas(16) static const float vavg_table[4] = { 1.0f, 1.0f / 2.0f, 1.0f / 3.0f, 1.0f / 4.0f }; void Arm64Jit::Comp_Vhoriz(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -559,7 +559,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_VDot(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -595,7 +595,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_VecDo3(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -744,7 +744,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_VV2Op(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -884,7 +884,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_Vi2f(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -931,7 +931,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_Vh2f(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -978,6 +978,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_Mftv(MIPSOpcode op) { + CONDITIONAL_DISABLE(VFPU_XFER); int imm = op & 0xFF; MIPSGPReg rt = _RT; switch ((op >> 21) & 0x1f) { @@ -1063,7 +1064,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_Vmfvc(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); int vs = _VS; int imm = op & 0xFF; @@ -1081,7 +1082,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_Vmtvc(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); int vs = _VS; int imm = op & 0xFF; @@ -1107,7 +1108,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_Vmmov(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_MTX); // This probably ignores prefixes for all sane intents and purposes. if (_VS == _VD) { @@ -1144,7 +1145,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_VScl(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1193,7 +1194,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_Vmmul(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_MTX); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1239,7 +1240,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_Vtfm(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_MTX); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1307,7 +1308,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_Vi2x(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -1376,7 +1377,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_Vx2i(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -1471,7 +1472,7 @@ namespace MIPSComp { void Arm64Jit::Comp_VCrossQuat(MIPSOpcode op) { // This op does not support prefixes anyway. - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -1550,7 +1551,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_Vcmp(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_COMP); if (js.HasUnknownPrefix()) DISABLE; @@ -1727,7 +1728,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_Vcmov(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_COMP); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1778,7 +1779,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_Viim(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1795,7 +1796,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_Vfim(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1814,7 +1815,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_Vcst(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1882,7 +1883,7 @@ namespace MIPSComp { // calling the math library. void Arm64Jit::Comp_VRot(MIPSOpcode op) { // VRot probably doesn't accept prefixes anyway. - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1943,7 +1944,7 @@ namespace MIPSComp { } void Arm64Jit::Comp_Vocp(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } diff --git a/Core/MIPS/IR/IRCompALU.cpp b/Core/MIPS/IR/IRCompALU.cpp index 70fa758dac..2622ea1b9d 100644 --- a/Core/MIPS/IR/IRCompALU.cpp +++ b/Core/MIPS/IR/IRCompALU.cpp @@ -38,14 +38,14 @@ // Currently known non working ones should have DISABLE. // #define CONDITIONAL_DISABLE { Comp_Generic(op); return; } -#define CONDITIONAL_DISABLE ; +#define CONDITIONAL_DISABLE(flag) if (opts.disableFlags & (uint32_t)JitDisable::flag) { Comp_Generic(op); return; } #define DISABLE { Comp_Generic(op); return; } #define INVALIDOP { Comp_Generic(op); return; } namespace MIPSComp { void IRFrontend::Comp_IType(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU_IMM); s32 simm = (s32)_IMM16; // sign extension u32 uimm = (u16)_IMM16; @@ -87,7 +87,7 @@ void IRFrontend::Comp_IType(MIPSOpcode op) { } void IRFrontend::Comp_RType2(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU_BIT); MIPSGPReg rs = _RS; MIPSGPReg rd = _RD; @@ -111,7 +111,7 @@ void IRFrontend::Comp_RType2(MIPSOpcode op) { } void IRFrontend::Comp_RType3(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU); MIPSGPReg rt = _RT; MIPSGPReg rs = _RS; @@ -197,7 +197,7 @@ void IRFrontend::CompShiftVar(MIPSOpcode op, IROp shiftOp) { } void IRFrontend::Comp_ShiftType(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU); MIPSGPReg rs = _RS; MIPSGPReg rd = _RD; int sa = _SA; @@ -222,7 +222,7 @@ void IRFrontend::Comp_ShiftType(MIPSOpcode op) { } void IRFrontend::Comp_Special3(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU_BIT); MIPSGPReg rs = _RS; MIPSGPReg rt = _RT; @@ -265,7 +265,7 @@ void IRFrontend::Comp_Special3(MIPSOpcode op) { void IRFrontend::Comp_Allegrex(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU_BIT); MIPSGPReg rt = _RT; MIPSGPReg rd = _RD; @@ -293,7 +293,7 @@ void IRFrontend::Comp_Allegrex(MIPSOpcode op) { } void IRFrontend::Comp_Allegrex2(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU_BIT); MIPSGPReg rt = _RT; MIPSGPReg rd = _RD; @@ -315,7 +315,7 @@ void IRFrontend::Comp_Allegrex2(MIPSOpcode op) { } void IRFrontend::Comp_MulDivType(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(MULDIV); MIPSGPReg rt = _RT; MIPSGPReg rs = _RS; MIPSGPReg rd = _RD; diff --git a/Core/MIPS/IR/IRCompFPU.cpp b/Core/MIPS/IR/IRCompFPU.cpp index ce01c7ff75..0392fb2795 100644 --- a/Core/MIPS/IR/IRCompFPU.cpp +++ b/Core/MIPS/IR/IRCompFPU.cpp @@ -49,14 +49,14 @@ // Currently known non working ones should have DISABLE. // #define CONDITIONAL_DISABLE { Comp_Generic(op); return; } -#define CONDITIONAL_DISABLE ; +#define CONDITIONAL_DISABLE(flag) if (opts.disableFlags & (uint32_t)JitDisable::flag) { Comp_Generic(op); return; } #define DISABLE { Comp_Generic(op); return; } #define INVALIDOP { Comp_Generic(op); return; } namespace MIPSComp { void IRFrontend::Comp_FPU3op(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(FPU); int ft = _FT; int fs = _FS; @@ -74,7 +74,7 @@ void IRFrontend::Comp_FPU3op(MIPSOpcode op) { } void IRFrontend::Comp_FPULS(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU_FPU); s32 offset = _IMM16; int ft = _FT; MIPSGPReg rs = _RS; @@ -97,7 +97,7 @@ void IRFrontend::Comp_FPULS(MIPSOpcode op) { } void IRFrontend::Comp_FPUComp(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(FPU_COMP); int opc = op & 0xF; if (opc >= 8) opc -= 8; // alias @@ -139,7 +139,7 @@ void IRFrontend::Comp_FPUComp(MIPSOpcode op) { } void IRFrontend::Comp_FPU2op(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(FPU); int fs = _FS; int fd = _FD; @@ -185,7 +185,7 @@ void IRFrontend::Comp_FPU2op(MIPSOpcode op) { } void IRFrontend::Comp_mxc1(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(FPU_XFER); int fs = _FS; MIPSGPReg rt = _RT; diff --git a/Core/MIPS/IR/IRCompLoadStore.cpp b/Core/MIPS/IR/IRCompLoadStore.cpp index 4ef50d5e0b..a8ed9d8166 100644 --- a/Core/MIPS/IR/IRCompLoadStore.cpp +++ b/Core/MIPS/IR/IRCompLoadStore.cpp @@ -39,13 +39,13 @@ // Currently known non working ones should have DISABLE. // #define CONDITIONAL_DISABLE { Comp_Generic(op); return; } -#define CONDITIONAL_DISABLE ; +#define CONDITIONAL_DISABLE(flag) if (opts.disableFlags & (uint32_t)JitDisable::flag) { Comp_Generic(op); return; } #define DISABLE { Comp_Generic(op); return; } #define INVALIDOP { Comp_Generic(op); return; } namespace MIPSComp { void IRFrontend::Comp_ITypeMem(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU); int offset = _IMM16; MIPSGPReg rt = _RT; @@ -106,7 +106,7 @@ namespace MIPSComp { } void IRFrontend::Comp_Cache(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU); // int imm = (s16)(op & 0xFFFF); // int rs = _RS; diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index 63fe98b033..0b61953b3c 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -35,7 +35,7 @@ // Currently known non working ones should have DISABLE. // #define CONDITIONAL_DISABLE { Comp_Generic(op); return; } -#define CONDITIONAL_DISABLE ; +#define CONDITIONAL_DISABLE(flag) if (opts.disableFlags & (uint32_t)JitDisable::flag) { Comp_Generic(op); return; } #define DISABLE { Comp_Generic(op); return; } #define INVALIDOP { Comp_Generic(op); return; } @@ -109,7 +109,7 @@ namespace MIPSComp { } void IRFrontend::Comp_VPFX(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); int data = op & 0xFFFFF; int regnum = (op >> 24) & 3; switch (regnum) { @@ -274,7 +274,7 @@ namespace MIPSComp { } void IRFrontend::Comp_SV(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU_VFPU); s32 offset = (signed short)(op & 0xFFFC); int vt = ((op >> 16) & 0x1f) | ((op & 3) << 5); MIPSGPReg rs = _RS; @@ -296,7 +296,7 @@ namespace MIPSComp { } void IRFrontend::Comp_SVQ(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU_VFPU); int imm = (signed short)(op & 0xFFFC); int vt = (((op >> 16) & 0x1f)) | ((op & 1) << 5); MIPSGPReg rs = _RS; @@ -342,7 +342,7 @@ namespace MIPSComp { } void IRFrontend::Comp_VVectorInit(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) { DISABLE; } @@ -368,7 +368,7 @@ namespace MIPSComp { } void IRFrontend::Comp_VIdt(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) { DISABLE; } @@ -406,7 +406,7 @@ namespace MIPSComp { } void IRFrontend::Comp_VMatrixInit(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); MatrixSize sz = GetMtxSize(op); if (sz != M_4x4) { DISABLE; @@ -447,7 +447,7 @@ namespace MIPSComp { } void IRFrontend::Comp_VHdp(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -487,7 +487,7 @@ namespace MIPSComp { alignas(16) static const float vavg_table[4] = { 1.0f, 1.0f / 2.0f, 1.0f / 3.0f, 1.0f / 4.0f }; void IRFrontend::Comp_Vhoriz(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -524,7 +524,7 @@ namespace MIPSComp { } void IRFrontend::Comp_VDot(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -562,7 +562,7 @@ namespace MIPSComp { } void IRFrontend::Comp_VecDo3(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -721,7 +721,7 @@ namespace MIPSComp { } void IRFrontend::Comp_VV2Op(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -847,7 +847,7 @@ namespace MIPSComp { } void IRFrontend::Comp_Vi2f(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -894,7 +894,7 @@ namespace MIPSComp { } void IRFrontend::Comp_Vh2f(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); // Vector expand half to float // d[N*2] = float(lowerhalf(s[N])), d[N*2+1] = float(upperhalf(s[N])) @@ -903,7 +903,7 @@ namespace MIPSComp { } void IRFrontend::Comp_Vf2i(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); // Vector float to integer // d[N] = int(S[N] * mult) @@ -913,7 +913,7 @@ namespace MIPSComp { } void IRFrontend::Comp_Mftv(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); int imm = op & 0xFF; MIPSGPReg rt = _RT; @@ -966,7 +966,7 @@ namespace MIPSComp { } void IRFrontend::Comp_Vmfvc(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); // Vector Move from vector control reg (no prefixes) // S[0] = VFPU_CTRL[i] @@ -982,7 +982,7 @@ namespace MIPSComp { } void IRFrontend::Comp_Vmtvc(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); // Vector Move to vector control reg (no prefixes) // VFPU_CTRL[i] = S[0] @@ -1004,7 +1004,7 @@ namespace MIPSComp { } void IRFrontend::Comp_Vmmov(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_MTX); // Matrix move (no prefixes) // D[N,M] = S[N,M] @@ -1061,7 +1061,7 @@ namespace MIPSComp { } void IRFrontend::Comp_Vmscl(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_MTX); // Matrix scale, matrix by scalar (no prefixes) // d[N,M] = s[N,M] * t[0] @@ -1099,7 +1099,7 @@ namespace MIPSComp { } void IRFrontend::Comp_VScl(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1173,7 +1173,7 @@ namespace MIPSComp { // This may or may not be a win when using the IR interpreter... // Many more instructions to interpret. void IRFrontend::Comp_Vmmul(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_MTX); // Matrix multiply (no prefixes) // D[0 .. N,0 .. M] = S[0 .. N, 0 .. M] * T[0 .. N,0 .. M] @@ -1256,7 +1256,7 @@ namespace MIPSComp { } void IRFrontend::Comp_Vtfm(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_MTX); // Vertex transform, vector by matrix (no prefixes) // d[N] = s[N*m .. N*m + n-1] dot t[0 .. n-1] @@ -1358,7 +1358,7 @@ namespace MIPSComp { } void IRFrontend::Comp_VCrs(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1372,7 +1372,7 @@ namespace MIPSComp { } void IRFrontend::Comp_VDet(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1385,7 +1385,7 @@ namespace MIPSComp { } void IRFrontend::Comp_Vi2x(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -1470,7 +1470,7 @@ namespace MIPSComp { } void IRFrontend::Comp_Vx2i(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -1570,7 +1570,7 @@ namespace MIPSComp { } void IRFrontend::Comp_VCrossQuat(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); // TODO: Does this instruction even look at prefixes at all? if (js.HasUnknownPrefix()) DISABLE; @@ -1627,7 +1627,7 @@ namespace MIPSComp { } void IRFrontend::Comp_Vcmp(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_COMP); if (js.HasUnknownPrefix()) DISABLE; @@ -1651,7 +1651,7 @@ namespace MIPSComp { } void IRFrontend::Comp_Vcmov(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_COMP); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1690,7 +1690,7 @@ namespace MIPSComp { } void IRFrontend::Comp_Viim(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) DISABLE; @@ -1705,7 +1705,7 @@ namespace MIPSComp { } void IRFrontend::Comp_Vfim(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) DISABLE; @@ -1723,7 +1723,7 @@ namespace MIPSComp { } void IRFrontend::Comp_Vcst(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) DISABLE; @@ -1747,7 +1747,7 @@ namespace MIPSComp { // Very heavily used by FF:CC. Should be replaced by a fast approximation instead of // calling the math library. void IRFrontend::Comp_VRot(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (!js.HasNoPrefix()) { // Prefixes work strangely for this: // * They never apply to cos (whether d or s prefixes.) @@ -1797,7 +1797,7 @@ namespace MIPSComp { } void IRFrontend::Comp_Vsgn(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1835,7 +1835,7 @@ namespace MIPSComp { } void IRFrontend::Comp_Vocp(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -1872,7 +1872,7 @@ namespace MIPSComp { } void IRFrontend::Comp_ColorConv(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -1883,7 +1883,7 @@ namespace MIPSComp { } void IRFrontend::Comp_Vbfy(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; diff --git a/Core/MIPS/x86/CompALU.cpp b/Core/MIPS/x86/CompALU.cpp index 6019d82d73..456695b575 100644 --- a/Core/MIPS/x86/CompALU.cpp +++ b/Core/MIPS/x86/CompALU.cpp @@ -40,8 +40,8 @@ using namespace MIPSAnalyst; // All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly. // Currently known non working ones should have DISABLE. -// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; } -#define CONDITIONAL_DISABLE ; +// #define CONDITIONAL_DISABLE(ignore) { Comp_Generic(op); return; } +#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; } #define DISABLE { Comp_Generic(op); return; } namespace MIPSComp @@ -74,7 +74,7 @@ namespace MIPSComp void Jit::Comp_IType(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU_IMM); s32 simm = (s32)_IMM16; // sign extension u32 uimm = op & 0xFFFF; u32 suimm = (u32)(s32)simm; @@ -197,7 +197,7 @@ namespace MIPSComp void Jit::Comp_RType2(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU_BIT); MIPSGPReg rs = _RS; MIPSGPReg rd = _RD; @@ -378,7 +378,7 @@ namespace MIPSComp void Jit::Comp_RType3(MIPSOpcode op) { - CONDITIONAL_DISABLE + CONDITIONAL_DISABLE(ALU); MIPSGPReg rt = _RT; MIPSGPReg rs = _RS; @@ -668,7 +668,7 @@ namespace MIPSComp void Jit::Comp_ShiftType(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU); int rs = (op>>21) & 0x1F; MIPSGPReg rd = _RD; int fd = (op>>6) & 0x1F; @@ -696,7 +696,7 @@ namespace MIPSComp void Jit::Comp_Special3(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(ALU_BIT); MIPSGPReg rs = _RS; MIPSGPReg rt = _RT; @@ -786,7 +786,7 @@ namespace MIPSComp void Jit::Comp_Allegrex(MIPSOpcode op) { - CONDITIONAL_DISABLE + CONDITIONAL_DISABLE(ALU_BIT); MIPSGPReg rt = _RT; MIPSGPReg rd = _RD; // Don't change $zr. @@ -894,7 +894,7 @@ namespace MIPSComp void Jit::Comp_Allegrex2(MIPSOpcode op) { - CONDITIONAL_DISABLE + CONDITIONAL_DISABLE(ALU_BIT); MIPSGPReg rt = _RT; MIPSGPReg rd = _RD; // Don't change $zr. @@ -938,7 +938,7 @@ namespace MIPSComp void Jit::Comp_MulDivType(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(MULDIV); MIPSGPReg rt = _RT; MIPSGPReg rs = _RS; MIPSGPReg rd = _RD; diff --git a/Core/MIPS/x86/CompFPU.cpp b/Core/MIPS/x86/CompFPU.cpp index 664490966e..1220f2a382 100644 --- a/Core/MIPS/x86/CompFPU.cpp +++ b/Core/MIPS/x86/CompFPU.cpp @@ -42,7 +42,7 @@ // Currently known non working ones should have DISABLE. // #define CONDITIONAL_DISABLE { Comp_Generic(op); return; } -#define CONDITIONAL_DISABLE ; +#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; } #define DISABLE { Comp_Generic(op); return; } namespace MIPSComp { @@ -86,7 +86,7 @@ void Jit::CompFPTriArith(MIPSOpcode op, void (XEmitter::*arith)(X64Reg reg, OpAr } void Jit::Comp_FPU3op(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(FPU); switch (op & 0x3f) { case 0: CompFPTriArith(op, &XEmitter::ADDSS, false); break; //F(fd) = F(fs) + F(ft); //add case 1: CompFPTriArith(op, &XEmitter::SUBSS, true); break; //F(fd) = F(fs) - F(ft); //sub @@ -99,7 +99,7 @@ void Jit::Comp_FPU3op(MIPSOpcode op) { } void Jit::Comp_FPULS(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU_FPU); s32 offset = _IMM16; int ft = _FT; MIPSGPReg rs = _RS; @@ -174,7 +174,7 @@ void Jit::CompFPComp(int lhs, int rhs, u8 compare, bool allowNaN) { } void Jit::Comp_FPUComp(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(FPU_COMP); int fs = _FS; int ft = _FT; @@ -226,7 +226,7 @@ void Jit::Comp_FPUComp(MIPSOpcode op) { } void Jit::Comp_FPU2op(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(FPU); int fs = _FS; int fd = _FD; @@ -355,7 +355,7 @@ void Jit::Comp_FPU2op(MIPSOpcode op) { } void Jit::Comp_mxc1(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(FPU_XFER); int fs = _FS; MIPSGPReg rt = _RT; diff --git a/Core/MIPS/x86/CompLoadStore.cpp b/Core/MIPS/x86/CompLoadStore.cpp index 28112c0bfc..5182c7fdc2 100644 --- a/Core/MIPS/x86/CompLoadStore.cpp +++ b/Core/MIPS/x86/CompLoadStore.cpp @@ -42,7 +42,7 @@ // Currently known non working ones should have DISABLE. // #define CONDITIONAL_DISABLE { Comp_Generic(op); return; } -#define CONDITIONAL_DISABLE ; +#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; } #define DISABLE { Comp_Generic(op); return; } namespace MIPSComp { @@ -50,7 +50,7 @@ namespace MIPSComp { void Jit::CompITypeMemRead(MIPSOpcode op, u32 bits, void (XEmitter::*mov)(int, int, X64Reg, OpArg), const void *safeFunc) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU); int offset = _IMM16; MIPSGPReg rt = _RT; MIPSGPReg rs = _RS; @@ -81,7 +81,7 @@ namespace MIPSComp { void Jit::CompITypeMemWrite(MIPSOpcode op, u32 bits, const void *safeFunc) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU); int offset = _IMM16; MIPSGPReg rt = _RT; MIPSGPReg rs = _RS; @@ -137,7 +137,7 @@ namespace MIPSComp { void Jit::CompITypeMemUnpairedLR(MIPSOpcode op, bool isStore) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU); int o = op>>26; int offset = _IMM16; MIPSGPReg rt = _RT; @@ -193,7 +193,7 @@ namespace MIPSComp { void Jit::CompITypeMemUnpairedLRInner(MIPSOpcode op, X64Reg shiftReg) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU); int o = op>>26; MIPSGPReg rt = _RT; @@ -285,7 +285,7 @@ namespace MIPSComp { void Jit::Comp_ITypeMem(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU); int offset = _IMM16; MIPSGPReg rt = _RT; MIPSGPReg rs = _RS; @@ -334,7 +334,7 @@ namespace MIPSComp { MIPSOpcode nextOp = GetOffsetInstruction(1); // Looking for lwr rd, offset-3(rs) which makes a pair. u32 desiredOp = ((op & 0xFFFF0000) + (4 << 26)) + (offset - 3); - if (!js.inDelaySlot && nextOp == desiredOp) + if (!js.inDelaySlot && nextOp == desiredOp && !jo.Disabled(JitDisable::LSU_UNALIGNED)) { EatInstruction(nextOp); // nextOp has the correct address. @@ -350,7 +350,7 @@ namespace MIPSComp { MIPSOpcode nextOp = GetOffsetInstruction(1); // Looking for lwl rd, offset+3(rs) which makes a pair. u32 desiredOp = ((op & 0xFFFF0000) - (4 << 26)) + (offset + 3); - if (!js.inDelaySlot && nextOp == desiredOp) + if (!js.inDelaySlot && nextOp == desiredOp && !jo.Disabled(JitDisable::LSU_UNALIGNED)) { EatInstruction(nextOp); // op has the correct address. @@ -366,7 +366,7 @@ namespace MIPSComp { MIPSOpcode nextOp = GetOffsetInstruction(1); // Looking for swr rd, offset-3(rs) which makes a pair. u32 desiredOp = ((op & 0xFFFF0000) + (4 << 26)) + (offset - 3); - if (!js.inDelaySlot && nextOp == desiredOp) + if (!js.inDelaySlot && nextOp == desiredOp && !jo.Disabled(JitDisable::LSU_UNALIGNED)) { EatInstruction(nextOp); // nextOp has the correct address. @@ -382,7 +382,7 @@ namespace MIPSComp { MIPSOpcode nextOp = GetOffsetInstruction(1); // Looking for swl rd, offset+3(rs) which makes a pair. u32 desiredOp = ((op & 0xFFFF0000) - (4 << 26)) + (offset + 3); - if (!js.inDelaySlot && nextOp == desiredOp) + if (!js.inDelaySlot && nextOp == desiredOp && !jo.Disabled(JitDisable::LSU_UNALIGNED)) { EatInstruction(nextOp); // op has the correct address. diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index 62076afe6a..d74a1f8e3a 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -42,7 +42,7 @@ // Currently known non working ones should have DISABLE. // #define CONDITIONAL_DISABLE { fpr.ReleaseSpillLocks(); Comp_Generic(op); return; } -#define CONDITIONAL_DISABLE ; +#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; } #define DISABLE { fpr.ReleaseSpillLocks(); Comp_Generic(op); return; } #define _RS MIPS_GET_RS(op) @@ -74,7 +74,7 @@ alignas(16) const float identityMatrix[4][4] = { { 1.0f, 0, 0, 0 }, { 0, 1.0f, 0 void Jit::Comp_VPFX(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); int data = op & 0xFFFFF; int regnum = (op >> 24) & 3; switch (regnum) { @@ -239,7 +239,7 @@ bool IsOverlapSafe(int dreg, int di, int sn, u8 sregs[], int tn = 0, u8 tregs[] alignas(16) static u32 ssLoadStoreTemp; void Jit::Comp_SV(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU_VFPU); s32 imm = (signed short)(op&0xFFFC); int vt = ((op >> 16) & 0x1f) | ((op & 3) << 5); @@ -294,7 +294,7 @@ void Jit::Comp_SV(MIPSOpcode op) { } void Jit::Comp_SVQ(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(LSU_VFPU); int imm = (signed short)(op&0xFFFC); int vt = (((op >> 16) & 0x1f)) | ((op&1) << 5); @@ -502,7 +502,7 @@ void Jit::Comp_SVQ(MIPSOpcode op) { } void Jit::Comp_VVectorInit(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) DISABLE; @@ -557,7 +557,7 @@ void Jit::Comp_VVectorInit(MIPSOpcode op) { } void Jit::Comp_VIdt(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) DISABLE; @@ -608,7 +608,7 @@ void Jit::Comp_VIdt(MIPSOpcode op) { } void Jit::Comp_VDot(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -739,7 +739,7 @@ void Jit::Comp_VDot(MIPSOpcode op) { void Jit::Comp_VHdp(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -788,7 +788,7 @@ void Jit::Comp_VHdp(MIPSOpcode op) { } void Jit::Comp_VCrossQuat(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -921,7 +921,7 @@ void Jit::Comp_VCrossQuat(MIPSOpcode op) { } void Jit::Comp_Vcmov(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_COMP); if (js.HasUnknownPrefix()) DISABLE; @@ -997,7 +997,7 @@ static s32 DoVmaxSS(s32 treg) { } void Jit::Comp_VecDo3(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -1269,7 +1269,7 @@ alignas(16) static const u32 vcmpMask[4][4] = { }; void Jit::Comp_Vcmp(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_COMP); if (js.HasUnknownPrefix()) DISABLE; @@ -1512,7 +1512,7 @@ extern const float mulTableVi2f[32] = { }; void Jit::Comp_Vi2f(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -1599,7 +1599,7 @@ void Jit::Comp_Vi2f(MIPSOpcode op) { // Translation of ryg's half_to_float5_SSE2 void Jit::Comp_Vh2f(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -1688,7 +1688,7 @@ alignas(16) static s8 vc2i_shuffle[16] = { -1, -1, -1, 0, -1, -1, -1, 1, -1, - alignas(16) static s8 vuc2i_shuffle[16] = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3 }; void Jit::Comp_Vx2i(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -1811,7 +1811,7 @@ static const float half = 0.5f; static const double maxMinIntAsDouble[2] = { (double)0x7fffffff, (double)(int)0x80000000 }; // that's not equal to 0x80000000 void Jit::Comp_Vf2i(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -1920,7 +1920,7 @@ void Jit::Comp_Vf2i(MIPSOpcode op) { } void Jit::Comp_Vcst(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) DISABLE; @@ -1957,7 +1957,7 @@ void Jit::Comp_Vcst(MIPSOpcode op) { } void Jit::Comp_Vsgn(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -2018,7 +2018,7 @@ void Jit::Comp_Vsgn(MIPSOpcode op) { } void Jit::Comp_Vocp(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -2067,7 +2067,7 @@ void Jit::Comp_Vocp(MIPSOpcode op) { } void Jit::Comp_Vbfy(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -2181,7 +2181,7 @@ void SinCosNegSin(SinCosArg angle, float *output) { } void Jit::Comp_VV2Op(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -2419,7 +2419,7 @@ void Jit::Comp_VV2Op(MIPSOpcode op) { } void Jit::Comp_Mftv(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); int imm = op & 0xFF; MIPSGPReg rt = _RT; @@ -2509,7 +2509,7 @@ void Jit::Comp_Mftv(MIPSOpcode op) { } void Jit::Comp_Vmfvc(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); int vs = _VS; int imm = op & 0xFF; if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) { @@ -2525,7 +2525,7 @@ void Jit::Comp_Vmfvc(MIPSOpcode op) { } void Jit::Comp_Vmtvc(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); int vs = _VS; int imm = op & 0xFF; if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) { @@ -2549,7 +2549,7 @@ void Jit::Comp_Vmtvc(MIPSOpcode op) { } void Jit::Comp_VMatrixInit(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) DISABLE; @@ -2632,7 +2632,7 @@ void Jit::Comp_VMatrixInit(MIPSOpcode op) { } void Jit::Comp_Vmmov(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_MTX); // TODO: This probably ignores prefixes? if (js.HasUnknownPrefix()) @@ -2718,7 +2718,7 @@ void Jit::Comp_Vmmov(MIPSOpcode op) { } void Jit::Comp_VScl(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -2780,7 +2780,7 @@ void Jit::Comp_VScl(MIPSOpcode op) { } void Jit::Comp_Vmmul(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_MTX); // TODO: This probably ignores prefixes? if (js.HasUnknownPrefix()) @@ -2974,7 +2974,7 @@ void Jit::Comp_Vmmul(MIPSOpcode op) { } void Jit::Comp_Vmscl(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_MTX); // TODO: This op probably ignores prefixes? if (js.HasUnknownPrefix()) @@ -3020,7 +3020,7 @@ void Jit::Comp_Vmscl(MIPSOpcode op) { } void Jit::Comp_Vtfm(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_MTX); // TODO: This probably ignores prefixes? Or maybe uses D? if (js.HasUnknownPrefix()) @@ -3163,7 +3163,7 @@ alignas(16) static const s8 vi2xc_shuffle[16] = { 3, 7, 11, 15, -1, -1, -1, -1, alignas(16) static const s8 vi2xs_shuffle[16] = { 2, 3, 6, 7, 10, 11, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1 }; void Jit::Comp_Vi2x(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -3295,7 +3295,7 @@ void Jit::Comp_Vi2x(MIPSOpcode op) { alignas(16) static const float vavg_table[4] = { 1.0f, 1.0f / 2.0f, 1.0f / 3.0f, 1.0f / 4.0f }; void Jit::Comp_Vhoriz(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; @@ -3412,7 +3412,7 @@ void Jit::Comp_Vhoriz(MIPSOpcode op) { } void Jit::Comp_Viim(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) DISABLE; @@ -3435,7 +3435,7 @@ void Jit::Comp_Viim(MIPSOpcode op) { } void Jit::Comp_Vfim(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_XFER); if (js.HasUnknownPrefix()) DISABLE; @@ -3497,7 +3497,7 @@ void Jit::CompVrotShuffle(u8 *dregs, int imm, int n, bool negSin) { // Very heavily used by FF:CC void Jit::Comp_VRot(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; } @@ -3569,7 +3569,7 @@ void Jit::Comp_VRot(MIPSOpcode op) { } void Jit::Comp_ColorConv(MIPSOpcode op) { - CONDITIONAL_DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) DISABLE; From 304c90934be2f43840181cdf7b8c4388ab4dc36e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 3 Feb 2019 14:02:47 -0800 Subject: [PATCH 308/347] UI: Add bitfield checkbox. --- ext/native/ui/view.cpp | 25 +++++++++++++++++++++---- ext/native/ui/view.h | 17 ++++++++++++++++- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/ext/native/ui/view.cpp b/ext/native/ui/view.cpp index 5f1deac264..3a9afc5a56 100644 --- a/ext/native/ui/view.cpp +++ b/ext/native/ui/view.cpp @@ -658,10 +658,16 @@ void PopupHeader::Draw(UIContext &dc) { } } -void CheckBox::Toggle(){ +void CheckBox::Toggle() { if (toggle_) *toggle_ = !(*toggle_); -}; +} + +bool CheckBox::Toggled() const { + if (toggle_) + return toggle_; + return false; +} EventReturn CheckBox::OnClicked(EventParams &e) { Toggle(); @@ -676,7 +682,7 @@ void CheckBox::Draw(UIContext &dc) { ClickableItem::Draw(dc); - int image = *toggle_ ? dc.theme->checkOn : dc.theme->checkOff; + int image = Toggled() ? dc.theme->checkOn : dc.theme->checkOff; float imageW, imageH; dc.Draw()->MeasureImage(image, &imageW, &imageH); @@ -703,7 +709,7 @@ float CheckBox::CalculateTextScale(const UIContext &dc, float availWidth) const } void CheckBox::GetContentDimensions(const UIContext &dc, float &w, float &h) const { - int image = *toggle_ ? dc.theme->checkOn : dc.theme->checkOff; + int image = Toggled() ? dc.theme->checkOn : dc.theme->checkOff; float imageW, imageH; dc.Draw()->MeasureImage(image, &imageW, &imageH); @@ -724,6 +730,17 @@ void CheckBox::GetContentDimensions(const UIContext &dc, float &w, float &h) con h = std::max(actualHeight, ITEM_HEIGHT); } +void BitCheckBox::Toggle() { + if (bitfield_) + *bitfield_ = *bitfield_ ^ bit_; +} + +bool BitCheckBox::Toggled() const { + if (bitfield_) + return (bit_ & *bitfield_) == bit_; + return false; +} + void Button::GetContentDimensions(const UIContext &dc, float &w, float &h) const { if (imageID_ != -1) { const AtlasImage *img = &dc.Draw()->GetAtlas()->images[imageID_]; diff --git a/ext/native/ui/view.h b/ext/native/ui/view.h index 3d89ea4d65..2ca22d1c38 100644 --- a/ext/native/ui/view.h +++ b/ext/native/ui/view.h @@ -742,7 +742,8 @@ public: EventReturn OnClicked(EventParams &e); //allow external agents to toggle the checkbox - void Toggle(); + virtual void Toggle(); + virtual bool Toggled() const; private: float CalculateTextScale(const UIContext &dc, float availWidth) const; @@ -751,6 +752,20 @@ private: std::string smallText_; }; +class BitCheckBox : public CheckBox { +public: + BitCheckBox(uint32_t *bitfield, uint32_t bit, const std::string &text, const std::string &smallText = "", LayoutParams *layoutParams = nullptr) + : CheckBox(nullptr, text, smallText, layoutParams), bitfield_(bitfield), bit_(bit) { + } + + void Toggle() override; + bool Toggled() const override; + +private: + uint32_t *bitfield_; + uint32_t bit_; +}; + // These are for generic use. class Spacer : public InertView { From 0b775bdac0d41e1f7a0049c6f701dcf6bc5948f1 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 3 Feb 2019 14:34:50 -0800 Subject: [PATCH 309/347] Reporting: Disable when jit flags are disabled. --- Core/Reporting.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Core/Reporting.cpp b/Core/Reporting.cpp index 6aeeadfbc3..6393a80f4a 100644 --- a/Core/Reporting.cpp +++ b/Core/Reporting.cpp @@ -462,6 +462,8 @@ namespace Reporting return false; if (g_Config.iLockedCPUSpeed != 0) return false; + if (g_Config.uJitDisableFlags != 0) + return false; // Don't allow builds without version info from git. They're useless for reporting. if (strcmp(PPSSPP_GIT_VERSION, "unknown") == 0) return false; From a802adb1f677ae4b61f0d59b464adb6130d9b68e Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Mon, 4 Feb 2019 13:00:08 +0100 Subject: [PATCH 310/347] Add simple UI for JIT feature disable flags --- Core/MIPS/JitCommon/JitState.h | 2 ++ UI/DevScreens.cpp | 65 ++++++++++++++++++++++++++++++++++ UI/DevScreens.h | 10 ++++++ UI/GameSettingsScreen.cpp | 6 ++++ UI/GameSettingsScreen.h | 1 + 5 files changed, 84 insertions(+) diff --git a/Core/MIPS/JitCommon/JitState.h b/Core/MIPS/JitCommon/JitState.h index c4b31274f3..ac16bcf7da 100644 --- a/Core/MIPS/JitCommon/JitState.h +++ b/Core/MIPS/JitCommon/JitState.h @@ -198,6 +198,8 @@ namespace MIPSComp { POINTERIFY = 0x00400000, STATIC_ALLOC = 0x00800000, CACHE_POINTERS = 0x01000000, + + ALL_FLAGS = 0x01FFFFFF, }; struct JitOptions { diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index 5bb95172d3..0815100336 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -37,6 +37,7 @@ #include "Core/MIPS/MIPSTables.h" #include "Core/MIPS/JitCommon/JitBlockCache.h" #include "Core/MIPS/JitCommon/JitCommon.h" +#include "Core/MIPS/JitCommon/JitState.h" #include "GPU/GPUInterface.h" #include "GPU/GPUState.h" #include "UI/MiscScreens.h" @@ -318,6 +319,70 @@ void LogLevelScreen::OnCompleted(DialogResult result) { } } +struct JitDisableFlag { + MIPSComp::JitDisable flag; + const char *name; +}; + +// Please do not try to translate these :) +static const JitDisableFlag jitDisableFlags[] = { + { MIPSComp::JitDisable::ALU, "ALU" }, + { MIPSComp::JitDisable::ALU_IMM, "ALU_IMM" }, + { MIPSComp::JitDisable::ALU_BIT, "ALU_BIT" }, + { MIPSComp::JitDisable::MULDIV, "MULDIV" }, + { MIPSComp::JitDisable::FPU, "FPU" }, + { MIPSComp::JitDisable::FPU_COMP, "FPU_COMP" }, + { MIPSComp::JitDisable::FPU_XFER, "FPU_XFER" }, + { MIPSComp::JitDisable::VFPU_VEC, "VFPU_VEC" }, + { MIPSComp::JitDisable::VFPU_MTX, "VFPU_MTX" }, + { MIPSComp::JitDisable::VFPU_COMP, "VFPU_COMP" }, + { MIPSComp::JitDisable::VFPU_XFER, "VFPU_XFER" }, + { MIPSComp::JitDisable::LSU, "LSU" }, + { MIPSComp::JitDisable::LSU_UNALIGNED, "LSU_UNALIGNED" }, + { MIPSComp::JitDisable::LSU_FPU, "LSU_FPU" }, + { MIPSComp::JitDisable::LSU_VFPU, "LSU_VFPU" }, + { MIPSComp::JitDisable::SIMD, "SIMD" }, + { MIPSComp::JitDisable::BLOCKLINK, "Block Linking" }, + { MIPSComp::JitDisable::POINTERIFY, "Pointerify" }, + { MIPSComp::JitDisable::STATIC_ALLOC, "Static regalloc" }, + { MIPSComp::JitDisable::CACHE_POINTERS, "Cached pointers" }, +}; + +void JitDebugScreen::CreateViews() { + using namespace UI; + + I18NCategory *di = GetI18NCategory("Dialog"); + I18NCategory *dev = GetI18NCategory("Developer"); + + root_ = new ScrollView(ORIENT_VERTICAL); + + LinearLayout *vert = root_->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT))); + vert->SetSpacing(0); + + LinearLayout *topbar = new LinearLayout(ORIENT_HORIZONTAL); + topbar->Add(new Choice(di->T("Back")))->OnClick.Handle(this, &UIScreen::OnBack); + topbar->Add(new Choice(di->T("Disable All")))->OnClick.Handle(this, &JitDebugScreen::OnDisableAll); + topbar->Add(new Choice(di->T("Enable All")))->OnClick.Handle(this, &JitDebugScreen::OnEnableAll); + + vert->Add(topbar); + vert->Add(new ItemHeader(dev->T("Disabled JIT functionality"))); + + for (auto flag : jitDisableFlags) { + // Do not add translation of these. + vert->Add(new BitCheckBox(&g_Config.uJitDisableFlags, (uint32_t)flag.flag, flag.name)); + } +} + +UI::EventReturn JitDebugScreen::OnEnableAll(UI::EventParams &e) { + g_Config.uJitDisableFlags &= ~(uint32_t)MIPSComp::JitDisable::ALL_FLAGS; + return UI::EVENT_DONE; +} + +UI::EventReturn JitDebugScreen::OnDisableAll(UI::EventParams &e) { + g_Config.uJitDisableFlags |= (uint32_t)MIPSComp::JitDisable::ALL_FLAGS; + return UI::EVENT_DONE; +} + const char *GetCompilerABI() { #if PPSSPP_ARCH(ARMV7) return "armeabi-v7a"; diff --git a/UI/DevScreens.h b/UI/DevScreens.h index a95ba61c27..a6c480bc66 100644 --- a/UI/DevScreens.h +++ b/UI/DevScreens.h @@ -47,6 +47,16 @@ protected: UI::EventReturn OnToggleAudioDebug(UI::EventParams &e); }; +class JitDebugScreen : public UIDialogScreenWithBackground { +public: + JitDebugScreen() {} + virtual void CreateViews() override; + +private: + UI::EventReturn OnEnableAll(UI::EventParams &e); + UI::EventReturn OnDisableAll(UI::EventParams &e); +}; + class LogConfigScreen : public UIDialogScreenWithBackground { public: LogConfigScreen() {} diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 0f34bdc50c..9f31ede54d 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1283,6 +1283,7 @@ void DeveloperToolsScreen::CreateViews() { core->HideChoice(1); } + list->Add(new Choice(dev->T("JIT debug tools")))->OnClick.Handle(this, &DeveloperToolsScreen::OnJitDebugTools); list->Add(new CheckBox(&g_Config.bShowDeveloperMenu, dev->T("Show Developer Menu"))); list->Add(new CheckBox(&g_Config.bDumpDecryptedEboot, dev->T("Dump Decrypted Eboot", "Dump Decrypted EBOOT.BIN (If Encrypted) When Booting Game"))); @@ -1388,6 +1389,11 @@ UI::EventReturn DeveloperToolsScreen::OnLogConfig(UI::EventParams &e) { return UI::EVENT_DONE; } +UI::EventReturn DeveloperToolsScreen::OnJitDebugTools(UI::EventParams &e) { + screenManager()->push(new JitDebugScreen()); + return UI::EVENT_DONE; +} + UI::EventReturn DeveloperToolsScreen::OnGPUDriverTest(UI::EventParams &e) { screenManager()->push(new GPUDriverTestScreen()); return UI::EVENT_DONE; diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index 915a524a20..78619558ac 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -157,6 +157,7 @@ private: UI::EventReturn OnOpenTexturesIniFile(UI::EventParams &e); UI::EventReturn OnLogConfig(UI::EventParams &e); UI::EventReturn OnJitAffectingSetting(UI::EventParams &e); + UI::EventReturn OnJitDebugTools(UI::EventParams &e); UI::EventReturn OnRemoteDebugger(UI::EventParams &e); UI::EventReturn OnGPUDriverTest(UI::EventParams &e); From 0aedf3755f6767b8d73965e5a426f98617273152 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Mon, 4 Feb 2019 13:22:58 +0100 Subject: [PATCH 311/347] Fix checkbox bug introduced in #11758. Fixes #11761. --- ext/native/ui/view.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/native/ui/view.cpp b/ext/native/ui/view.cpp index 3a9afc5a56..2a0fc2cbb6 100644 --- a/ext/native/ui/view.cpp +++ b/ext/native/ui/view.cpp @@ -665,7 +665,7 @@ void CheckBox::Toggle() { bool CheckBox::Toggled() const { if (toggle_) - return toggle_; + return *toggle_; return false; } From 128c0adc3918914935d2e03c95cc46edd85d963d Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Mon, 4 Feb 2019 14:21:46 +0100 Subject: [PATCH 312/347] Vulkan: Fix typo, bump shader cache version. --- GPU/Vulkan/PipelineManagerVulkan.cpp | 2 +- GPU/Vulkan/ShaderManagerVulkan.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 6141c87b11..dbb04144a2 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -245,7 +245,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip attributeCount = SetupVertexAttribs(attrs, *decFmt); vertexStride = decFmt->stride; } else { - bool needsColor1 = vs->GetID().Bit(FS_BIT_LMODE); + bool needsColor1 = vs->GetID().Bit(VS_BIT_LMODE); attributeCount = SetupVertexAttribsPretransformed(attrs, needsColor1); vertexStride = 36; } diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 10675fd5e1..1032ffffe8 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -361,7 +361,7 @@ VulkanFragmentShader *ShaderManagerVulkan::GetFragmentShaderFromModule(VkShaderM // instantaneous. #define CACHE_HEADER_MAGIC 0xff51f420 -#define CACHE_VERSION 15 +#define CACHE_VERSION 16 struct VulkanCacheHeader { uint32_t magic; uint32_t version; From 217205e4333dea80efe1b86c653e46d632cb997c Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Tue, 5 Feb 2019 15:57:43 +0100 Subject: [PATCH 313/347] To avoid strange images in Android gallery, pre-create TEXTURES with a .nomedia, and add .nomedia to the PSP directory. --- UI/NativeApp.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 55d4c3b955..d02e9fbc4f 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -344,11 +344,15 @@ void CreateDirectoriesAndroid() { File::CreateFullPath(GetSysDirectory(DIRECTORY_SAVESTATE)); File::CreateFullPath(GetSysDirectory(DIRECTORY_GAME)); File::CreateFullPath(GetSysDirectory(DIRECTORY_SYSTEM)); + File::CreateFullPath(GetSysDirectory(DIRECTORY_TEXTURES)); - // Avoid media scanners in PPSSPP_STATE and SAVEDATA directories + // Avoid media scanners in PPSSPP_STATE and SAVEDATA directories, + // and in the root PSP directory as well. + File::CreateEmptyFile(g_Config.memStickDirectory + "PSP/.nomedia"); File::CreateEmptyFile(GetSysDirectory(DIRECTORY_SAVESTATE) + ".nomedia"); File::CreateEmptyFile(GetSysDirectory(DIRECTORY_SAVEDATA) + ".nomedia"); File::CreateEmptyFile(GetSysDirectory(DIRECTORY_SYSTEM) + ".nomedia"); + File::CreateEmptyFile(GetSysDirectory(DIRECTORY_TEXTURES) + ".nomedia"); } static void CheckFailedGPUBackends() { From 58db029f7e562b2bb62e52189aaed70ab99af62d Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Tue, 5 Feb 2019 16:40:10 +0100 Subject: [PATCH 314/347] Android .nomedia: Don't hide everything under PSP, too harsh. --- UI/NativeApp.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index d02e9fbc4f..7b7cee5158 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -348,7 +348,6 @@ void CreateDirectoriesAndroid() { // Avoid media scanners in PPSSPP_STATE and SAVEDATA directories, // and in the root PSP directory as well. - File::CreateEmptyFile(g_Config.memStickDirectory + "PSP/.nomedia"); File::CreateEmptyFile(GetSysDirectory(DIRECTORY_SAVESTATE) + ".nomedia"); File::CreateEmptyFile(GetSysDirectory(DIRECTORY_SAVEDATA) + ".nomedia"); File::CreateEmptyFile(GetSysDirectory(DIRECTORY_SYSTEM) + ".nomedia"); From fdd0d7acb479e220d19616f8b8deaee4e27f43f0 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Mon, 4 Feb 2019 14:33:01 +0100 Subject: [PATCH 315/347] More Vulkan validation fixes NVIDIA no longer uses nVidia capitalization. --- Common/Vulkan/VulkanContext.cpp | 2 +- Common/Vulkan/VulkanDebug.cpp | 2 -- GPU/D3D11/ShaderManagerD3D11.cpp | 6 +++--- GPU/Vulkan/PipelineManagerVulkan.cpp | 9 ++++++--- GPU/Vulkan/ShaderManagerVulkan.cpp | 6 +++--- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index 6b9284ef29..c614dc4126 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -60,7 +60,7 @@ static const char *validationLayers[] = { std::string VulkanVendorString(uint32_t vendorId) { switch (vendorId) { case VULKAN_VENDOR_INTEL: return "Intel"; - case VULKAN_VENDOR_NVIDIA: return "nVidia"; + case VULKAN_VENDOR_NVIDIA: return "NVIDIA"; case VULKAN_VENDOR_AMD: return "AMD"; case VULKAN_VENDOR_ARM: return "ARM"; case VULKAN_VENDOR_QUALCOMM: return "Qualcomm"; diff --git a/Common/Vulkan/VulkanDebug.cpp b/Common/Vulkan/VulkanDebug.cpp index 0ee407b735..81925a4653 100644 --- a/Common/Vulkan/VulkanDebug.cpp +++ b/Common/Vulkan/VulkanDebug.cpp @@ -73,8 +73,6 @@ VkBool32 VKAPI_CALL Vulkan_Dbg(VkDebugReportFlagsEXT msgFlags, VkDebugReportObje } message << "[" << pLayerPrefix << "] " << ObjTypeToString(objType) << " Code " << msgCode << " : " << pMsg << "\n"; - if (msgCode == 2) // Useless perf warning ("Vertex attribute at location X not consumed by vertex shader") - return false; if (msgCode == 64) // Another useless perf warning that will be seen less and less as we optimize - vkCmdClearAttachments() issued on command buffer object 0x00000195296C6D40 prior to any Draw Cmds. It is recommended you use RenderPass LOAD_OP_CLEAR on Attachments prior to any Draw. return false; if (msgCode == 5) diff --git a/GPU/D3D11/ShaderManagerD3D11.cpp b/GPU/D3D11/ShaderManagerD3D11.cpp index 935c101e68..e928106d3a 100644 --- a/GPU/D3D11/ShaderManagerD3D11.cpp +++ b/GPU/D3D11/ShaderManagerD3D11.cpp @@ -96,9 +96,9 @@ ShaderManagerD3D11::ShaderManagerD3D11(Draw::DrawContext *draw, ID3D11Device *de memset(&ub_lights, 0, sizeof(ub_lights)); memset(&ub_bones, 0, sizeof(ub_bones)); - INFO_LOG(G3D, "sizeof(ub_base): %d", (int)sizeof(ub_base)); - INFO_LOG(G3D, "sizeof(ub_lights): %d", (int)sizeof(ub_lights)); - INFO_LOG(G3D, "sizeof(ub_bones): %d", (int)sizeof(ub_bones)); + static_assert(sizeof(ub_base) <= 512, "ub_base grew too big"); + static_assert(sizeof(ub_lights) <= 512, "ub_lights grew too big"); + static_assert(sizeof(ub_bones) <= 384, "ub_bones grew too big"); D3D11_BUFFER_DESC desc{sizeof(ub_base), D3D11_USAGE_DYNAMIC, D3D11_BIND_CONSTANT_BUFFER, D3D11_CPU_ACCESS_WRITE }; ASSERT_SUCCESS(device_->CreateBuffer(&desc, nullptr, &push_base)); diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index dbb04144a2..653667ad82 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -112,10 +112,12 @@ static int SetupVertexAttribs(VkVertexInputAttributeDescription attrs[], const D return count; } -static int SetupVertexAttribsPretransformed(VkVertexInputAttributeDescription attrs[], bool needsColor1) { +static int SetupVertexAttribsPretransformed(VkVertexInputAttributeDescription attrs[], bool needsUV, bool needsColor1) { int count = 0; VertexAttribSetup(&attrs[count++], DEC_FLOAT_4, 0, PspAttributeLocation::POSITION); - VertexAttribSetup(&attrs[count++], DEC_FLOAT_3, 16, PspAttributeLocation::TEXCOORD); + if (needsUV) { + VertexAttribSetup(&attrs[count++], DEC_FLOAT_3, 16, PspAttributeLocation::TEXCOORD); + } VertexAttribSetup(&attrs[count++], DEC_U8_4, 28, PspAttributeLocation::COLOR0); if (needsColor1) { VertexAttribSetup(&attrs[count++], DEC_U8_4, 32, PspAttributeLocation::COLOR1); @@ -245,8 +247,9 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip attributeCount = SetupVertexAttribs(attrs, *decFmt); vertexStride = decFmt->stride; } else { + bool needsUV = vs->GetID().Bit(VS_BIT_DO_TEXTURE); bool needsColor1 = vs->GetID().Bit(VS_BIT_LMODE); - attributeCount = SetupVertexAttribsPretransformed(attrs, needsColor1); + attributeCount = SetupVertexAttribsPretransformed(attrs, needsUV, needsColor1); vertexStride = 36; } diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 1032ffffe8..48599ec11a 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -165,9 +165,9 @@ ShaderManagerVulkan::ShaderManagerVulkan(Draw::DrawContext *draw, VulkanContext memset(&ub_lights, 0, sizeof(ub_lights)); memset(&ub_bones, 0, sizeof(ub_bones)); - ILOG("sizeof(ub_base): %d", (int)sizeof(ub_base)); - ILOG("sizeof(ub_lights): %d", (int)sizeof(ub_lights)); - ILOG("sizeof(ub_bones): %d", (int)sizeof(ub_bones)); + static_assert(sizeof(ub_base) <= 512, "ub_base grew too big"); + static_assert(sizeof(ub_lights) <= 512, "ub_lights grew too big"); + static_assert(sizeof(ub_bones) <= 384, "ub_bones grew too big"); } ShaderManagerVulkan::~ShaderManagerVulkan() { From 8e1a5ef3d6f2aef0367257245da3b6aa35ce1d14 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Tue, 5 Feb 2019 10:05:22 +0100 Subject: [PATCH 316/347] Minor refactor of physical device property/feature detection, to allow for more extension use. --- Common/Vulkan/VulkanContext.cpp | 87 +++++++++++++++-------- Common/Vulkan/VulkanContext.h | 30 +++++--- Common/Vulkan/VulkanLoader.cpp | 5 +- Common/Vulkan/VulkanLoader.h | 3 +- GPU/Vulkan/DrawEngineVulkan.cpp | 2 +- GPU/Vulkan/GPU_Vulkan.cpp | 22 +++--- GPU/Vulkan/PipelineManagerVulkan.cpp | 2 +- GPU/Vulkan/ShaderManagerVulkan.cpp | 8 +-- GPU/Vulkan/StateMappingVulkan.cpp | 2 +- GPU/Vulkan/StencilBufferVulkan.cpp | 2 +- GPU/Vulkan/TextureCacheVulkan.cpp | 2 +- Windows/GPU/WindowsVulkanContext.cpp | 4 +- ext/native/thin3d/VulkanQueueRunner.cpp | 2 +- ext/native/thin3d/VulkanRenderManager.cpp | 2 +- ext/native/thin3d/thin3d_vulkan.cpp | 35 ++++----- 15 files changed, 130 insertions(+), 78 deletions(-) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index c614dc4126..b518157d4b 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -143,6 +143,11 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { } } + if (IsInstanceExtensionAvailable(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { + instance_extensions_enabled_.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + extensionsLookup_.KHR_get_physical_device_properties2 = true; + } + // Validate that all the instance extensions we ask for are actually available. for (auto ext : instance_extensions_enabled_) { if (!IsInstanceExtensionAvailable(ext)) @@ -222,8 +227,25 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { return res; } - for (uint32_t i = 0; i < gpu_count; i++) { - vkGetPhysicalDeviceProperties(physical_devices_[i], &physicalDeviceProperties_[i]); + if (extensionsLookup_.KHR_get_physical_device_properties2) { + for (uint32_t i = 0; i < gpu_count; i++) { + VkPhysicalDeviceProperties2 props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; + VkPhysicalDevicePushDescriptorPropertiesKHR pushProps{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR}; + VkPhysicalDeviceExternalMemoryHostPropertiesEXT extHostMemProps{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT}; + props2.pNext = &pushProps; + pushProps.pNext = &extHostMemProps; + vkGetPhysicalDeviceProperties2KHR(physical_devices_[i], &props2); + // Don't want bad pointers sitting around. + props2.pNext = nullptr; + pushProps.pNext = nullptr; + physicalDeviceProperties_[i].properties = props2.properties; + physicalDeviceProperties_[i].pushDescriptorProperties = pushProps; + physicalDeviceProperties_[i].externalMemoryHostProperties = extHostMemProps; + } + } else { + for (uint32_t i = 0; i < gpu_count; i++) { + vkGetPhysicalDeviceProperties(physical_devices_[i], &physicalDeviceProperties_[i].properties); + } } return VK_SUCCESS; } @@ -423,7 +445,7 @@ bool VulkanContext::CheckLayers(const std::vector &layer_props, int VulkanContext::GetPhysicalDeviceByName(std::string name) { for (size_t i = 0; i < physical_devices_.size(); i++) { - if (physicalDeviceProperties_[i].deviceName == name) + if (physicalDeviceProperties_[i].properties.deviceName == name) return (int)i; } return -1; @@ -520,37 +542,45 @@ void VulkanContext::ChooseDevice(int physical_device) { } // Optional features - vkGetPhysicalDeviceFeatures(physical_devices_[physical_device_], &featuresAvailable_); - memset(&featuresEnabled_, 0, sizeof(featuresEnabled_)); + + if (extensionsLookup_.KHR_get_physical_device_properties2) { + VkPhysicalDeviceFeatures2 features2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR}; + vkGetPhysicalDeviceFeatures2KHR(physical_devices_[physical_device_], &features2); + deviceFeatures_.available = features2.features; + } else { + vkGetPhysicalDeviceFeatures(physical_devices_[physical_device_], &deviceFeatures_.available); + } + + deviceFeatures_.enabled = {}; // Enable a few safe ones if they are available. - if (featuresAvailable_.dualSrcBlend) { - featuresEnabled_.dualSrcBlend = true; + if (deviceFeatures_.available.dualSrcBlend) { + deviceFeatures_.enabled.dualSrcBlend = true; } - if (featuresAvailable_.largePoints) { - featuresEnabled_.largePoints = true; + if (deviceFeatures_.available.largePoints) { + deviceFeatures_.enabled.largePoints = true; } - if (featuresAvailable_.wideLines) { - featuresEnabled_.wideLines = true; + if (deviceFeatures_.available.wideLines) { + deviceFeatures_.enabled.wideLines = true; } - if (featuresAvailable_.geometryShader) { - featuresEnabled_.geometryShader = true; + if (deviceFeatures_.available.geometryShader) { + deviceFeatures_.enabled.geometryShader = true; } - if (featuresAvailable_.logicOp) { - featuresEnabled_.logicOp = true; + if (deviceFeatures_.available.logicOp) { + deviceFeatures_.enabled.logicOp = true; } - if (featuresAvailable_.depthClamp) { - featuresEnabled_.depthClamp = true; + if (deviceFeatures_.available.depthClamp) { + deviceFeatures_.enabled.depthClamp = true; } - if (featuresAvailable_.depthBounds) { - featuresEnabled_.depthBounds = true; + if (deviceFeatures_.available.depthBounds) { + deviceFeatures_.enabled.depthBounds = true; } - if (featuresAvailable_.samplerAnisotropy) { - featuresEnabled_.samplerAnisotropy = true; + if (deviceFeatures_.available.samplerAnisotropy) { + deviceFeatures_.enabled.samplerAnisotropy = true; } // For easy wireframe mode, someday. - if (featuresEnabled_.fillModeNonSolid) { - featuresEnabled_.fillModeNonSolid = true; + if (deviceFeatures_.available.fillModeNonSolid) { + deviceFeatures_.enabled.fillModeNonSolid = true; } GetDeviceLayerExtensionList(nullptr, device_extension_properties_); @@ -589,10 +619,10 @@ VkResult VulkanContext::CreateDevice() { assert(found); if (EnableDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME)) { - deviceExtensionsLookup_.KHR_get_memory_requirements2 = true; - deviceExtensionsLookup_.KHR_dedicated_allocation = EnableDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); + extensionsLookup_.KHR_get_memory_requirements2 = true; + extensionsLookup_.KHR_dedicated_allocation = EnableDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); } - deviceExtensionsLookup_.EXT_external_memory_host = EnableDeviceExtension(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME); + extensionsLookup_.EXT_external_memory_host = EnableDeviceExtension(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME); VkDeviceCreateInfo device_info{ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; device_info.queueCreateInfoCount = 1; @@ -601,7 +631,8 @@ VkResult VulkanContext::CreateDevice() { device_info.ppEnabledLayerNames = device_info.enabledLayerCount ? device_layer_names_.data() : nullptr; device_info.enabledExtensionCount = (uint32_t)device_extensions_enabled_.size(); device_info.ppEnabledExtensionNames = device_info.enabledExtensionCount ? device_extensions_enabled_.data() : nullptr; - device_info.pEnabledFeatures = &featuresEnabled_; + device_info.pEnabledFeatures = &deviceFeatures_.enabled; + VkResult res = vkCreateDevice(physical_devices_[physical_device_], &device_info, nullptr, &device_); if (res != VK_SUCCESS) { init_error_ = "Unable to create Vulkan device"; @@ -836,7 +867,7 @@ bool VulkanContext::InitSwapchain() { swapChainExtent_.width = clamp(surfCapabilities_.currentExtent.width, surfCapabilities_.minImageExtent.width, surfCapabilities_.maxImageExtent.width); swapChainExtent_.height = clamp(surfCapabilities_.currentExtent.height, surfCapabilities_.minImageExtent.height, surfCapabilities_.maxImageExtent.height); - if (physicalDeviceProperties_[physical_device_].vendorID == VULKAN_VENDOR_IMGTEC) { + if (physicalDeviceProperties_[physical_device_].properties.vendorID == VULKAN_VENDOR_IMGTEC) { // Swap chain width hack to avoid issue #11743 (PowerVR driver bug). swapChainExtent_.width &= ~31; } diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index ae1687a3ce..a785f285eb 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -106,6 +106,8 @@ struct VulkanDeviceExtensions { bool KHR_get_memory_requirements2; bool KHR_dedicated_allocation; bool EXT_external_memory_host; + bool KHR_get_physical_device_properties2; + // bool EXT_depth_range_unrestricted; // Allows depth outside [0.0, 1.0] in 32-bit float depth buffers. }; // Useful for debugging on ARM Mali. This eliminates transaction elimination @@ -192,7 +194,15 @@ public: return graphics_queue_family_index_; } - const VkPhysicalDeviceProperties &GetPhysicalDeviceProperties(int i) const { + struct PhysicalDeviceProps { + VkPhysicalDeviceProperties properties; + VkPhysicalDevicePushDescriptorPropertiesKHR pushDescriptorProperties; + VkPhysicalDeviceExternalMemoryHostPropertiesEXT externalMemoryHostProperties; + }; + + const PhysicalDeviceProps &GetPhysicalDeviceProperties(int i = -1) const { + if (i < 0) + i = GetCurrentPhysicalDevice(); return physicalDeviceProperties_[i]; } @@ -208,8 +218,13 @@ public: const std::vector &GetDeviceExtensionsEnabled() const { return device_extensions_enabled_; } - const VkPhysicalDeviceFeatures &GetFeaturesAvailable() const { return featuresAvailable_; } - const VkPhysicalDeviceFeatures &GetFeaturesEnabled() const { return featuresEnabled_; } + + struct PhysicalDeviceFeatures { + VkPhysicalDeviceFeatures available{}; + VkPhysicalDeviceFeatures enabled{}; + }; + + const PhysicalDeviceFeatures &GetDeviceFeatures() const { return deviceFeatures_; } const VulkanPhysicalDeviceInfo &GetDeviceInfo() const { return deviceInfo_; } const VkSurfaceCapabilitiesKHR &GetSurfaceCapabilities() const { return surfCapabilities_; } @@ -250,7 +265,7 @@ public: MAX_INFLIGHT_FRAMES = 3, }; - const VulkanDeviceExtensions &DeviceExtensions() { return deviceExtensionsLookup_; } + const VulkanDeviceExtensions &DeviceExtensions() { return extensionsLookup_; } private: // A layer can expose extensions, keep track of those extensions here. @@ -284,14 +299,14 @@ private: std::vector device_extensions_enabled_; std::vector device_extension_properties_; - VulkanDeviceExtensions deviceExtensionsLookup_{}; + VulkanDeviceExtensions extensionsLookup_{}; std::vector physical_devices_; int physical_device_ = -1; uint32_t graphics_queue_family_index_ = -1; - std::vector physicalDeviceProperties_{}; + std::vector physicalDeviceProperties_{}; std::vector queue_props; VkPhysicalDeviceMemoryProperties memory_properties{}; @@ -323,8 +338,7 @@ private: uint32_t queue_count = 0; - VkPhysicalDeviceFeatures featuresAvailable_{}; - VkPhysicalDeviceFeatures featuresEnabled_{}; + PhysicalDeviceFeatures deviceFeatures_; VkSurfaceCapabilitiesKHR surfCapabilities_{}; diff --git a/Common/Vulkan/VulkanLoader.cpp b/Common/Vulkan/VulkanLoader.cpp index 132394018e..b9e4522005 100644 --- a/Common/Vulkan/VulkanLoader.cpp +++ b/Common/Vulkan/VulkanLoader.cpp @@ -199,6 +199,8 @@ PFN_vkDestroyDebugReportCallbackEXT dyn_vkDestroyDebugReportCallbackEXT; PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT; PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; +PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; +PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; #ifdef _WIN32 static HINSTANCE vulkanLibrary; @@ -568,6 +570,8 @@ void VulkanLoadInstanceFunctions(VkInstance instance) { #endif LOAD_INSTANCE_FUNC(instance, vkDestroySurfaceKHR); + LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceProperties2KHR); + LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceFeatures2KHR); dyn_vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"); dyn_vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"); @@ -589,7 +593,6 @@ void VulkanLoadDeviceFunctions(VkDevice device) { LOAD_DEVICE_FUNC(device, vkGetMemoryHostPointerPropertiesEXT); LOAD_DEVICE_FUNC(device, vkGetBufferMemoryRequirements2KHR); LOAD_DEVICE_FUNC(device, vkGetImageMemoryRequirements2KHR); - } void VulkanFree() { diff --git a/Common/Vulkan/VulkanLoader.h b/Common/Vulkan/VulkanLoader.h index 6d5aad6ddc..25c93efee0 100644 --- a/Common/Vulkan/VulkanLoader.h +++ b/Common/Vulkan/VulkanLoader.h @@ -204,7 +204,8 @@ extern PFN_vkDestroyDebugReportCallbackEXT dyn_vkDestroyDebugReportCallbackEXT; extern PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; extern PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; extern PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT; - +extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; +extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; // Way to do a quick check before even attempting to load. bool VulkanMayBeAvailable(); diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index bc928c3cb2..4d9de9b4eb 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -1023,7 +1023,7 @@ void TessellationDataTransferVulkan::SendDataToShader(const SimpleVertex *const int size = size_u * size_v; - int ssboAlignment = vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).limits.minStorageBufferOffsetAlignment; + int ssboAlignment = vulkan_->GetPhysicalDeviceProperties().properties.limits.minStorageBufferOffsetAlignment; uint8_t *data = (uint8_t *)push_->PushAligned(size * sizeof(TessData), (uint32_t *)&bufInfo_[0].offset, &bufInfo_[0].buffer, ssboAlignment); bufInfo_[0].range = size * sizeof(TessData); diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 216b1300d0..5ad07c0ca4 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -95,7 +95,7 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw) UpdateVsyncInterval(true); textureCacheVulkan_->NotifyConfigChanged(); - if (vulkan_->GetFeaturesEnabled().wideLines) { + if (vulkan_->GetDeviceFeatures().enabled.wideLines) { drawEngine_.SetLineWidth(PSP_CoreParameter().renderWidth / 480.0f); } @@ -183,7 +183,7 @@ void GPU_Vulkan::CheckGPUFeatures() { features |= GPU_SUPPORTS_VS_RANGE_CULLING; - switch (vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).vendorID) { + switch (vulkan_->GetPhysicalDeviceProperties().properties.vendorID) { case VULKAN_VENDOR_AMD: // Accurate depth is required on AMD (due to reverse-Z driver bug) so we ignore the compat flag to disable it on those. See #9545 features |= GPU_SUPPORTS_ACCURATE_DEPTH; @@ -191,7 +191,7 @@ void GPU_Vulkan::CheckGPUFeatures() { case VULKAN_VENDOR_ARM: // Also required on older ARM Mali drivers, like the one on many Galaxy S7. if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth || - vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).driverVersion <= VK_MAKE_VERSION(428, 811, 2674)) { + vulkan_->GetPhysicalDeviceProperties().properties.driverVersion <= VK_MAKE_VERSION(428, 811, 2674)) { features |= GPU_SUPPORTS_ACCURATE_DEPTH; } break; @@ -217,21 +217,21 @@ void GPU_Vulkan::CheckGPUFeatures() { features |= GPU_SUPPORTS_VERTEX_TEXTURE_FETCH; features |= GPU_SUPPORTS_TEXTURE_FLOAT; - if (vulkan_->GetFeaturesEnabled().wideLines) { + if (vulkan_->GetDeviceFeatures().enabled.wideLines) { features |= GPU_SUPPORTS_WIDE_LINES; } - if (vulkan_->GetFeaturesEnabled().depthClamp) { + if (vulkan_->GetDeviceFeatures().enabled.depthClamp) { features |= GPU_SUPPORTS_DEPTH_CLAMP; } - if (vulkan_->GetFeaturesEnabled().dualSrcBlend) { + if (vulkan_->GetDeviceFeatures().enabled.dualSrcBlend) { if (!g_Config.bVendorBugChecksEnabled || !draw_->GetBugs().Has(Draw::Bugs::DUAL_SOURCE_BLENDING_BROKEN)) { features |= GPU_SUPPORTS_DUALSOURCE_BLEND; } } - if (vulkan_->GetFeaturesEnabled().logicOp) { + if (vulkan_->GetDeviceFeatures().enabled.logicOp) { features |= GPU_SUPPORTS_LOGIC_OP; } - if (vulkan_->GetFeaturesEnabled().samplerAnisotropy) { + if (vulkan_->GetDeviceFeatures().enabled.samplerAnisotropy) { features |= GPU_SUPPORTS_ANISOTROPY; } @@ -264,7 +264,7 @@ void GPU_Vulkan::BeginHostFrame() { framebufferManager_->Resized(); drawEngine_.Resized(); textureCacheVulkan_->NotifyConfigChanged(); - if (vulkan_->GetFeaturesEnabled ().wideLines) { + if (vulkan_->GetDeviceFeatures().enabled.wideLines) { drawEngine_.SetLineWidth(PSP_CoreParameter().renderWidth / 480.0f); } } @@ -311,8 +311,8 @@ void GPU_Vulkan::EndHostFrame() { // Needs to be called on GPU thread, not reporting thread. void GPU_Vulkan::BuildReportingInfo() { - const auto &props = vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()); - const auto &features = vulkan_->GetFeaturesAvailable(); + const auto &props = vulkan_->GetPhysicalDeviceProperties().properties; + const auto &features = vulkan_->GetDeviceFeatures().available; #define CHECK_BOOL_FEATURE(n) do { if (features.n) { featureNames += ", " #n; } } while (false) diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 653667ad82..8f803d563d 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -682,7 +682,7 @@ bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, Sha WARN_LOG(G3D, "Bad Vulkan pipeline cache header - ignoring"); return false; } - if (0 != memcmp(header->uuid, vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).pipelineCacheUUID, VK_UUID_SIZE)) { + if (0 != memcmp(header->uuid, vulkan_->GetPhysicalDeviceProperties().properties.pipelineCacheUUID, VK_UUID_SIZE)) { // Wrong hardware/driver/etc. WARN_LOG(G3D, "Bad Vulkan pipeline cache UUID - ignoring"); return false; diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 48599ec11a..43dd9de1ea 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -160,7 +160,7 @@ std::string VulkanVertexShader::GetShaderString(DebugShaderStringType type) cons ShaderManagerVulkan::ShaderManagerVulkan(Draw::DrawContext *draw, VulkanContext *vulkan) : ShaderManagerCommon(draw), vulkan_(vulkan), lastVShader_(nullptr), lastFShader_(nullptr), fsCache_(16), vsCache_(16) { codeBuffer_ = new char[16384]; - uboAlignment_ = vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).limits.minUniformBufferOffsetAlignment; + uboAlignment_ = vulkan_->GetPhysicalDeviceProperties().properties.limits.minUniformBufferOffsetAlignment; memset(&ub_base, 0, sizeof(ub_base)); memset(&ub_lights, 0, sizeof(ub_lights)); memset(&ub_bones, 0, sizeof(ub_bones)); @@ -178,7 +178,7 @@ ShaderManagerVulkan::~ShaderManagerVulkan() { void ShaderManagerVulkan::DeviceRestore(VulkanContext *vulkan, Draw::DrawContext *draw) { vulkan_ = vulkan; draw_ = draw; - uboAlignment_ = vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).limits.minUniformBufferOffsetAlignment; + uboAlignment_ = vulkan_->GetPhysicalDeviceProperties().properties.limits.minUniformBufferOffsetAlignment; } void ShaderManagerVulkan::Clear() { @@ -270,7 +270,7 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader VulkanFragmentShader *fs = fsCache_.Get(FSID); if (!fs) { - uint32_t vendorID = vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).vendorID; + uint32_t vendorID = vulkan_->GetPhysicalDeviceProperties().properties.vendorID; // Fragment shader not in cache. Let's compile it. GenerateVulkanGLSLFragmentShader(FSID, codeBuffer_, vendorID); fs = new VulkanFragmentShader(vulkan_, FSID, codeBuffer_); @@ -392,7 +392,7 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { VulkanVertexShader *vs = new VulkanVertexShader(vulkan_, id, codeBuffer_, useHWTransform); vsCache_.Insert(id, vs); } - uint32_t vendorID = vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).vendorID; + uint32_t vendorID = vulkan_->GetPhysicalDeviceProperties().properties.vendorID; for (int i = 0; i < header.numFragmentShaders; i++) { FShaderID id; if (fread(&id, sizeof(id), 1, f) != 1) { diff --git a/GPU/Vulkan/StateMappingVulkan.cpp b/GPU/Vulkan/StateMappingVulkan.cpp index e72df78c35..3fef920fca 100644 --- a/GPU/Vulkan/StateMappingVulkan.cpp +++ b/GPU/Vulkan/StateMappingVulkan.cpp @@ -237,7 +237,7 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag key.colorWriteMask = (rmask ? VK_COLOR_COMPONENT_R_BIT : 0) | (gmask ? VK_COLOR_COMPONENT_G_BIT : 0) | (bmask ? VK_COLOR_COMPONENT_B_BIT : 0) | (amask ? VK_COLOR_COMPONENT_A_BIT : 0); // Workaround proposed in #10421, for bug where the color write mask is not applied correctly on Adreno. - if ((gstate.pmskc & 0x00FFFFFF) == 0x00FFFFFF && vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).vendorID == VULKAN_VENDOR_QUALCOMM) { + if ((gstate.pmskc & 0x00FFFFFF) == 0x00FFFFFF && vulkan_->GetPhysicalDeviceProperties().properties.vendorID == VULKAN_VENDOR_QUALCOMM) { key.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; if (!key.blendEnable) { key.blendEnable = true; diff --git a/GPU/Vulkan/StencilBufferVulkan.cpp b/GPU/Vulkan/StencilBufferVulkan.cpp index bbf4a6abef..cfce98f3fb 100644 --- a/GPU/Vulkan/StencilBufferVulkan.cpp +++ b/GPU/Vulkan/StencilBufferVulkan.cpp @@ -146,7 +146,7 @@ bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, bool skip if (!stencilVs_) { const char *stencil_fs_source = stencil_fs; // See comment above the stencil_fs_adreno definition. - if (vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).vendorID == VULKAN_VENDOR_QUALCOMM) + if (vulkan_->GetPhysicalDeviceProperties().properties.vendorID == VULKAN_VENDOR_QUALCOMM) stencil_fs_source = stencil_fs_adreno; stencilVs_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_VERTEX_BIT, stencil_vs, &error); diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index cc6d6dedaa..0eb056af6c 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -683,7 +683,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { uint32_t bufferOffset; VkBuffer texBuf; // nvidia returns 1 but that can't be healthy... let's align by 16 as a minimum. - int pushAlignment = std::max(16, (int)vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).limits.optimalBufferCopyOffsetAlignment); + int pushAlignment = std::max(16, (int)vulkan_->GetPhysicalDeviceProperties().properties.limits.optimalBufferCopyOffsetAlignment); void *data = drawEngine_->GetPushBufferForTextureData()->PushAligned(size, &bufferOffset, &texBuf, pushAlignment); if (replaced.Valid()) { replaced.Load(i, data, stride); diff --git a/Windows/GPU/WindowsVulkanContext.cpp b/Windows/GPU/WindowsVulkanContext.cpp index 3c9bf4e724..77abd7d94b 100644 --- a/Windows/GPU/WindowsVulkanContext.cpp +++ b/Windows/GPU/WindowsVulkanContext.cpp @@ -114,7 +114,7 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m if (deviceNum < 0) { deviceNum = g_Vulkan->GetBestPhysicalDevice(); if (!g_Config.sVulkanDevice.empty()) - g_Config.sVulkanDevice = g_Vulkan->GetPhysicalDeviceProperties(deviceNum).deviceName; + g_Config.sVulkanDevice = g_Vulkan->GetPhysicalDeviceProperties(deviceNum).properties.deviceName; } g_Vulkan->ChooseDevice(deviceNum); if (g_Vulkan->CreateDevice() != VK_SUCCESS) { @@ -137,7 +137,7 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m bool splitSubmit = g_Config.bGfxDebugSplitSubmit; draw_ = Draw::T3DCreateVulkanContext(g_Vulkan, splitSubmit); - SetGPUBackend(GPUBackend::VULKAN, g_Vulkan->GetPhysicalDeviceProperties(deviceNum).deviceName); + SetGPUBackend(GPUBackend::VULKAN, g_Vulkan->GetPhysicalDeviceProperties(deviceNum).properties.deviceName); bool success = draw_->CreatePresets(); _assert_msg_(G3D, success, "Failed to compile preset shaders"); draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp index 631d088d26..4de46705be 100644 --- a/ext/native/thin3d/VulkanQueueRunner.cpp +++ b/ext/native/thin3d/VulkanQueueRunner.cpp @@ -865,7 +865,7 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step // See pull request #10723. bool maliBugWorkaround = step.render.numDraws == 0 && step.render.color == VKRRenderPassAction::CLEAR && - vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).driverVersion == 0xaa9c4b29; + vulkan_->GetPhysicalDeviceProperties().properties.driverVersion == 0xaa9c4b29; if (maliBugWorkaround) { TransitionImageLayout2(cmd, step.render.framebuffer->color.image, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT, fb->color.layout, VK_IMAGE_LAYOUT_GENERAL, diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index 55bf1daec1..7f3cb56715 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -138,7 +138,7 @@ VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan queueRunner_.CreateDeviceObjects(); // Temporary AMD hack for issue #10097 - if (vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).vendorID == VULKAN_VENDOR_AMD) { + if (vulkan_->GetPhysicalDeviceProperties().properties.vendorID == VULKAN_VENDOR_AMD) { useThread_ = false; } } diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index eaa6b0ad52..6885e1bc84 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -260,7 +260,7 @@ public: // Returns the binding offset, and the VkBuffer to bind. size_t PushUBO(VulkanPushBuffer *buf, VulkanContext *vulkan, VkBuffer *vkbuf) { - return buf->PushAligned(ubo_, uboSize_, vulkan->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).limits.minUniformBufferOffsetAlignment, vkbuf); + return buf->PushAligned(ubo_, uboSize_, vulkan->GetPhysicalDeviceProperties().properties.limits.minUniformBufferOffsetAlignment, vkbuf); } int GetUniformLoc(const char *name); @@ -352,7 +352,7 @@ public: std::vector GetDeviceList() const override { std::vector list; for (int i = 0; i < vulkan_->GetNumPhysicalDevices(); i++) { - list.push_back(vulkan_->GetPhysicalDeviceProperties(i).deviceName); + list.push_back(vulkan_->GetPhysicalDeviceProperties(i).properties.deviceName); } return list; } @@ -433,7 +433,7 @@ public: // From Sascha's code static std::string FormatDriverVersion(const VkPhysicalDeviceProperties &props) { - if (props.vendorID == 4318) { + if (props.vendorID == VULKAN_VENDOR_NVIDIA) { // 10 bits = major version (up to r1023) // 8 bits = minor version (up to 255) // 8 bits = secondary branch version/build version (up to 255) @@ -443,6 +443,9 @@ public: uint32_t secondaryBranch = (props.driverVersion >> 6) & 0x0ff; uint32_t tertiaryBranch = (props.driverVersion) & 0x003f; return StringFromFormat("%d.%d.%d.%d (%08x)", major, minor, secondaryBranch, tertiaryBranch, props.driverVersion); + } else if (props.vendorID == VULKAN_VENDOR_ARM) { + // ARM just puts a hash here, let's just output it as is. + return StringFromFormat("%08x", props.driverVersion); } else { // Standard scheme, use the standard macros. uint32_t major = VK_VERSION_MAJOR(props.driverVersion); @@ -456,13 +459,13 @@ public: // TODO: Make these actually query the right information switch (info) { case APINAME: return "Vulkan"; - case VENDORSTRING: return vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).deviceName; - case VENDOR: return VulkanVendorString(vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).vendorID); - case DRIVER: return FormatDriverVersion(vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice())); + case VENDORSTRING: return vulkan_->GetPhysicalDeviceProperties().properties.deviceName; + case VENDOR: return VulkanVendorString(vulkan_->GetPhysicalDeviceProperties().properties.vendorID); + case DRIVER: return FormatDriverVersion(vulkan_->GetPhysicalDeviceProperties().properties); case SHADELANGVERSION: return "N/A";; case APIVERSION: { - uint32_t ver = vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).apiVersion; + uint32_t ver = vulkan_->GetPhysicalDeviceProperties().properties.apiVersion; return StringFromFormat("%d.%d.%d", ver >> 22, (ver >> 12) & 0x3ff, ver & 0xfff); } default: return "?"; @@ -750,19 +753,19 @@ bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const Textur VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit) : vulkan_(vulkan), caps_{}, renderManager_(vulkan) { - caps_.anisoSupported = vulkan->GetFeaturesAvailable().samplerAnisotropy != 0; - caps_.geometryShaderSupported = vulkan->GetFeaturesAvailable().geometryShader != 0; - caps_.tesselationShaderSupported = vulkan->GetFeaturesAvailable().tessellationShader != 0; - caps_.multiViewport = vulkan->GetFeaturesAvailable().multiViewport != 0; - caps_.dualSourceBlend = vulkan->GetFeaturesAvailable().dualSrcBlend != 0; - caps_.depthClampSupported = vulkan->GetFeaturesAvailable().depthClamp != 0; + caps_.anisoSupported = vulkan->GetDeviceFeatures().enabled.samplerAnisotropy != 0; + caps_.geometryShaderSupported = vulkan->GetDeviceFeatures().enabled.geometryShader != 0; + caps_.tesselationShaderSupported = vulkan->GetDeviceFeatures().enabled.tessellationShader != 0; + caps_.multiViewport = vulkan->GetDeviceFeatures().enabled.multiViewport != 0; + caps_.dualSourceBlend = vulkan->GetDeviceFeatures().enabled.dualSrcBlend != 0; + caps_.depthClampSupported = vulkan->GetDeviceFeatures().enabled.depthClamp != 0; caps_.framebufferBlitSupported = true; caps_.framebufferCopySupported = true; caps_.framebufferDepthBlitSupported = false; // Can be checked for. caps_.framebufferDepthCopySupported = true; // Will pretty much always be the case. caps_.preferredDepthBufferFormat = DataFormat::D24_S8; // TODO: Ask vulkan. - auto deviceProps = vulkan->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()); + auto deviceProps = vulkan->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).properties; switch (deviceProps.vendorID) { case VULKAN_VENDOR_AMD: caps_.vendor = GPUVendor::VENDOR_AMD; break; case VULKAN_VENDOR_ARM: caps_.vendor = GPUVendor::VENDOR_ARM; break; @@ -1319,8 +1322,8 @@ static const char *VulkanFormatToString(VkFormat fmt) { } std::vector VKContext::GetFeatureList() const { - const VkPhysicalDeviceFeatures &available = vulkan_->GetFeaturesAvailable(); - const VkPhysicalDeviceFeatures &enabled = vulkan_->GetFeaturesEnabled(); + const VkPhysicalDeviceFeatures &available = vulkan_->GetDeviceFeatures().available; + const VkPhysicalDeviceFeatures &enabled = vulkan_->GetDeviceFeatures().enabled; std::vector features; AddFeature(features, "dualSrcBlend", available.dualSrcBlend, enabled.dualSrcBlend); From 32f37723f92352d784fa230b49a86ec956d86a3d Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Tue, 5 Feb 2019 10:20:40 +0100 Subject: [PATCH 317/347] Properly use VK_KHR_dedicated_allocation to make some drivers extra happy --- Common/Vulkan/VulkanImage.cpp | 28 +++++++++- ext/native/thin3d/VulkanRenderManager.cpp | 68 ++++++++++++++++++----- 2 files changed, 79 insertions(+), 17 deletions(-) diff --git a/Common/Vulkan/VulkanImage.cpp b/Common/Vulkan/VulkanImage.cpp index 8344699157..68b1801f67 100644 --- a/Common/Vulkan/VulkanImage.cpp +++ b/Common/Vulkan/VulkanImage.cpp @@ -72,9 +72,27 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, } VkMemoryRequirements mem_reqs{}; - vkGetImageMemoryRequirements(vulkan_->GetDevice(), image_, &mem_reqs); - if (allocator_) { + bool dedicatedAllocation = false; + if (vulkan_->DeviceExtensions().KHR_dedicated_allocation) { + VkImageMemoryRequirementsInfo2KHR memReqInfo2{VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR}; + memReqInfo2.image = image_; + + VkMemoryRequirements2KHR memReq2 = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR}; + VkMemoryDedicatedRequirementsKHR memDedicatedReq{VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR}; + memReq2.pNext = &memDedicatedReq; + + vkGetImageMemoryRequirements2KHR(vulkan_->GetDevice(), &memReqInfo2, &memReq2); + + mem_reqs = memReq2.memoryRequirements; + dedicatedAllocation = + (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE) || + (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE); + } else { + vkGetImageMemoryRequirements(vulkan_->GetDevice(), image_, &mem_reqs); + } + + if (allocator_ && !dedicatedAllocation) { offset_ = allocator_->Allocate(mem_reqs, &mem_, Tag()); if (offset_ == VulkanDeviceAllocator::ALLOCATE_FAILED) { ELOG("Image memory allocation failed (mem_reqs.size=%d, typebits=%08x", (int)mem_reqs.size, (int)mem_reqs.memoryTypeBits); @@ -86,6 +104,12 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, mem_alloc.memoryTypeIndex = 0; mem_alloc.allocationSize = mem_reqs.size; + VkMemoryDedicatedAllocateInfoKHR dedicatedAllocateInfo{VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR}; + if (dedicatedAllocation) { + dedicatedAllocateInfo.image = image_; + mem_alloc.pNext = &dedicatedAllocateInfo; + } + // Find memory type - don't specify any mapping requirements bool pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &mem_alloc.memoryTypeIndex); _assert_(pass); diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index 7f3cb56715..c63e0dd412 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -42,24 +42,39 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int vkCreateImage(vulkan->GetDevice(), &ici, nullptr, &img.image); VkMemoryRequirements memreq; - vkGetImageMemoryRequirements(vulkan->GetDevice(), img.image, &memreq); + + bool dedicatedAllocation = false; + if (vulkan->DeviceExtensions().KHR_dedicated_allocation) { + VkImageMemoryRequirementsInfo2KHR memReqInfo2{VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR}; + memReqInfo2.image = img.image; + + VkMemoryRequirements2KHR memReq2 = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR}; + VkMemoryDedicatedRequirementsKHR memDedicatedReq{VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR}; + memReq2.pNext = &memDedicatedReq; + + vkGetImageMemoryRequirements2KHR(vulkan->GetDevice(), &memReqInfo2, &memReq2); + + memreq = memReq2.memoryRequirements; + dedicatedAllocation = + (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE) || + (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE); + } else { + vkGetImageMemoryRequirements(vulkan->GetDevice(), img.image, &memreq); + } VkMemoryAllocateInfo alloc{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; alloc.allocationSize = memreq.size; - - /* - // Hint to the driver that this allocation is image-specific. Some drivers benefit. - // We only bother supporting the KHR extension, not the old NV one. - VkMemoryDedicatedAllocateInfoKHR dedicated{ VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR }; - if (vulkan->DeviceExtensions().DEDICATED_ALLOCATION) { - alloc.pNext = &dedicated; - dedicated.image = img.image; + VkMemoryDedicatedAllocateInfoKHR dedicatedAllocateInfo{VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR}; + if (dedicatedAllocation) { + dedicatedAllocateInfo.image = img.image; + alloc.pNext = &dedicatedAllocateInfo; } - */ vulkan->MemoryTypeFromProperties(memreq.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &alloc.memoryTypeIndex); + VkResult res = vkAllocateMemory(vulkan->GetDevice(), &alloc, nullptr, &img.memory); assert(res == VK_SUCCESS); + res = vkBindImageMemory(vulkan->GetDevice(), img.image, img.memory, 0); assert(res == VK_SUCCESS); @@ -554,10 +569,6 @@ bool VulkanRenderManager::InitDepthStencilBuffer(VkCommandBuffer cmd) { image_info.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; image_info.flags = 0; - VkMemoryAllocateInfo mem_alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; - mem_alloc.allocationSize = 0; - mem_alloc.memoryTypeIndex = 0; - VkMemoryRequirements mem_reqs; depth_.format = depth_format; @@ -568,9 +579,36 @@ bool VulkanRenderManager::InitDepthStencilBuffer(VkCommandBuffer cmd) { if (res != VK_SUCCESS) return false; - vkGetImageMemoryRequirements(device, depth_.image, &mem_reqs); + bool dedicatedAllocation = false; + if (vulkan_->DeviceExtensions().KHR_dedicated_allocation) { + VkImageMemoryRequirementsInfo2KHR memReqInfo2{VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR}; + memReqInfo2.image = depth_.image; + VkMemoryRequirements2KHR memReq2 = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR}; + VkMemoryDedicatedRequirementsKHR memDedicatedReq{VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR}; + memReq2.pNext = &memDedicatedReq; + + vkGetImageMemoryRequirements2KHR(vulkan_->GetDevice(), &memReqInfo2, &memReq2); + + mem_reqs = memReq2.memoryRequirements; + dedicatedAllocation = + (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE) || + (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE); + } else { + vkGetImageMemoryRequirements(vulkan_->GetDevice(), depth_.image, &mem_reqs); + } + + + VkMemoryAllocateInfo mem_alloc = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; mem_alloc.allocationSize = mem_reqs.size; + mem_alloc.memoryTypeIndex = 0; + + VkMemoryDedicatedAllocateInfoKHR dedicatedAllocateInfo{VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR}; + if (dedicatedAllocation) { + dedicatedAllocateInfo.image = depth_.image; + mem_alloc.pNext = &dedicatedAllocateInfo; + } + // Use the memory properties to determine the type of memory required pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, 0, /* No requirements */ From 7ae6ba9d91b729858c5981c327fd214f652aa048 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Tue, 5 Feb 2019 10:35:38 +0100 Subject: [PATCH 318/347] Add code to enable a couple more extensions I anticipate using eventually. --- Common/Vulkan/VulkanContext.cpp | 2 ++ Common/Vulkan/VulkanContext.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index b518157d4b..03cfb76730 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -623,6 +623,8 @@ VkResult VulkanContext::CreateDevice() { extensionsLookup_.KHR_dedicated_allocation = EnableDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); } extensionsLookup_.EXT_external_memory_host = EnableDeviceExtension(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME); + extensionsLookup_.KHR_depth_stencil_resolve = EnableDeviceExtension(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME); + extensionsLookup_.EXT_shader_stencil_export = EnableDeviceExtension(VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME); VkDeviceCreateInfo device_info{ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; device_info.queueCreateInfoCount = 1; diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index a785f285eb..41d1cd3436 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -107,6 +107,8 @@ struct VulkanDeviceExtensions { bool KHR_dedicated_allocation; bool EXT_external_memory_host; bool KHR_get_physical_device_properties2; + bool KHR_depth_stencil_resolve; + bool EXT_shader_stencil_export; // bool EXT_depth_range_unrestricted; // Allows depth outside [0.0, 1.0] in 32-bit float depth buffers. }; From 014668b9bc537eb1397e4b5c73bc167f7c5d3f70 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Tue, 5 Feb 2019 10:58:18 +0100 Subject: [PATCH 319/347] Update glslang to latest version --- UWP/glslang_UWP/glslang_UWP.vcxproj | 3 ++- ext/glslang | 2 +- ext/glslang-build/Android.mk | 1 + ext/glslang.vcxproj | 1 + ext/glslang.vcxproj.filters | 3 +++ 5 files changed, 8 insertions(+), 2 deletions(-) diff --git a/UWP/glslang_UWP/glslang_UWP.vcxproj b/UWP/glslang_UWP/glslang_UWP.vcxproj index 446c6d00d4..13eadac609 100644 --- a/UWP/glslang_UWP/glslang_UWP.vcxproj +++ b/UWP/glslang_UWP/glslang_UWP.vcxproj @@ -390,6 +390,7 @@ + Create Create @@ -405,4 +406,4 @@ - \ No newline at end of file + diff --git a/ext/glslang b/ext/glslang index 29619b2312..9983f99e87 160000 --- a/ext/glslang +++ b/ext/glslang @@ -1 +1 @@ -Subproject commit 29619b2312f7bc862221749f3f4d37c3e6a0dee2 +Subproject commit 9983f99e87ab0b6608b236ea59bcf873f90e1435 diff --git a/ext/glslang-build/Android.mk b/ext/glslang-build/Android.mk index 47e232c5cf..4b642c6586 100644 --- a/ext/glslang-build/Android.mk +++ b/ext/glslang-build/Android.mk @@ -50,6 +50,7 @@ LOCAL_SRC_FILES := \ ../glslang/SPIRV/InReadableOrder.cpp \ ../glslang/SPIRV/SpvBuilder.cpp \ ../glslang/SPIRV/SPVRemapper.cpp \ + ../glslang/SPIRV/SpvPostProcess.cpp \ ../glslang/OGLCompilersDLL/InitializeDll.cpp diff --git a/ext/glslang.vcxproj b/ext/glslang.vcxproj index abc83b6c34..2d3af8be1d 100644 --- a/ext/glslang.vcxproj +++ b/ext/glslang.vcxproj @@ -193,6 +193,7 @@ + diff --git a/ext/glslang.vcxproj.filters b/ext/glslang.vcxproj.filters index d37c8c805e..2e0e95ab88 100644 --- a/ext/glslang.vcxproj.filters +++ b/ext/glslang.vcxproj.filters @@ -140,6 +140,9 @@ glslang + + SPIRV + From 478b0b42782a985f2fe8b485f44f222043a89449 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Tue, 5 Feb 2019 13:00:23 +0100 Subject: [PATCH 320/347] Further improve VK extension loading. Switch to VK_EXT_debug_utils (but fallback to VK_EXT_debug_report if only that is available). --- Common/Vulkan/VulkanContext.cpp | 72 +++++++++++++++++++++----- Common/Vulkan/VulkanContext.h | 18 +++---- Common/Vulkan/VulkanDebug.cpp | 59 ++++++++++++++++++++- Common/Vulkan/VulkanDebug.h | 3 +- Common/Vulkan/VulkanLoader.cpp | 76 ++++++++++++++++++++-------- Common/Vulkan/VulkanLoader.h | 35 +++++++++++-- Windows/GPU/WindowsVulkanContext.cpp | 14 ++++- android/jni/AndroidVulkanContext.cpp | 2 + 8 files changed, 225 insertions(+), 54 deletions(-) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index 03cfb76730..ac64e2716f 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -120,9 +120,6 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { //#if defined(VK_USE_PLATFORM_XCB_KHR) // instance_extensions_enabled_.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME); //#endif -//#if defined(VK_USE_PLATFORM_MIR_KHR) -// instance_extensions_enabled_.push_back(VK_KHR_MIR_SURFACE_EXTENSION_NAME); -//#endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) if (IsInstanceExtensionAvailable(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME)) { instance_extensions_enabled_.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); @@ -131,12 +128,21 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { #endif if (flags_ & VULKAN_FLAG_VALIDATE) { - if (IsInstanceExtensionAvailable(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) { + if (IsInstanceExtensionAvailable(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) { + // Enable the validation layers + for (size_t i = 0; i < ARRAY_SIZE(validationLayers); i++) { + instance_layer_names_.push_back(validationLayers[i]); + device_layer_names_.push_back(validationLayers[i]); + } + instance_extensions_enabled_.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + extensionsLookup_.EXT_debug_utils = true; + } else if (IsInstanceExtensionAvailable(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) { for (size_t i = 0; i < ARRAY_SIZE(validationLayers); i++) { instance_layer_names_.push_back(validationLayers[i]); device_layer_names_.push_back(validationLayers[i]); } instance_extensions_enabled_.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); + extensionsLookup_.EXT_debug_report = true; } else { ELOG("Validation layer extension not available - not enabling Vulkan validation."); flags_ &= ~VULKAN_FLAG_VALIDATE; @@ -195,7 +201,7 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { return res; } - VulkanLoadInstanceFunctions(instance_); + VulkanLoadInstanceFunctions(instance_, extensionsLookup_); if (!CheckLayers(instance_layer_properties_, instance_layer_names_)) { WLOG("CheckLayers for instance failed"); // init_error_ = "Failed to validate instance layers"; @@ -604,8 +610,8 @@ VkResult VulkanContext::CreateDevice() { return VK_ERROR_INITIALIZATION_FAILED; } - VkDeviceQueueCreateInfo queue_info{ VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO }; - float queue_priorities[1] = { 1.0f }; + VkDeviceQueueCreateInfo queue_info{VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO}; + float queue_priorities[1] = {1.0f}; queue_info.queueCount = 1; queue_info.pQueuePriorities = queue_priorities; bool found = false; @@ -618,12 +624,24 @@ VkResult VulkanContext::CreateDevice() { } assert(found); + extensionsLookup_.KHR_maintenance1 = EnableDeviceExtension(VK_KHR_MAINTENANCE1_EXTENSION_NAME); + extensionsLookup_.KHR_maintenance2 = EnableDeviceExtension(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + extensionsLookup_.KHR_maintenance3 = EnableDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); + extensionsLookup_.KHR_multiview = EnableDeviceExtension(VK_KHR_MULTIVIEW_EXTENSION_NAME); + if (EnableDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME)) { extensionsLookup_.KHR_get_memory_requirements2 = true; extensionsLookup_.KHR_dedicated_allocation = EnableDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); } - extensionsLookup_.EXT_external_memory_host = EnableDeviceExtension(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME); - extensionsLookup_.KHR_depth_stencil_resolve = EnableDeviceExtension(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME); + if (EnableDeviceExtension(VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME)) { + if (EnableDeviceExtension(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME)) { + extensionsLookup_.EXT_external_memory_host = EnableDeviceExtension(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME); + } + } + if (EnableDeviceExtension(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) { + extensionsLookup_.KHR_create_renderpass2 = true; + extensionsLookup_.KHR_depth_stencil_resolve = EnableDeviceExtension(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME); + } extensionsLookup_.EXT_shader_stencil_export = EnableDeviceExtension(VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME); VkDeviceCreateInfo device_info{ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; @@ -640,7 +658,7 @@ VkResult VulkanContext::CreateDevice() { init_error_ = "Unable to create Vulkan device"; ELOG("Unable to create Vulkan device"); } else { - VulkanLoadDeviceFunctions(device_); + VulkanLoadDeviceFunctions(device_, extensionsLookup_); } ILOG("Device created.\n"); VulkanSetAvailable(true); @@ -662,7 +680,7 @@ VkResult VulkanContext::InitDebugMsgCallback(PFN_vkDebugReportCallbackEXT dbgFun cb.flags = bits; cb.pfnCallback = dbgFunc; cb.pUserData = userdata; - VkResult res = dyn_vkCreateDebugReportCallbackEXT(instance_, &cb, nullptr, &msg_callback); + VkResult res = vkCreateDebugReportCallbackEXT(instance_, &cb, nullptr, &msg_callback); switch (res) { case VK_SUCCESS: msg_callbacks.push_back(msg_callback); @@ -676,12 +694,42 @@ VkResult VulkanContext::InitDebugMsgCallback(PFN_vkDebugReportCallbackEXT dbgFun } void VulkanContext::DestroyDebugMsgCallback() { + if (!extensionsLookup_.EXT_debug_report) + return; while (msg_callbacks.size() > 0) { - dyn_vkDestroyDebugReportCallbackEXT(instance_, msg_callbacks.back(), nullptr); + vkDestroyDebugReportCallbackEXT(instance_, msg_callbacks.back(), nullptr); msg_callbacks.pop_back(); } } +VkResult VulkanContext::InitDebugUtilsCallback(PFN_vkDebugUtilsMessengerCallbackEXT callback, int bits, void *userdata) { + VkDebugUtilsMessengerCreateInfoEXT callback1{VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT}; + callback1.messageSeverity = bits; + callback1.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + callback1.pfnUserCallback = callback; + callback1.pUserData = userdata; + VkDebugUtilsMessengerEXT messenger; + VkResult res = vkCreateDebugUtilsMessengerEXT(instance_, &callback1, nullptr, &messenger); + if (res != VK_SUCCESS) { + ELOG("Failed to register debug callback with vkCreateDebugUtilsMessengerEXT"); + // Do error handling for VK_ERROR_OUT_OF_MEMORY + } else { + ILOG("Debug callback registered with vkCreateDebugUtilsMessengerEXT."); + utils_callbacks.push_back(messenger); + } + return res; +} + +void VulkanContext::DestroyDebugUtilsCallback() { + if (!extensionsLookup_.EXT_debug_utils) + return; + while (utils_callbacks.size() > 0) { + vkDestroyDebugUtilsMessengerEXT(instance_, utils_callbacks.back(), nullptr); + utils_callbacks.pop_back(); + } +} + + VkResult VulkanContext::InitSurface(WindowSystem winsys, void *data1, void *data2) { winsys_ = winsys; winsysData1_ = data1; diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index 41d1cd3436..42ae79d132 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -101,17 +101,6 @@ private: std::vector callbacks_; }; -// For fast extension-enabled checks. -struct VulkanDeviceExtensions { - bool KHR_get_memory_requirements2; - bool KHR_dedicated_allocation; - bool EXT_external_memory_host; - bool KHR_get_physical_device_properties2; - bool KHR_depth_stencil_resolve; - bool EXT_shader_stencil_export; - // bool EXT_depth_range_unrestricted; // Allows depth outside [0.0, 1.0] in 32-bit float depth buffers. -}; - // Useful for debugging on ARM Mali. This eliminates transaction elimination // which can cause artifacts if you get barriers wrong (or if there are driver bugs). // Cost is reduced performance on some GPU architectures. @@ -175,7 +164,11 @@ public: bool MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex); - VkResult InitDebugMsgCallback(PFN_vkDebugReportCallbackEXT dbgFunc, int bits, void *userdata = nullptr); + VkResult InitDebugUtilsCallback(PFN_vkDebugUtilsMessengerCallbackEXT callback, int bits, void *userdata); + void DestroyDebugUtilsCallback(); + + // Legacy reporting + VkResult InitDebugMsgCallback(PFN_vkDebugReportCallbackEXT dbgFunc, int bits, void *userdata); void DestroyDebugMsgCallback(); VkPhysicalDevice GetPhysicalDevice(int n = 0) const { @@ -334,6 +327,7 @@ private: VulkanDeleteList globalDeleteList_; std::vector msg_callbacks; + std::vector utils_callbacks; VkSwapchainKHR swapchain_ = VK_NULL_HANDLE; VkFormat swapchainFormat_; diff --git a/Common/Vulkan/VulkanDebug.cpp b/Common/Vulkan/VulkanDebug.cpp index 81925a4653..64538196ff 100644 --- a/Common/Vulkan/VulkanDebug.cpp +++ b/Common/Vulkan/VulkanDebug.cpp @@ -56,7 +56,7 @@ const char *ObjTypeToString(VkDebugReportObjectTypeEXT type) { } } -VkBool32 VKAPI_CALL Vulkan_Dbg(VkDebugReportFlagsEXT msgFlags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void *pUserData) { +VkBool32 VKAPI_CALL VulkanDebugReportCallback(VkDebugReportFlagsEXT msgFlags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void *pUserData) { const VulkanLogOptions *options = (const VulkanLogOptions *)pUserData; std::ostringstream message; @@ -103,3 +103,60 @@ VkBool32 VKAPI_CALL Vulkan_Dbg(VkDebugReportFlagsEXT msgFlags, VkDebugReportObje // keep that behavior here. return false; } + +VkBool32 VKAPI_CALL VulkanDebugUtilsCallback( + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void* pUserData) { + const VulkanLogOptions *options = (const VulkanLogOptions *)pUserData; + std::ostringstream message; + + const char *pMessage = pCallbackData->pMessage; + int messageCode = pCallbackData->messageIdNumber; + const char *pLayerPrefix = ""; + // Ignore perf warnings for now. Could log them, so still want them registered. + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { + message << "ERROR("; + } else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { + message << "WARNING("; + } else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) { + message << "INFO("; + } else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) { + message << "VERBOSE("; + } + + if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) { + message << "perf"; + } else if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) { + message << "general"; + } else if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) { + message << "validation"; + } + message << ":" << pCallbackData->messageIdNumber << ") " << pMessage << "\n"; + + +#ifdef _WIN32 + std::string msg = message.str(); + OutputDebugStringA(msg.c_str()); + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { + if (options->breakOnError && IsDebuggerPresent()) { + DebugBreak(); + } + if (options->msgBoxOnError) { + MessageBoxA(NULL, pMessage, "Alert", MB_OK); + } + } else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { + if (options->breakOnWarning && IsDebuggerPresent() && 0 == (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)) { + DebugBreak(); + } + } +#endif + + // false indicates that layer should not bail-out of an + // API call that had validation failures. This may mean that the + // app dies inside the driver due to invalid parameter(s). + // That's what would happen without validation layers, so we'll + // keep that behavior here. + return false; +} diff --git a/Common/Vulkan/VulkanDebug.h b/Common/Vulkan/VulkanDebug.h index 21a4e671bb..10cb70d8ed 100644 --- a/Common/Vulkan/VulkanDebug.h +++ b/Common/Vulkan/VulkanDebug.h @@ -25,4 +25,5 @@ struct VulkanLogOptions { bool msgBoxOnError; }; -VkBool32 VKAPI_CALL Vulkan_Dbg(VkDebugReportFlagsEXT msgFlags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void *pUserData); +VkBool32 VKAPI_CALL VulkanDebugReportCallback(VkDebugReportFlagsEXT msgFlags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void *pUserData); +VkBool32 VKAPI_CALL VulkanDebugUtilsCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, void *pUserData); diff --git a/Common/Vulkan/VulkanLoader.cpp b/Common/Vulkan/VulkanLoader.cpp index b9e4522005..aedcfd639b 100644 --- a/Common/Vulkan/VulkanLoader.cpp +++ b/Common/Vulkan/VulkanLoader.cpp @@ -193,8 +193,16 @@ PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; PFN_vkQueuePresentKHR vkQueuePresentKHR; // And the DEBUG_REPORT extension. We dynamically load this. -PFN_vkCreateDebugReportCallbackEXT dyn_vkCreateDebugReportCallbackEXT; -PFN_vkDestroyDebugReportCallbackEXT dyn_vkDestroyDebugReportCallbackEXT; +PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT; +PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; + +PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT; +PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT; +PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT; +PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT; +PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT; +PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT; +PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT; PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT; PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; @@ -262,19 +270,22 @@ bool VulkanMayBeAvailable() { VkApplicationInfo info{ VK_STRUCTURE_TYPE_APPLICATION_INFO }; std::vector devices; bool anyGood = false; - const char *instanceExtensions[1]{}; + const char *instanceExtensions[2]{}; VkInstance instance = VK_NULL_HANDLE; VkResult res; uint32_t physicalDeviceCount = 0; - uint32_t instanceExtCount = 0; + uint32_t instanceExtCount = 1; + bool surfaceExtensionFound = false; + bool platformSurfaceExtensionFound = false; std::vector instanceExts; + instanceExtensions[ci.enabledExtensionCount++] = VK_KHR_SURFACE_EXTENSION_NAME; #ifdef _WIN32 - const char * const surfaceExtension = VK_KHR_WIN32_SURFACE_EXTENSION_NAME; + const char * const platformSurfaceExtension = VK_KHR_WIN32_SURFACE_EXTENSION_NAME; #elif defined(__ANDROID__) - const char *surfaceExtension = VK_KHR_ANDROID_SURFACE_EXTENSION_NAME; + const char *platformSurfaceExtension = VK_KHR_ANDROID_SURFACE_EXTENSION_NAME; #else - const char *surfaceExtension = 0; + const char *platformSurfaceExtension = 0; #endif if (!localEnumerateInstanceExtensionProperties || !localCreateInstance || !localEnumerate || !localDestroyInstance || !localGetPhysicalDeviceProperties) @@ -297,16 +308,18 @@ bool VulkanMayBeAvailable() { goto bail; } - if (surfaceExtension) { + if (platformSurfaceExtension) { for (auto iter : instanceExts) { - if (!strcmp(iter.extensionName, surfaceExtension)) { - instanceExtensions[0] = surfaceExtension; - ci.enabledExtensionCount = 1; + if (!strcmp(iter.extensionName, platformSurfaceExtension)) { + instanceExtensions[ci.enabledExtensionCount++] = platformSurfaceExtension; + platformSurfaceExtensionFound = true; break; + } else if (!strcmp(iter.extensionName, VK_KHR_SURFACE_EXTENSION_NAME)) { + surfaceExtensionFound = true; } } - if (!ci.enabledExtensionCount) { - ELOG("Surface extension not found"); + if (!platformSurfaceExtensionFound || !surfaceExtensionFound) { + ELOG("Platform surface extension not found"); goto bail; } } @@ -411,7 +424,7 @@ bool VulkanLoad() { return true; } -void VulkanLoadInstanceFunctions(VkInstance instance) { +void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanDeviceExtensions &enabledExtensions) { // OK, let's use the above functions to get the rest. LOAD_INSTANCE_FUNC(instance, vkDestroyInstance); LOAD_INSTANCE_FUNC(instance, vkEnumeratePhysicalDevices); @@ -570,11 +583,26 @@ void VulkanLoadInstanceFunctions(VkInstance instance) { #endif LOAD_INSTANCE_FUNC(instance, vkDestroySurfaceKHR); - LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceProperties2KHR); - LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceFeatures2KHR); - dyn_vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"); - dyn_vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"); + if (enabledExtensions.KHR_get_physical_device_properties2) { + LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceProperties2KHR); + LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceFeatures2KHR); + } + + if (enabledExtensions.EXT_debug_report) { + LOAD_INSTANCE_FUNC(instance, vkCreateDebugReportCallbackEXT); + LOAD_INSTANCE_FUNC(instance, vkDestroyDebugReportCallbackEXT); + } + + if (enabledExtensions.EXT_debug_utils) { + LOAD_INSTANCE_FUNC(instance, vkCreateDebugUtilsMessengerEXT); + LOAD_INSTANCE_FUNC(instance, vkDestroyDebugUtilsMessengerEXT); + LOAD_INSTANCE_FUNC(instance, vkCmdBeginDebugUtilsLabelEXT); + LOAD_INSTANCE_FUNC(instance, vkCmdEndDebugUtilsLabelEXT); + LOAD_INSTANCE_FUNC(instance, vkCmdInsertDebugUtilsLabelEXT); + LOAD_INSTANCE_FUNC(instance, vkSetDebugUtilsObjectNameEXT); + LOAD_INSTANCE_FUNC(instance, vkSetDebugUtilsObjectTagEXT); + } WLOG("Vulkan instance functions loaded."); } @@ -582,7 +610,7 @@ void VulkanLoadInstanceFunctions(VkInstance instance) { // On some implementations, loading functions (that have Device as their first parameter) via vkGetDeviceProcAddr may // increase performance - but then these function pointers will only work on that specific device. Thus, this loader is not very // good for multi-device. -void VulkanLoadDeviceFunctions(VkDevice device) { +void VulkanLoadDeviceFunctions(VkDevice device, const VulkanDeviceExtensions &enabledExtensions) { WLOG("Vulkan device functions loaded."); // TODO: Move more functions VulkanLoadInstanceFunctions to here. LOAD_DEVICE_FUNC(device, vkCreateSwapchainKHR); @@ -590,9 +618,13 @@ void VulkanLoadDeviceFunctions(VkDevice device) { LOAD_DEVICE_FUNC(device, vkGetSwapchainImagesKHR); LOAD_DEVICE_FUNC(device, vkAcquireNextImageKHR); LOAD_DEVICE_FUNC(device, vkQueuePresentKHR); - LOAD_DEVICE_FUNC(device, vkGetMemoryHostPointerPropertiesEXT); - LOAD_DEVICE_FUNC(device, vkGetBufferMemoryRequirements2KHR); - LOAD_DEVICE_FUNC(device, vkGetImageMemoryRequirements2KHR); + if (enabledExtensions.EXT_external_memory_host) { + LOAD_DEVICE_FUNC(device, vkGetMemoryHostPointerPropertiesEXT); + } + if (enabledExtensions.KHR_dedicated_allocation) { + LOAD_DEVICE_FUNC(device, vkGetBufferMemoryRequirements2KHR); + LOAD_DEVICE_FUNC(device, vkGetImageMemoryRequirements2KHR); + } } void VulkanFree() { diff --git a/Common/Vulkan/VulkanLoader.h b/Common/Vulkan/VulkanLoader.h index 25c93efee0..3d1ccae86b 100644 --- a/Common/Vulkan/VulkanLoader.h +++ b/Common/Vulkan/VulkanLoader.h @@ -197,8 +197,16 @@ extern PFN_vkQueuePresentKHR vkQueuePresentKHR; // And the DEBUG_REPORT extension. Since we load this dynamically even in static // linked mode, we have to rename it :( -extern PFN_vkCreateDebugReportCallbackEXT dyn_vkCreateDebugReportCallbackEXT; -extern PFN_vkDestroyDebugReportCallbackEXT dyn_vkDestroyDebugReportCallbackEXT; +extern PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT; +extern PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; + +extern PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT; +extern PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT; +extern PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT; +extern PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT; +extern PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT; +extern PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT; +extern PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT; // Assorted other extensions. extern PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; @@ -207,11 +215,30 @@ extern PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesE extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; + +// For fast extension-enabled checks. +struct VulkanDeviceExtensions { + bool EXT_debug_report; + bool EXT_debug_utils; + bool KHR_maintenance1; // required for KHR_create_renderpass2 + bool KHR_maintenance2; + bool KHR_maintenance3; + bool KHR_multiview; // required for KHR_create_renderpass2 + bool KHR_get_memory_requirements2; + bool KHR_dedicated_allocation; + bool KHR_create_renderpass2; + bool EXT_external_memory_host; + bool KHR_get_physical_device_properties2; + bool KHR_depth_stencil_resolve; + bool EXT_shader_stencil_export; + // bool EXT_depth_range_unrestricted; // Allows depth outside [0.0, 1.0] in 32-bit float depth buffers. +}; + // Way to do a quick check before even attempting to load. bool VulkanMayBeAvailable(); void VulkanSetAvailable(bool available); bool VulkanLoad(); -void VulkanLoadInstanceFunctions(VkInstance instance); -void VulkanLoadDeviceFunctions(VkDevice device); +void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanDeviceExtensions &enabledExtensions); +void VulkanLoadDeviceFunctions(VkDevice device, const VulkanDeviceExtensions &enabledExtensions); void VulkanFree(); diff --git a/Windows/GPU/WindowsVulkanContext.cpp b/Windows/GPU/WindowsVulkanContext.cpp index 77abd7d94b..fbbf1ce12d 100644 --- a/Windows/GPU/WindowsVulkanContext.cpp +++ b/Windows/GPU/WindowsVulkanContext.cpp @@ -124,8 +124,17 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m return false; } if (g_validate_) { - int bits = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; - g_Vulkan->InitDebugMsgCallback(&Vulkan_Dbg, bits, &g_LogOptions); + if (g_Vulkan->DeviceExtensions().EXT_debug_utils) { + int bits = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + g_Vulkan->InitDebugUtilsCallback(&VulkanDebugUtilsCallback, bits, &g_LogOptions); + } else { + int bits = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; + g_Vulkan->InitDebugMsgCallback(&VulkanDebugReportCallback, bits, &g_LogOptions); + } } g_Vulkan->InitSurface(WINDOWSYSTEM_WIN32, (void *)hInst, (void *)hWnd); if (!g_Vulkan->InitObjects()) { @@ -160,6 +169,7 @@ void WindowsVulkanContext::Shutdown() { g_Vulkan->WaitUntilQueueIdle(); g_Vulkan->DestroyObjects(); g_Vulkan->DestroyDevice(); + g_Vulkan->DestroyDebugUtilsCallback(); g_Vulkan->DestroyDebugMsgCallback(); g_Vulkan->DestroyInstance(); diff --git a/android/jni/AndroidVulkanContext.cpp b/android/jni/AndroidVulkanContext.cpp index 78b1211b10..f20247145c 100644 --- a/android/jni/AndroidVulkanContext.cpp +++ b/android/jni/AndroidVulkanContext.cpp @@ -160,6 +160,7 @@ bool AndroidVulkanContext::InitFromRenderThread(ANativeWindow *wnd, int desiredB if (!success) { g_Vulkan->DestroyObjects(); g_Vulkan->DestroyDevice(); + g_Vulkan->DestroyDebugUtilsCallback(); g_Vulkan->DestroyDebugMsgCallback(); g_Vulkan->DestroyInstance(); @@ -181,6 +182,7 @@ void AndroidVulkanContext::ShutdownFromRenderThread() { void AndroidVulkanContext::Shutdown() { ILOG("Calling NativeShutdownGraphics"); g_Vulkan->DestroyDevice(); + g_Vulkan->DestroyDebugUtilsCallback(); g_Vulkan->DestroyDebugMsgCallback(); g_Vulkan->DestroyInstance(); From e30daa802779b7b24170d69fa5d63473df6835c4 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Tue, 5 Feb 2019 13:10:05 +0100 Subject: [PATCH 321/347] Remove unused API, assorted cleanup. No longer enable the geometry shader feature, no plans to use it. --- Common/Vulkan/VulkanContext.cpp | 18 +++++++----------- GPU/Vulkan/DrawEngineVulkan.cpp | 1 - GPU/Vulkan/PipelineManagerVulkan.cpp | 1 - GPU/Vulkan/VulkanUtil.cpp | 7 +++---- ext/native/thin3d/thin3d.h | 7 ------- ext/native/thin3d/thin3d_vulkan.cpp | 17 ++++------------- 6 files changed, 14 insertions(+), 37 deletions(-) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index ac64e2716f..63ef9abd45 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -77,6 +77,8 @@ const char *PresentModeString(VkPresentModeKHR presentMode) { case VK_PRESENT_MODE_MAILBOX_KHR: return "MAILBOX"; case VK_PRESENT_MODE_FIFO_KHR: return "FIFO"; case VK_PRESENT_MODE_FIFO_RELAXED_KHR: return "FIFO_RELAXED"; + case VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR: return "SHARED_DEMAND_REFRESH_KHR"; + case VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR: return "SHARED_CONTINUOUS_REFRESH_KHR"; default: return "UNKNOWN"; } } @@ -548,7 +550,6 @@ void VulkanContext::ChooseDevice(int physical_device) { } // Optional features - if (extensionsLookup_.KHR_get_physical_device_properties2) { VkPhysicalDeviceFeatures2 features2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR}; vkGetPhysicalDeviceFeatures2KHR(physical_devices_[physical_device_], &features2); @@ -569,9 +570,6 @@ void VulkanContext::ChooseDevice(int physical_device) { if (deviceFeatures_.available.wideLines) { deviceFeatures_.enabled.wideLines = true; } - if (deviceFeatures_.available.geometryShader) { - deviceFeatures_.enabled.geometryShader = true; - } if (deviceFeatures_.available.logicOp) { deviceFeatures_.enabled.logicOp = true; } @@ -674,9 +672,7 @@ VkResult VulkanContext::InitDebugMsgCallback(PFN_vkDebugReportCallbackEXT dbgFun } ILOG("Registering debug report callback"); - VkDebugReportCallbackCreateInfoEXT cb = {}; - cb.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; - cb.pNext = nullptr; + VkDebugReportCallbackCreateInfoEXT cb{VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT}; cb.flags = bits; cb.pfnCallback = dbgFunc; cb.pUserData = userdata; @@ -769,7 +765,7 @@ VkResult VulkanContext::ReinitSurface() { #if defined(VK_USE_PLATFORM_XLIB_KHR) case WINDOWSYSTEM_XLIB: { - VkXlibSurfaceCreateInfoKHR xlib = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR }; + VkXlibSurfaceCreateInfoKHR xlib{ VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR }; xlib.flags = 0; xlib.dpy = (Display *)winsysData1_; xlib.window = (Window)winsysData2_; @@ -779,7 +775,7 @@ VkResult VulkanContext::ReinitSurface() { #if defined(VK_USE_PLATFORM_XCB_KHR) case WINDOWSYSTEM_XCB: { - VkXCBSurfaceCreateInfoKHR xcb = { VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR }; + VkXCBSurfaceCreateInfoKHR xcb{ VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR }; xcb.flags = 0; xcb.connection = (Connection *)winsysData1_; xcb.window = (Window)(uintptr_t)winsysData2_; @@ -789,7 +785,7 @@ VkResult VulkanContext::ReinitSurface() { #if defined(VK_USE_PLATFORM_WAYLAND_KHR) case WINDOWSYSTEM_WAYLAND: { - VkWaylandSurfaceCreateInfoKHR wayland = { VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR }; + VkWaylandSurfaceCreateInfoKHR wayland{ VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR }; wayland.flags = 0; wayland.display = (wl_display *)winsysData1_; wayland.surface = (wl_surface *)winsysData2_; @@ -973,7 +969,7 @@ bool VulkanContext::InitSwapchain() { preTransform = surfCapabilities_.currentTransform; } - VkSwapchainCreateInfoKHR swap_chain_info = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR }; + VkSwapchainCreateInfoKHR swap_chain_info{ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR }; swap_chain_info.surface = surface_; swap_chain_info.minImageCount = desiredNumberOfSwapChainImages; swap_chain_info.imageFormat = swapchainFormat_; diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 4d9de9b4eb..daeef502dc 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -401,7 +401,6 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView VkDescriptorSet desc; VkDescriptorSetAllocateInfo descAlloc{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; - descAlloc.pNext = nullptr; descAlloc.pSetLayouts = &descriptorSetLayout_; descAlloc.descriptorPool = frame.descPool; descAlloc.descriptorSetCount = 1; diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 8f803d563d..27d513aa2c 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -237,7 +237,6 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip inputAssembly.flags = 0; inputAssembly.topology = (VkPrimitiveTopology)key.topology; inputAssembly.primitiveRestartEnable = false; - int vertexStride = 0; int offset = 0; diff --git a/GPU/Vulkan/VulkanUtil.cpp b/GPU/Vulkan/VulkanUtil.cpp index d7d6223fc8..424594d641 100644 --- a/GPU/Vulkan/VulkanUtil.cpp +++ b/GPU/Vulkan/VulkanUtil.cpp @@ -160,12 +160,11 @@ VkDescriptorSet Vulkan2D::GetDescriptorSet(VkImageView tex1, VkSampler sampler1, assert(result == VK_SUCCESS); // We just don't write to the slots we don't care about. - VkWriteDescriptorSet writes[2]; - memset(writes, 0, sizeof(writes)); + VkWriteDescriptorSet writes[2]{}; // Main and sub textures int n = 0; - VkDescriptorImageInfo image1 = {}; - VkDescriptorImageInfo image2 = {}; + VkDescriptorImageInfo image1{}; + VkDescriptorImageInfo image2{}; if (tex1) { #ifdef VULKAN_USE_GENERAL_LAYOUT_FOR_COLOR image1.imageLayout = VK_IMAGE_LAYOUT_GENERAL; diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 20b96d5f0b..6365d9d9c6 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -655,13 +655,6 @@ public: virtual void HandleEvent(Event ev, int width, int height, void *param1 = nullptr, void *param2 = nullptr) = 0; - // This flushes command buffers and waits for execution at the point of the end of the last - // renderpass that wrote to the requested framebuffer. This is needed before trying to read it back - // on modern APIs like Vulkan. Ifr the framebuffer is currently being rendered to, we'll just end the render pass. - // The next draw call will automatically start up a new one. - // APIs like OpenGL won't need to implement this one. - virtual void WaitRenderCompletion(Framebuffer *fbo) {} - // Flush state like scissors etc so the caller can do its own custom drawing. virtual void FlushState() {} diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 6885e1bc84..7277647eb2 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -427,9 +427,7 @@ public: void EndFrame() override; void WipeQueue() override; - void FlushState() override { - } - void WaitRenderCompletion(Framebuffer *fbo) override; + void FlushState() override {} // From Sascha's code static std::string FormatDriverVersion(const VkPhysicalDeviceProperties &props) { @@ -894,10 +892,6 @@ void VKContext::BeginFrame() { _assert_(result == VK_SUCCESS); } -void VKContext::WaitRenderCompletion(Framebuffer *fbo) { - // TODO -} - void VKContext::EndFrame() { // Stop collecting data in the frame's data pushbuffer. push_->End(); @@ -1014,13 +1008,11 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) { dynamicInfo.dynamicStateCount = depth->info.stencilTestEnable ? ARRAY_SIZE(dynamics) : 2; dynamicInfo.pDynamicStates = dynamics; - VkPipelineMultisampleStateCreateInfo ms = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO }; - ms.pNext = nullptr; + VkPipelineMultisampleStateCreateInfo ms{ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO }; ms.pSampleMask = nullptr; ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - VkPipelineViewportStateCreateInfo vs = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO }; - vs.pNext = nullptr; + VkPipelineViewportStateCreateInfo vs{ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO }; vs.viewportCount = 1; vs.scissorCount = 1; vs.pViewports = nullptr; // dynamic @@ -1029,8 +1021,7 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) { VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO }; raster->ToVulkan(&rs); - VkGraphicsPipelineCreateInfo info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO }; - info.pNext = nullptr; + VkGraphicsPipelineCreateInfo info{ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO }; info.flags = 0; info.stageCount = (uint32_t)stages.size(); info.pStages = stages.data(); From 3d114c5bcaf5c39f8328ca1dc9e758232d504d85 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Wed, 6 Feb 2019 10:45:12 +0100 Subject: [PATCH 322/347] Compat: Force realistic UMD timing for F1 2006. Fixes #9193 but not the game, since there's also #11177. --- Core/Compatibility.cpp | 1 + Core/Compatibility.h | 1 + Core/HLE/sceIo.cpp | 25 ++++++++++++++++++------- assets/compat.ini | 5 +++++ 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp index 855218db6b..b0c12d4656 100644 --- a/Core/Compatibility.cpp +++ b/Core/Compatibility.cpp @@ -61,6 +61,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "SonicRivalsHack", &flags_.SonicRivalsHack); CheckSetting(iniFile, gameID, "BlockTransferAllowCreateFB", &flags_.BlockTransferAllowCreateFB); CheckSetting(iniFile, gameID, "YugiohSaveFix", &flags_.YugiohSaveFix); + CheckSetting(iniFile, gameID, "ForceUMDDelay", &flags_.ForceUMDDelay); } void Compatibility::CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag) { diff --git a/Core/Compatibility.h b/Core/Compatibility.h index 0d74f828f6..92eb8590ea 100644 --- a/Core/Compatibility.h +++ b/Core/Compatibility.h @@ -61,6 +61,7 @@ struct CompatFlags { bool SonicRivalsHack; bool BlockTransferAllowCreateFB; bool YugiohSaveFix; + bool ForceUMDDelay; }; class IniFile; diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index e4a525f5d7..341b31b8d9 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -253,6 +253,14 @@ public: u64 __IoCompleteAsyncIO(FileNode *f); +static int GetIOTimingMethod() { + if (PSP_CoreParameter().compat.flags().ForceUMDDelay) { + return IOTIMING_REALISTIC; + } else { + return g_Config.iIOTimingMethod; + } +} + static void TellFsThreadEnded (SceUID threadID) { pspFileSystem.ThreadEnded(threadID); } @@ -339,7 +347,8 @@ static void __IoAsyncNotify(u64 userdata, int cyclesLate) { return; } - if (g_Config.iIOTimingMethod == IOTIMING_HOST) { + int ioTimingMethod = GetIOTimingMethod(); + if (ioTimingMethod == IOTIMING_HOST) { // Not all async operations actually queue up. Maybe should separate them? if (!ioManager.HasResult(f->handle) && ioManager.HasOperation(f->handle)) { // Try again in another 0.5ms until the IO completes on the host. @@ -347,7 +356,7 @@ static void __IoAsyncNotify(u64 userdata, int cyclesLate) { return; } __IoCompleteAsyncIO(f); - } else if (g_Config.iIOTimingMethod == IOTIMING_REALISTIC) { + } else if (ioTimingMethod == IOTIMING_REALISTIC) { u64 finishTicks = __IoCompleteAsyncIO(f); if (finishTicks > CoreTiming::GetTicks()) { // Reschedule for later, since we now know how long it ought to take. @@ -396,13 +405,14 @@ static void __IoSyncNotify(u64 userdata, int cyclesLate) { return; } - if (g_Config.iIOTimingMethod == IOTIMING_HOST) { + int ioTimingMethod = GetIOTimingMethod(); + if (ioTimingMethod == IOTIMING_HOST) { if (!ioManager.HasResult(f->handle)) { // Try again in another 0.5ms until the IO completes on the host. CoreTiming::ScheduleEvent(usToCycles(500) - cyclesLate, syncNotifyEvent, userdata); return; } - } else if (g_Config.iIOTimingMethod == IOTIMING_REALISTIC) { + } else if (ioTimingMethod == IOTIMING_REALISTIC) { u64 finishTicks = ioManager.ResultFinishTicks(f->handle); if (finishTicks > CoreTiming::GetTicks()) { // Reschedule for later when the result should finish. @@ -723,7 +733,8 @@ static u32 sceKernelStderr() { u64 __IoCompleteAsyncIO(FileNode *f) { PROFILE_THIS_SCOPE("io_rw"); - if (g_Config.iIOTimingMethod == IOTIMING_REALISTIC) { + int ioTimingMethod = GetIOTimingMethod(); + if (ioTimingMethod == IOTIMING_REALISTIC) { u64 finishTicks = ioManager.ResultFinishTicks(f->handle); if (finishTicks > CoreTiming::GetTicks()) { return finishTicks; @@ -921,7 +932,7 @@ static bool __IoRead(int &result, int id, u32 data_addr, int size, int &us) { ioManager.ScheduleOperation(ev); return false; } else { - if (g_Config.iIOTimingMethod != IOTIMING_REALISTIC) { + if (GetIOTimingMethod() != IOTIMING_REALISTIC) { result = (int) pspFileSystem.ReadFile(f->handle, data, size); } else { result = (int) pspFileSystem.ReadFile(f->handle, data, size, us); @@ -1056,7 +1067,7 @@ static bool __IoWrite(int &result, int id, u32 data_addr, int size, int &us) { ioManager.ScheduleOperation(ev); return false; } else { - if (g_Config.iIOTimingMethod != IOTIMING_REALISTIC) { + if (GetIOTimingMethod() != IOTIMING_REALISTIC) { result = (int) pspFileSystem.WriteFile(f->handle, (u8 *) data_ptr, size); } else { result = (int) pspFileSystem.WriteFile(f->handle, (u8 *) data_ptr, size, us); diff --git a/assets/compat.ini b/assets/compat.ini index d64361c8eb..0839552275 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -384,3 +384,8 @@ ULJM05940 = true # Yu-Gi-Oh! ARC-V Tag Force Special NPJH00142 = true + +[ForceUMDDelay] +# F1 2006 +UCES00238 = true +UCJS10045 = true From e84c466532b198082c2807dde6eb6b6b5a7845e7 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Wed, 6 Feb 2019 12:23:59 +0100 Subject: [PATCH 323/347] Qt: Remove keyboard shortcut for buffered rendering. Mitigates #11725 although not a proper fix. --- Qt/mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Qt/mainwindow.cpp b/Qt/mainwindow.cpp index f2d7723d79..fbeaf17b1e 100644 --- a/Qt/mainwindow.cpp +++ b/Qt/mainwindow.cpp @@ -488,7 +488,7 @@ void MainWindow::createMenus() anisotropicGroup = new MenuActionGroup(this, anisotropicMenu, SLOT(anisotropicGroup_triggered(QAction *)), QStringList() << "Off" << "2x" << "4x" << "8x" << "16x", QList() << 0 << 1 << 2 << 3 << 4); - videoMenu->add(new MenuAction(this, SLOT(bufferRenderAct()), QT_TR_NOOP("&Buffered Rendering"), Qt::Key_F5)) + videoMenu->add(new MenuAction(this, SLOT(bufferRenderAct()), QT_TR_NOOP("&Buffered Rendering"))) ->addEventChecked(&g_Config.iRenderingMode); videoMenu->add(new MenuAction(this, SLOT(linearAct()), QT_TR_NOOP("&Linear Filtering"))) ->addEventChecked(&g_Config.iTexFiltering); From 7e9b889d0145c2ed5d9df9466d3eb40fa8031ebd Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Wed, 6 Feb 2019 13:01:48 +0100 Subject: [PATCH 324/347] Qt: Apply suggested keyboard shortcut fix. Fixes #11735. --- Qt/mainwindow.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Qt/mainwindow.cpp b/Qt/mainwindow.cpp index fbeaf17b1e..30949eb493 100644 --- a/Qt/mainwindow.cpp +++ b/Qt/mainwindow.cpp @@ -494,11 +494,12 @@ void MainWindow::createMenus() ->addEventChecked(&g_Config.iTexFiltering); videoMenu->addSeparator(); // - Screen Size - MenuTree* screenMenu = new MenuTree(this, videoMenu, QT_TR_NOOP("&Screen Size")); + MenuTree* screenMenu = new MenuTree(this, videoMenu, QT_TR_NOOP("&Screen Size")); screenGroup = new MenuActionGroup(this, screenMenu, SLOT(screenGroup_triggered(QAction *)), QStringList() << "1x" << "2x" << "3x" << "4x" << "5x" << "6x" << "7x" << "8x" << "9x" << "10x", - QList() << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10, - QList() << Qt::CTRL + Qt::Key_1 << Qt::CTRL + Qt::Key_2 << Qt::CTRL + Qt::Key_3 << Qt::CTRL + Qt::Key_4); + QList() << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10, + QList() << Qt::CTRL + Qt::Key_1 << Qt::CTRL + Qt::Key_2 << Qt::CTRL + Qt::Key_3 << Qt::CTRL + Qt::Key_4 << Qt::CTRL + Qt::Key_5 + << Qt::CTRL + Qt::Key_6 << Qt::CTRL + Qt::Key_7 << Qt::CTRL + Qt::Key_8 << Qt::CTRL + Qt::Key_9 << Qt::CTRL + Qt::Key_0); MenuTree* displayLayoutMenu = new MenuTree(this, videoMenu, QT_TR_NOOP("&Display Layout Options")); displayLayoutGroup = new MenuActionGroup(this, displayLayoutMenu, SLOT(displayLayoutGroup_triggered(QAction *)), From 47a9145355ecac56ef3d200fbec4533d36f86545 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Wed, 6 Feb 2019 10:54:03 +0100 Subject: [PATCH 325/347] Remove iForceMaxEmulatedFPS and replace with a compat setting for the two games that really need it. Takes care of one setting listed in #8171 "Options to remove" --- Core/Compatibility.cpp | 1 + Core/Compatibility.h | 1 + Core/Config.cpp | 1 - Core/Config.h | 1 - Core/HLE/sceDisplay.cpp | 4 ++-- UI/GameSettingsScreen.cpp | 4 ---- assets/compat.ini | 24 ++++++++++++++++++++++++ libretro/libretro.cpp | 3 --- 8 files changed, 28 insertions(+), 11 deletions(-) diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp index b0c12d4656..d5574488d1 100644 --- a/Core/Compatibility.cpp +++ b/Core/Compatibility.cpp @@ -62,6 +62,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "BlockTransferAllowCreateFB", &flags_.BlockTransferAllowCreateFB); CheckSetting(iniFile, gameID, "YugiohSaveFix", &flags_.YugiohSaveFix); CheckSetting(iniFile, gameID, "ForceUMDDelay", &flags_.ForceUMDDelay); + CheckSetting(iniFile, gameID, "ForceMax60FPS", &flags_.ForceMax60FPS); } void Compatibility::CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag) { diff --git a/Core/Compatibility.h b/Core/Compatibility.h index 92eb8590ea..c5a46ba9a2 100644 --- a/Core/Compatibility.h +++ b/Core/Compatibility.h @@ -62,6 +62,7 @@ struct CompatFlags { bool BlockTransferAllowCreateFB; bool YugiohSaveFix; bool ForceUMDDelay; + bool ForceMax60FPS; }; class IniFile; diff --git a/Core/Config.cpp b/Core/Config.cpp index 8326658d1d..4c366e5a07 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -625,7 +625,6 @@ static ConfigSetting graphicsSettings[] = { #if defined(USING_WIN_UI) ConfigSetting("RestartRequired", &g_Config.bRestartRequired, false, false), #endif - ReportedConfigSetting("ForceMaxEmulatedFPS", &g_Config.iForceMaxEmulatedFPS, 60, true, true), // Most low-performance (and many high performance) mobile GPUs do not support aniso anyway so defaulting to 4 is fine. ConfigSetting("AnisotropyLevel", &g_Config.iAnisotropyLevel, 4, true, true), diff --git a/Core/Config.h b/Core/Config.h index c5cf22f545..ce8ad14588 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -176,7 +176,6 @@ public: bool bTexDeposterize; int iFpsLimit1; int iFpsLimit2; - int iForceMaxEmulatedFPS; int iMaxRecent; int iCurrentStateSlot; int iRewindFlipFrequency; diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index b570aa4aeb..fadcd298e1 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -928,7 +928,7 @@ u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int sync) s64 delayCycles = 0; // Don't count transitions between display off and display on. - if (topaddr != 0 && topaddr != framebuf.topaddr && framebuf.topaddr != 0 && g_Config.iForceMaxEmulatedFPS > 0) { + if (topaddr != 0 && topaddr != framebuf.topaddr && framebuf.topaddr != 0 && PSP_CoreParameter().compat.flags().ForceMax60FPS) { // sceDisplaySetFramebuf() isn't supposed to delay threads at all. This is a hack. // So let's only delay when it's more than 1ms. const s64 FLIP_DELAY_CYCLES_MIN = usToCycles(1000); @@ -952,7 +952,7 @@ u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int sync) } // 1001 to account for NTSC timing (59.94 fps.) - u64 expected = msToCycles(1001) / g_Config.iForceMaxEmulatedFPS - LEEWAY_CYCLES_PER_FLIP; + u64 expected = msToCycles(1001) / 60 - LEEWAY_CYCLES_PER_FLIP; lastFlipCycles = now; nextFlipCycles = std::max(lastFlipCycles, nextFlipCycles) + expected; } diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 9f31ede54d..5159d96854 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -137,8 +137,6 @@ void GameSettingsScreen::CreateViews() { g_Config.loadGameConfig(gameID_); } - cap60FPS_ = g_Config.iForceMaxEmulatedFPS == 60; - iAlternateSpeedPercent1_ = g_Config.iFpsLimit1 < 0 ? -1 : (g_Config.iFpsLimit1 * 100) / 60; iAlternateSpeedPercent2_ = g_Config.iFpsLimit2 < 0 ? -1 : (g_Config.iFpsLimit2 * 100) / 60; @@ -276,7 +274,6 @@ void GameSettingsScreen::CreateViews() { graphicsSettings->Add(new PopupMultiChoice(&g_Config.iFrameSkipType, gr->T("Frame Skipping Type"), frameSkipType, 0, ARRAY_SIZE(frameSkipType), gr->GetName(), screenManager())); frameSkipAuto_ = graphicsSettings->Add(new CheckBox(&g_Config.bAutoFrameSkip, gr->T("Auto FrameSkip"))); frameSkipAuto_->OnClick.Handle(this, &GameSettingsScreen::OnAutoFrameskip); - graphicsSettings->Add(new CheckBox(&cap60FPS_, gr->T("Force max 60 FPS (helps GoW)"))); PopupSliderChoice *altSpeed1 = graphicsSettings->Add(new PopupSliderChoice(&iAlternateSpeedPercent1_, 0, 1000, gr->T("Alternative Speed", "Alternative speed"), 5, screenManager(), gr->T("%, 0:unlimited"))); altSpeed1->SetFormat("%i%%"); @@ -1037,7 +1034,6 @@ UI::EventReturn GameSettingsScreen::OnDumpNextFrameToLog(UI::EventParams &e) { void GameSettingsScreen::update() { UIScreen::update(); - g_Config.iForceMaxEmulatedFPS = cap60FPS_ ? 60 : 0; g_Config.iFpsLimit1 = iAlternateSpeedPercent1_ < 0 ? -1 : (iAlternateSpeedPercent1_ * 60) / 100; g_Config.iFpsLimit2 = iAlternateSpeedPercent2_ < 0 ? -1 : (iAlternateSpeedPercent2_ * 60) / 100; diff --git a/assets/compat.ini b/assets/compat.ini index 0839552275..34f295d2b0 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -389,3 +389,27 @@ NPJH00142 = true # F1 2006 UCES00238 = true UCJS10045 = true + +[ForceMax60FPS] +# The GOW games are very heavy and render as fast as they can. They benefit greatly from +# capping the framerate at 60fps. + +# GOW : Ghost of Sparta +UCUS98737 = true +UCAS40323 = true +NPHG00092 = true +NPEG00044 = true +NPJG00120 = true +UCJS10114 = true +UCES01401 = true +# GOW : Chains Of Olympus +UCUS98653 = true +UCUS98705 = true +UCES00842 = true +ULJM05438 = true +ULJM05348 = true +UCKS45084 = true +NPUG80325 = true +NPEG00023 = true +NPHG00028 = true +NPJG00120 = true diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index 7ea47093b9..4b528588ce 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -170,7 +170,6 @@ static RetroOption ppsspp_rendering_mode("ppsspp_rendering_mode", "Renderin static RetroOption ppsspp_auto_frameskip("ppsspp_auto_frameskip", "Auto Frameskip", false); static RetroOption ppsspp_frameskip("ppsspp_frameskip", "Frameskip", 0, 10); static RetroOption ppsspp_frameskiptype("ppsspp_frameskiptype", "Frameskip Type", 0, 10); -static RetroOption ppsspp_force_max_fps("ppsspp_force_max_fps", "Force Max FPS", { { "disabled", 0 }, { "enabled", 60 } }); static RetroOption ppsspp_audio_latency("ppsspp_audio_latency", "Audio latency", { "low", "medium", "high" }); static RetroOption ppsspp_internal_resolution("ppsspp_internal_resolution", "Internal Resolution", 1, { "480x272", "960x544", "1440x816", "1920x1088", "2400x1360", "2880x1632", "3360x1904", "3840x2176", "4320x2448", "4800x2720" }); static RetroOption ppsspp_button_preference("ppsspp_button_preference", "Confirmation Button", { { "cross", PSP_SYSTEMPARAM_BUTTON_CROSS }, { "circle", PSP_SYSTEMPARAM_BUTTON_CIRCLE } }); @@ -198,7 +197,6 @@ void retro_set_environment(retro_environment_t cb) { vars.push_back(ppsspp_auto_frameskip.GetOptions()); vars.push_back(ppsspp_frameskip.GetOptions()); vars.push_back(ppsspp_frameskiptype.GetOptions()); - vars.push_back(ppsspp_force_max_fps.GetOptions()); vars.push_back(ppsspp_audio_latency.GetOptions()); vars.push_back(ppsspp_internal_resolution.GetOptions()); vars.push_back(ppsspp_button_preference.GetOptions()); @@ -282,7 +280,6 @@ static void check_variables(CoreParameter &coreParam) { ppsspp_cheats.Update(&g_Config.bEnableCheats); ppsspp_locked_cpu_speed.Update(&g_Config.iLockedCPUSpeed); ppsspp_rendering_mode.Update(&g_Config.iRenderingMode); - ppsspp_force_max_fps.Update(&g_Config.iForceMaxEmulatedFPS); ppsspp_cpu_core.Update((CPUCore *)&g_Config.iCpuCore); ppsspp_language.Update(&g_Config.iLanguage); From 38a2d83aa8de6fba961308b5c51b52a892332d42 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Wed, 6 Feb 2019 12:18:04 +0100 Subject: [PATCH 326/347] Partially revert #10456 (avoid limit FPS without a clear). It's a pretty gnarly hack-upon-a-hack. Better to remove the original hack (limit fps) in the general case. --- Core/HLE/sceDisplay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index fadcd298e1..4b25735e31 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -942,7 +942,7 @@ u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int sync) u64 now = CoreTiming::GetTicks(); s64 cyclesAhead = nextFlipCycles - now; if (cyclesAhead > FLIP_DELAY_CYCLES_MIN) { - if (lastFlipsTooFrequent >= FLIP_DELAY_MIN_FLIPS && gpuStats.numClears > 0) { + if (lastFlipsTooFrequent >= FLIP_DELAY_MIN_FLIPS) { delayCycles = cyclesAhead; } else { ++lastFlipsTooFrequent; From d43858dfc7091b0494d4ac78ad7bdf48ec6e081b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 6 Feb 2019 18:28:52 +0100 Subject: [PATCH 327/347] Enable the FPS limit for F1 2006, too. --- assets/compat.ini | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/assets/compat.ini b/assets/compat.ini index 34f295d2b0..c8991bdc2c 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -386,7 +386,7 @@ ULJM05940 = true NPJH00142 = true [ForceUMDDelay] -# F1 2006 +# F1 2006 won't boot at all with our standard unrealistically fast timing. UCES00238 = true UCJS10045 = true @@ -413,3 +413,7 @@ NPUG80325 = true NPEG00023 = true NPHG00028 = true NPJG00120 = true + +# F1 2006 has extremely long loading times if we don't limit the framerate. +UCES00238 = true +UCJS10045 = true From d15e71915a45ef8d033ce92ea9de8a87388dd3e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 6 Feb 2019 19:57:44 +0100 Subject: [PATCH 328/347] Add missing break statement fixing bizarre language menu issue from #7929 --- Windows/MainWindowMenu.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index 057872be4f..130a35fd69 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -685,6 +685,7 @@ namespace MainWindow { SaveState::SaveSlot(PSP_CoreParameter().fileToStart, g_Config.iCurrentStateSlot, SaveStateActionFinished); break; } + break; } case ID_OPTIONS_LANGUAGE: From 54c6c148fbf81bb8e17e0c56c7cadbc16cfd229e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 6 Feb 2019 22:43:31 +0100 Subject: [PATCH 329/347] Detect PCI device ID where available (not in GL?) --- ext/native/thin3d/thin3d.h | 2 ++ ext/native/thin3d/thin3d_d3d11.cpp | 1 + ext/native/thin3d/thin3d_d3d9.cpp | 2 +- ext/native/thin3d/thin3d_vulkan.cpp | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 6365d9d9c6..c07b6130b5 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -493,6 +493,8 @@ struct PipelineDesc { struct DeviceCaps { GPUVendor vendor; + uint32_t deviceID; // use caution! + DataFormat preferredDepthBufferFormat; DataFormat preferredShadowMapFormatLow; DataFormat preferredShadowMapFormatHigh; diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index e93abb4c7e..2d8fae57b3 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -267,6 +267,7 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de default: caps_.vendor = GPUVendor::VENDOR_UNKNOWN; } + caps_.deviceID = desc.DeviceId; adapter->Release(); } dxgiDevice->Release(); diff --git a/ext/native/thin3d/thin3d_d3d9.cpp b/ext/native/thin3d/thin3d_d3d9.cpp index 8273446d48..d5d4c45bcd 100644 --- a/ext/native/thin3d/thin3d_d3d9.cpp +++ b/ext/native/thin3d/thin3d_d3d9.cpp @@ -603,7 +603,7 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID } else { strcpy(shadeLangVersion_, "N/A"); } - + caps_.deviceID = identifier_.DeviceId; caps_.multiViewport = false; caps_.anisoSupported = true; caps_.depthRangeMinusOneToOne = false; diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 7277647eb2..1ff74d1d5a 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -791,6 +791,7 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit) bugs_.Infest(Bugs::DUAL_SOURCE_BLENDING_BROKEN); } + caps_.deviceID = deviceProps.deviceID; device_ = vulkan->GetDevice(); queue_ = vulkan->GetGraphicsQueue(); From 8af523596f68a260515679dea38c7b77dbf8d69a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 6 Feb 2019 22:44:02 +0100 Subject: [PATCH 330/347] Disable vertex range culling on old NVIDIA. Should help #11638 --- GPU/Directx9/GPU_DX9.cpp | 73 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 2 deletions(-) diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index e7501ca702..62b3caf1c2 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -106,6 +106,63 @@ GPU_DX9::GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw) } } +// TODO: Move this detection elsewhere when it's needed elsewhere, not before. It's ugly. +// Source: https://envytools.readthedocs.io/en/latest/hw/pciid.html#gf100 +enum NVIDIAGeneration { + NV_PRE_KEPLER, + NV_KEPLER, + NV_MAXWELL, + NV_PASCAL, + NV_VOLTA, + NV_TURING, // or later +}; + +static NVIDIAGeneration NVIDIAGetDeviceGeneration(int deviceID) { + if (deviceID >= 0x1180 && deviceID <= 0x11bf) + return NV_KEPLER; // GK104 + if (deviceID >= 0x11c0 && deviceID <= 0x11fa) + return NV_KEPLER; // GK106 + if (deviceID >= 0x0fc0 && deviceID <= 0x0fff) + return NV_KEPLER; // GK107 + if (deviceID >= 0x1003 && deviceID <= 0x1028) + return NV_KEPLER; // GK110(B) + if (deviceID >= 0x1280 && deviceID <= 0x12ba) + return NV_KEPLER; // GK208 + if (deviceID >= 0x1381 && deviceID <= 0x13b0) + return NV_MAXWELL; // GM107 + if (deviceID >= 0x1340 && deviceID <= 0x134d) + return NV_MAXWELL; // GM108 + if (deviceID >= 0x13c0 && deviceID <= 0x13d9) + return NV_MAXWELL; // GM204 + if (deviceID >= 0x1401 && deviceID <= 0x1427) + return NV_MAXWELL; // GM206 + if (deviceID >= 0x15f7 && deviceID <= 0x15f9) + return NV_PASCAL; // GP100 + if (deviceID >= 0x15f7 && deviceID <= 0x15f9) + return NV_PASCAL; // GP100 + if (deviceID >= 0x1b00 && deviceID <= 0x1b38) + return NV_PASCAL; // GP102 + if (deviceID >= 0x1b80 && deviceID <= 0x1be1) + return NV_PASCAL; // GP104 + if (deviceID >= 0x1c02 && deviceID <= 0x1c62) + return NV_PASCAL; // GP106 + if (deviceID >= 0x1c81 && deviceID <= 0x1c92) + return NV_PASCAL; // GP107 + if (deviceID >= 0x1d01 && deviceID <= 0x1d12) + return NV_PASCAL; // GP108 + if (deviceID >= 0x1d81 && deviceID <= 0x1dba) + return NV_VOLTA; // GV100 + if (deviceID >= 0x1e02 && deviceID <= 0x1e3c) + return NV_TURING; // TU102 + if (deviceID >= 0x1e82 && deviceID <= 0x1ed0) + return NV_TURING; // TU104 + if (deviceID >= 0x1f02 && deviceID <= 0x1f51) + return NV_TURING; // TU104 + if (deviceID >= 0x1e02) + return NV_TURING; // More TU models or later, probably. + return NV_PRE_KEPLER; +} + void GPU_DX9::CheckGPUFeatures() { u32 features = 0; features |= GPU_SUPPORTS_16BIT_FORMATS; @@ -119,9 +176,21 @@ void GPU_DX9::CheckGPUFeatures() { features |= GPU_SUPPORTS_ACCURATE_DEPTH; } - // VS range culling causes problems on Intel. - if (vendor != Draw::GPUVendor::VENDOR_INTEL) { + // VS range culling (killing triangles in the vertex shader using NaN) causes problems on Intel. + // Also causes problems on old NVIDIA. + switch (vendor) { + case Draw::GPUVendor::VENDOR_INTEL: + break; + case Draw::GPUVendor::VENDOR_NVIDIA: + // Older NVIDIAs don't seem to like NaNs in their DX9 vertex shaders. + // No idea if KEPLER is the right cutoff, but let's go with it. + if (NVIDIAGetDeviceGeneration(draw_->GetDeviceCaps().deviceID) >= NV_KEPLER) { + features |= GPU_SUPPORTS_VS_RANGE_CULLING; + } + break; + default: features |= GPU_SUPPORTS_VS_RANGE_CULLING; + break; } D3DCAPS9 caps; From f38a6650b17ef04b2b93f229db3655f85c8344c9 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 7 Feb 2019 14:56:29 +0100 Subject: [PATCH 331/347] VK code cleanup: Just a little helper for handling dedicated allocation for images. --- Common/Vulkan/VulkanContext.cpp | 21 ++++++++++++ Common/Vulkan/VulkanContext.h | 2 ++ Common/Vulkan/VulkanDebug.cpp | 3 +- Common/Vulkan/VulkanImage.cpp | 19 +---------- ext/native/thin3d/VulkanRenderManager.cpp | 40 ++--------------------- 5 files changed, 28 insertions(+), 57 deletions(-) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index 63ef9abd45..c71d9edbbe 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -1319,3 +1319,24 @@ void VulkanDeleteList::PerformDeletes(VkDevice device) { } descSetLayouts_.clear(); } + +void VulkanContext::GetImageMemoryRequirements(VkImage image, VkMemoryRequirements *mem_reqs, bool *dedicatedAllocation) { + if (DeviceExtensions().KHR_dedicated_allocation) { + VkImageMemoryRequirementsInfo2KHR memReqInfo2{VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR}; + memReqInfo2.image = image; + + VkMemoryRequirements2KHR memReq2 = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR}; + VkMemoryDedicatedRequirementsKHR memDedicatedReq{VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR}; + memReq2.pNext = &memDedicatedReq; + + vkGetImageMemoryRequirements2KHR(GetDevice(), &memReqInfo2, &memReq2); + + *mem_reqs = memReq2.memoryRequirements; + *dedicatedAllocation = + (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE) || + (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE); + } else { + vkGetImageMemoryRequirements(GetDevice(), image, mem_reqs); + *dedicatedAllocation = false; + } +} diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index 42ae79d132..01761aab6b 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -262,6 +262,8 @@ public: const VulkanDeviceExtensions &DeviceExtensions() { return extensionsLookup_; } + void GetImageMemoryRequirements(VkImage image, VkMemoryRequirements *mem_reqs, bool *dedicatedAllocation); + private: // A layer can expose extensions, keep track of those extensions here. struct LayerProperties { diff --git a/Common/Vulkan/VulkanDebug.cpp b/Common/Vulkan/VulkanDebug.cpp index 64538196ff..be7512b738 100644 --- a/Common/Vulkan/VulkanDebug.cpp +++ b/Common/Vulkan/VulkanDebug.cpp @@ -115,7 +115,6 @@ VkBool32 VKAPI_CALL VulkanDebugUtilsCallback( const char *pMessage = pCallbackData->pMessage; int messageCode = pCallbackData->messageIdNumber; const char *pLayerPrefix = ""; - // Ignore perf warnings for now. Could log them, so still want them registered. if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { message << "ERROR("; } else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { @@ -135,7 +134,6 @@ VkBool32 VKAPI_CALL VulkanDebugUtilsCallback( } message << ":" << pCallbackData->messageIdNumber << ") " << pMessage << "\n"; - #ifdef _WIN32 std::string msg = message.str(); OutputDebugStringA(msg.c_str()); @@ -147,6 +145,7 @@ VkBool32 VKAPI_CALL VulkanDebugUtilsCallback( MessageBoxA(NULL, pMessage, "Alert", MB_OK); } } else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { + // Don't break on perf warnings for now, even with a debugger. We log them at least. if (options->breakOnWarning && IsDebuggerPresent() && 0 == (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)) { DebugBreak(); } diff --git a/Common/Vulkan/VulkanImage.cpp b/Common/Vulkan/VulkanImage.cpp index 68b1801f67..4c4d2fcff1 100644 --- a/Common/Vulkan/VulkanImage.cpp +++ b/Common/Vulkan/VulkanImage.cpp @@ -72,25 +72,8 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, } VkMemoryRequirements mem_reqs{}; - bool dedicatedAllocation = false; - if (vulkan_->DeviceExtensions().KHR_dedicated_allocation) { - VkImageMemoryRequirementsInfo2KHR memReqInfo2{VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR}; - memReqInfo2.image = image_; - - VkMemoryRequirements2KHR memReq2 = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR}; - VkMemoryDedicatedRequirementsKHR memDedicatedReq{VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR}; - memReq2.pNext = &memDedicatedReq; - - vkGetImageMemoryRequirements2KHR(vulkan_->GetDevice(), &memReqInfo2, &memReq2); - - mem_reqs = memReq2.memoryRequirements; - dedicatedAllocation = - (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE) || - (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE); - } else { - vkGetImageMemoryRequirements(vulkan_->GetDevice(), image_, &mem_reqs); - } + vulkan_->GetImageMemoryRequirements(image_, &mem_reqs, &dedicatedAllocation); if (allocator_ && !dedicatedAllocation) { offset_ = allocator_->Allocate(mem_reqs, &mem_, Tag()); diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index c63e0dd412..dac2b50492 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -42,25 +42,8 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int vkCreateImage(vulkan->GetDevice(), &ici, nullptr, &img.image); VkMemoryRequirements memreq; - bool dedicatedAllocation = false; - if (vulkan->DeviceExtensions().KHR_dedicated_allocation) { - VkImageMemoryRequirementsInfo2KHR memReqInfo2{VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR}; - memReqInfo2.image = img.image; - - VkMemoryRequirements2KHR memReq2 = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR}; - VkMemoryDedicatedRequirementsKHR memDedicatedReq{VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR}; - memReq2.pNext = &memDedicatedReq; - - vkGetImageMemoryRequirements2KHR(vulkan->GetDevice(), &memReqInfo2, &memReq2); - - memreq = memReq2.memoryRequirements; - dedicatedAllocation = - (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE) || - (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE); - } else { - vkGetImageMemoryRequirements(vulkan->GetDevice(), img.image, &memreq); - } + vulkan->GetImageMemoryRequirements(img.image, &memreq, &dedicatedAllocation); VkMemoryAllocateInfo alloc{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; alloc.allocationSize = memreq.size; @@ -569,7 +552,6 @@ bool VulkanRenderManager::InitDepthStencilBuffer(VkCommandBuffer cmd) { image_info.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; image_info.flags = 0; - VkMemoryRequirements mem_reqs; depth_.format = depth_format; @@ -580,24 +562,8 @@ bool VulkanRenderManager::InitDepthStencilBuffer(VkCommandBuffer cmd) { return false; bool dedicatedAllocation = false; - if (vulkan_->DeviceExtensions().KHR_dedicated_allocation) { - VkImageMemoryRequirementsInfo2KHR memReqInfo2{VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR}; - memReqInfo2.image = depth_.image; - - VkMemoryRequirements2KHR memReq2 = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR}; - VkMemoryDedicatedRequirementsKHR memDedicatedReq{VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR}; - memReq2.pNext = &memDedicatedReq; - - vkGetImageMemoryRequirements2KHR(vulkan_->GetDevice(), &memReqInfo2, &memReq2); - - mem_reqs = memReq2.memoryRequirements; - dedicatedAllocation = - (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE) || - (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE); - } else { - vkGetImageMemoryRequirements(vulkan_->GetDevice(), depth_.image, &mem_reqs); - } - + VkMemoryRequirements mem_reqs; + vulkan_->GetImageMemoryRequirements(depth_.image, &mem_reqs, &dedicatedAllocation); VkMemoryAllocateInfo mem_alloc = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; mem_alloc.allocationSize = mem_reqs.size; From bff58d0921acc2654d485a81231cc592235939b2 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 7 Feb 2019 15:44:26 +0100 Subject: [PATCH 332/347] Update lang --- assets/lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/lang b/assets/lang index 4238fedf68..f97aa5d000 160000 --- a/assets/lang +++ b/assets/lang @@ -1 +1 @@ -Subproject commit 4238fedf686fb868bbe8d32ec009260e4ecc1e09 +Subproject commit f97aa5d000b0a27e27b88b0072ccf932de506eae From 9736bc431aba6525510a52a0629f95e0cf00dca4 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 8 Feb 2019 14:46:16 +0100 Subject: [PATCH 333/347] The block transfer setting should not affect clearing memory behind a render target, especially since that's already gated behind a compat flag. --- GPU/D3D11/DrawEngineD3D11.cpp | 2 +- GPU/Directx9/DrawEngineDX9.cpp | 2 +- GPU/GLES/DrawEngineGLES.cpp | 6 +++--- GPU/Vulkan/DrawEngineVulkan.cpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 129325fc69..3e52cf83ef 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -657,7 +657,7 @@ rotateVBO: int scissorX2 = gstate.getScissorX2() + 1; int scissorY2 = gstate.getScissorY2() + 1; framebufferManager_->SetSafeSize(scissorX2, scissorY2); - if (g_Config.bBlockTransferGPU && (gstate_c.featureFlags & GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate.FrameBufFormat() == GE_FORMAT_565)) { + if ((gstate_c.featureFlags & GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate.FrameBufFormat() == GE_FORMAT_565)) { int scissorX1 = gstate.getScissorX1(); int scissorY1 = gstate.getScissorY1(); framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, clearColor); diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index 0f1c0b62d3..9d02936e71 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -593,7 +593,7 @@ rotateVBO: int scissorX2 = gstate.getScissorX2() + 1; int scissorY2 = gstate.getScissorY2() + 1; framebufferManager_->SetSafeSize(scissorX2, scissorY2); - if (g_Config.bBlockTransferGPU && (gstate_c.featureFlags & GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate.FrameBufFormat() == GE_FORMAT_565)) { + if ((gstate_c.featureFlags & GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate.FrameBufFormat() == GE_FORMAT_565)) { int scissorX1 = gstate.getScissorX1(); int scissorY1 = gstate.getScissorY1(); framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, clearColor); diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 30f71fdd99..b24be91098 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -609,8 +609,6 @@ rotateVBO: if (alphaMask) target |= GL_STENCIL_BUFFER_BIT; if (depthMask) target |= GL_DEPTH_BUFFER_BIT; - int scissorX1 = gstate.getScissorX1(); - int scissorY1 = gstate.getScissorY1(); int scissorX2 = gstate.getScissorX2() + 1; int scissorY2 = gstate.getScissorY2() + 1; @@ -618,7 +616,9 @@ rotateVBO: framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason); framebufferManager_->SetSafeSize(scissorX2, scissorY2); - if (g_Config.bBlockTransferGPU && (gstate_c.featureFlags & GPU_USE_CLEAR_RAM_HACK) && colorMask && (alphaMask || gstate.FrameBufFormat() == GE_FORMAT_565)) { + if ((gstate_c.featureFlags & GPU_USE_CLEAR_RAM_HACK) && colorMask && (alphaMask || gstate.FrameBufFormat() == GE_FORMAT_565)) { + int scissorX1 = gstate.getScissorX1(); + int scissorY1 = gstate.getScissorY1(); framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, clearColor); } gstate_c.Dirty(DIRTY_BLEND_STATE); // Make sure the color mask gets re-applied. diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index daeef502dc..a2a9737a31 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -968,7 +968,7 @@ void DrawEngineVulkan::DoFlush() { int scissorY2 = gstate.getScissorY2() + 1; framebufferManager_->SetSafeSize(scissorX2, scissorY2); - if (g_Config.bBlockTransferGPU && (gstate_c.featureFlags & GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate.FrameBufFormat() == GE_FORMAT_565)) { + if ((gstate_c.featureFlags & GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate.FrameBufFormat() == GE_FORMAT_565)) { framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, result.color); } } From 11c8450f196f261e6e509448d873464f44797d4c Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 8 Feb 2019 14:50:47 +0100 Subject: [PATCH 334/347] Only gate really expensive block transfers behind the setting. --- GPU/Common/FramebufferCommon.cpp | 89 ++++++++++++++------------------ GPU/GPUCommon.cpp | 3 +- 2 files changed, 39 insertions(+), 53 deletions(-) diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index 7468b2258f..96634edc69 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -1280,11 +1280,9 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, } else { WARN_LOG_REPORT_ONCE(dstnotsrccpy, G3D, "Inter-buffer memcpy %08x -> %08x", src, dst); // Just do the blit! - if (g_Config.bBlockTransferGPU) { - BlitFramebuffer(dstBuffer, 0, dstY, srcBuffer, 0, srcY, srcBuffer->width, srcH, 0); - SetColorUpdated(dstBuffer, skipDrawReason); - RebindFramebuffer(); - } + BlitFramebuffer(dstBuffer, 0, dstY, srcBuffer, 0, srcY, srcBuffer->width, srcH, 0); + SetColorUpdated(dstBuffer, skipDrawReason); + RebindFramebuffer(); } return false; } else if (dstBuffer) { @@ -1292,15 +1290,12 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, gpuStats.numClears++; } WARN_LOG_ONCE(btucpy, G3D, "Memcpy fbo upload %08x -> %08x", src, dst); - if (g_Config.bBlockTransferGPU) { - FlushBeforeCopy(); - const u8 *srcBase = Memory::GetPointerUnchecked(src); - DrawPixels(dstBuffer, 0, dstY, srcBase, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->width, dstH); - SetColorUpdated(dstBuffer, skipDrawReason); - RebindFramebuffer(); - // This is a memcpy, let's still copy just in case. - return false; - } + FlushBeforeCopy(); + const u8 *srcBase = Memory::GetPointerUnchecked(src); + DrawPixels(dstBuffer, 0, dstY, srcBase, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->width, dstH); + SetColorUpdated(dstBuffer, skipDrawReason); + RebindFramebuffer(); + // This is a memcpy, let's still copy just in case. return false; } else if (srcBuffer) { WARN_LOG_ONCE(btdcpy, G3D, "Memcpy fbo download %08x -> %08x", src, dst); @@ -1638,29 +1633,23 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst if (srcBuffer == dstBuffer) { if (srcX != dstX || srcY != dstY) { WARN_LOG_ONCE(dstsrc, G3D, "Intra-buffer block transfer %08x -> %08x", srcBasePtr, dstBasePtr); - if (g_Config.bBlockTransferGPU) { - FlushBeforeCopy(); - BlitFramebuffer(dstBuffer, dstX, dstY, srcBuffer, srcX, srcY, dstWidth, dstHeight, bpp); - RebindFramebuffer(); - SetColorUpdated(dstBuffer, skipDrawReason); - return true; - } - } else { - // Ignore, nothing to do. Tales of Phantasia X does this by accident. - if (g_Config.bBlockTransferGPU) { - return true; - } - } - } else { - WARN_LOG_ONCE(dstnotsrc, G3D, "Inter-buffer block transfer %08x -> %08x", srcBasePtr, dstBasePtr); - // Just do the blit! - if (g_Config.bBlockTransferGPU) { FlushBeforeCopy(); BlitFramebuffer(dstBuffer, dstX, dstY, srcBuffer, srcX, srcY, dstWidth, dstHeight, bpp); RebindFramebuffer(); SetColorUpdated(dstBuffer, skipDrawReason); - return true; // No need to actually do the memory copy behind, probably. + return true; + } else { + // Ignore, nothing to do. Tales of Phantasia X does this by accident. + return true; } + } else { + WARN_LOG_ONCE(dstnotsrc, G3D, "Inter-buffer block transfer %08x -> %08x", srcBasePtr, dstBasePtr); + // Just do the blit! + FlushBeforeCopy(); + BlitFramebuffer(dstBuffer, dstX, dstY, srcBuffer, srcX, srcY, dstWidth, dstHeight, bpp); + RebindFramebuffer(); + SetColorUpdated(dstBuffer, skipDrawReason); + return true; // No need to actually do the memory copy behind, probably. } return false; } else if (dstBuffer) { @@ -1718,26 +1707,24 @@ void FramebufferManagerCommon::NotifyBlockTransferAfter(u32 dstBasePtr, int dstS if (dstBuffer && !srcBuffer) { WARN_LOG_ONCE(btu, G3D, "Block transfer upload %08x -> %08x", srcBasePtr, dstBasePtr); - if (g_Config.bBlockTransferGPU) { - FlushBeforeCopy(); - const u8 *srcBase = Memory::GetPointerUnchecked(srcBasePtr) + (srcX + srcY * srcStride) * bpp; - int dstBpp = dstBuffer->format == GE_FORMAT_8888 ? 4 : 2; - float dstXFactor = (float)bpp / dstBpp; - if (dstWidth > dstBuffer->width || dstHeight > dstBuffer->height) { - // The buffer isn't big enough, and we have a clear hint of size. Resize. - // This happens in Valkyrie Profile when uploading video at the ending. - ResizeFramebufFBO(dstBuffer, dstWidth, dstHeight, false, true); - // Make sure we don't flop back and forth. - dstBuffer->newWidth = std::max(dstWidth, (int)dstBuffer->width); - dstBuffer->newHeight = std::max(dstHeight, (int)dstBuffer->height); - dstBuffer->lastFrameNewSize = gpuStats.numFlips; - // Resizing may change the viewport/etc. - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE); - } - DrawPixels(dstBuffer, static_cast(dstX * dstXFactor), dstY, srcBase, dstBuffer->format, static_cast(srcStride * dstXFactor), static_cast(dstWidth * dstXFactor), dstHeight); - SetColorUpdated(dstBuffer, skipDrawReason); - RebindFramebuffer(); + FlushBeforeCopy(); + const u8 *srcBase = Memory::GetPointerUnchecked(srcBasePtr) + (srcX + srcY * srcStride) * bpp; + int dstBpp = dstBuffer->format == GE_FORMAT_8888 ? 4 : 2; + float dstXFactor = (float)bpp / dstBpp; + if (dstWidth > dstBuffer->width || dstHeight > dstBuffer->height) { + // The buffer isn't big enough, and we have a clear hint of size. Resize. + // This happens in Valkyrie Profile when uploading video at the ending. + ResizeFramebufFBO(dstBuffer, dstWidth, dstHeight, false, true); + // Make sure we don't flop back and forth. + dstBuffer->newWidth = std::max(dstWidth, (int)dstBuffer->width); + dstBuffer->newHeight = std::max(dstHeight, (int)dstBuffer->height); + dstBuffer->lastFrameNewSize = gpuStats.numFlips; + // Resizing may change the viewport/etc. + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE); } + DrawPixels(dstBuffer, static_cast(dstX * dstXFactor), dstY, srcBase, dstBuffer->format, static_cast(srcStride * dstXFactor), static_cast(dstWidth * dstXFactor), dstHeight); + SetColorUpdated(dstBuffer, skipDrawReason); + RebindFramebuffer(); } } } diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index ef11d91974..4ad5ddfbf6 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -2717,9 +2717,8 @@ void GPUCommon::InvalidateCache(u32 addr, int size, GPUInvalidationType type) { textureCache_->InvalidateAll(type); if (type != GPU_INVALIDATE_ALL && framebufferManager_->MayIntersectFramebuffer(addr)) { - // If we're doing block transfers, we shouldn't need this, and it'll only confuse us. // Vempire invalidates (with writeback) after drawing, but before blitting. - if (!g_Config.bBlockTransferGPU || type == GPU_INVALIDATE_SAFE) { + if (type == GPU_INVALIDATE_SAFE) { framebufferManager_->UpdateFromMemory(addr, size, type == GPU_INVALIDATE_SAFE); } } From 5aed2a2cee49e47881145484b950cb2c711b039a Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 8 Feb 2019 15:02:31 +0100 Subject: [PATCH 335/347] Gate fewer effects behind "Disable slow framebuffer effects". --- GPU/Common/DrawEngineCommon.cpp | 8 +++----- GPU/Common/FramebufferCommon.cpp | 4 ++-- GPU/D3D11/FramebufferManagerD3D11.cpp | 5 +---- GPU/Directx9/FramebufferDX9.cpp | 6 +----- GPU/GLES/FramebufferManagerGLES.cpp | 6 +----- GPU/Vulkan/FramebufferVulkan.cpp | 6 +----- 6 files changed, 9 insertions(+), 26 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 9fe14adfca..8b6638ed74 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -731,11 +731,9 @@ void DrawEngineCommon::SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, } if (prim == GE_PRIM_RECTANGLES && (gstate.getTextureAddress(0) & 0x3FFFFFFF) == (gstate.getFrameBufAddress() & 0x3FFFFFFF)) { - // Rendertarget == texture? - if (!g_Config.bDisableSlowFramebufEffects) { - gstate_c.Dirty(DIRTY_TEXTURE_PARAMS); - DispatchFlush(); - } + // Rendertarget == texture? Shouldn't happen. Still, try some mitigations. + gstate_c.Dirty(DIRTY_TEXTURE_PARAMS); + DispatchFlush(); } } diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index 7468b2258f..01faf039b1 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -588,7 +588,7 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe shaderManager_->DirtyLastShader(); // Copy depth pixel value from the read framebuffer to the draw framebuffer - if (prevVfb && !g_Config.bDisableSlowFramebufEffects) { + if (prevVfb) { bool hasNewerDepth = prevVfb->last_frame_depth_render != 0 && prevVfb->last_frame_depth_render >= vfb->last_frame_depth_updated; if (!prevVfb->fbo || !vfb->fbo || !useBufferedRendering_ || !hasNewerDepth || isClearingDepth) { // If depth wasn't updated, then we're at least "two degrees" away from the data. @@ -1177,7 +1177,7 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }); // GLES resets the blend state on clears. gstate_c.Dirty(DIRTY_BLEND_STATE); - if (!skipCopy && !g_Config.bDisableSlowFramebufEffects) { + if (!skipCopy) { BlitFramebuffer(vfb, 0, 0, &old, 0, 0, std::min((u16)oldWidth, std::min(vfb->bufferWidth, vfb->width)), std::min((u16)oldHeight, std::min(vfb->height, vfb->bufferHeight)), 0); } } diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index 69b07bb36e..785db51eb5 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -512,9 +512,6 @@ static void CopyPixelDepthOnly(u32 *dstp, const u32 *srcp, size_t c) { } void FramebufferManagerD3D11::BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) { - if (g_Config.bDisableSlowFramebufEffects) { - return; - } bool matchingDepthBuffer = src->z_address == dst->z_address && src->z_stride != 0 && dst->z_stride != 0; bool matchingSize = src->width == dst->width && src->height == dst->height; bool matchingRenderSize = src->renderWidth == dst->renderWidth && src->renderHeight == dst->renderHeight; @@ -537,7 +534,7 @@ void FramebufferManagerD3D11::BindFramebufferAsColorTexture(int stage, VirtualFr // currentRenderVfb_ will always be set when this is called, except from the GE debugger. // Let's just not bother with the copy in that case. bool skipCopy = (flags & BINDFBCOLOR_MAY_COPY) == 0; - if (GPUStepping::IsStepping() || g_Config.bDisableSlowFramebufEffects) { + if (GPUStepping::IsStepping()) { skipCopy = true; } // Currently rendering to this framebuffer. Need to make a copy. diff --git a/GPU/Directx9/FramebufferDX9.cpp b/GPU/Directx9/FramebufferDX9.cpp index e6f215168e..f364685813 100644 --- a/GPU/Directx9/FramebufferDX9.cpp +++ b/GPU/Directx9/FramebufferDX9.cpp @@ -394,10 +394,6 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { } void FramebufferManagerDX9::BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) { - if (g_Config.bDisableSlowFramebufEffects) { - return; - } - bool matchingDepthBuffer = src->z_address == dst->z_address && src->z_stride != 0 && dst->z_stride != 0; bool matchingSize = src->width == dst->width && src->height == dst->height; if (matchingDepthBuffer && matchingSize) { @@ -450,7 +446,7 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { // currentRenderVfb_ will always be set when this is called, except from the GE debugger. // Let's just not bother with the copy in that case. bool skipCopy = (flags & BINDFBCOLOR_MAY_COPY) == 0; - if (GPUStepping::IsStepping() || g_Config.bDisableSlowFramebufEffects) { + if (GPUStepping::IsStepping()) { skipCopy = true; } if (!skipCopy && framebuffer == currentRenderVfb_) { diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 57c92fe7f9..b34c4b5572 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -486,10 +486,6 @@ void FramebufferManagerGLES::ReformatFramebufferFrom(VirtualFramebuffer *vfb, GE } void FramebufferManagerGLES::BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) { - if (g_Config.bDisableSlowFramebufEffects) { - return; - } - bool matchingDepthBuffer = src->z_address == dst->z_address && src->z_stride != 0 && dst->z_stride != 0; bool matchingSize = src->width == dst->width && src->height == dst->height; @@ -516,7 +512,7 @@ void FramebufferManagerGLES::BindFramebufferAsColorTexture(int stage, VirtualFra // currentRenderVfb_ will always be set when this is called, except from the GE debugger. // Let's just not bother with the copy in that case. bool skipCopy = (flags & BINDFBCOLOR_MAY_COPY) == 0; - if (GPUStepping::IsStepping() || g_Config.bDisableSlowFramebufEffects) { + if (GPUStepping::IsStepping()) { skipCopy = true; } if (!skipCopy && framebuffer == currentRenderVfb_) { diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp index 4ec89a66e1..2e87b65390 100644 --- a/GPU/Vulkan/FramebufferVulkan.cpp +++ b/GPU/Vulkan/FramebufferVulkan.cpp @@ -379,10 +379,6 @@ void FramebufferManagerVulkan::ReformatFramebufferFrom(VirtualFramebuffer *vfb, // Except for a missing rebind and silly scissor enables, identical copy of the same function in GPU_GLES - tricky parts are in thin3d. void FramebufferManagerVulkan::BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) { - if (g_Config.bDisableSlowFramebufEffects) { - return; - } - bool matchingDepthBuffer = src->z_address == dst->z_address && src->z_stride != 0 && dst->z_stride != 0; bool matchingSize = src->width == dst->width && src->height == dst->height; bool matchingRenderSize = src->renderWidth == dst->renderWidth && src->renderHeight == dst->renderHeight; @@ -408,7 +404,7 @@ VkImageView FramebufferManagerVulkan::BindFramebufferAsColorTexture(int stage, V // currentRenderVfb_ will always be set when this is called, except from the GE debugger. // Let's just not bother with the copy in that case. bool skipCopy = (flags & BINDFBCOLOR_MAY_COPY) == 0; - if (GPUStepping::IsStepping() || g_Config.bDisableSlowFramebufEffects) { + if (GPUStepping::IsStepping()) { skipCopy = true; } // Currently rendering to this framebuffer. Need to make a copy. From 23dd47ab7732c9c32d5321c6c003b9a1272a0bdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 9 Feb 2019 11:22:41 +0100 Subject: [PATCH 336/347] Make "Show FPS Counter" in the Windows menu actually show fps, not just speed --- .gitignore | 2 +- Windows/MainWindowMenu.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index b0bc906ca8..e391987ab1 100644 --- a/.gitignore +++ b/.gitignore @@ -65,7 +65,7 @@ desc.txt Logs Memstick -memstick +memstick* Cheats /git-version.cpp diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index 130a35fd69..2bb5f9be4b 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -947,7 +947,7 @@ namespace MainWindow { break; case ID_OPTIONS_SHOWFPS: - g_Config.iShowFPSCounter = !g_Config.iShowFPSCounter; + g_Config.iShowFPSCounter = g_Config.iShowFPSCounter ? 0 : 3; // 3 = both speed and FPS break; case ID_OPTIONS_TEXTUREFILTERING_AUTO: setTexFiltering(TEX_FILTER_AUTO); break; From ecf62a03adc909d001c3fc6de7b887c998969bc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 9 Feb 2019 09:56:59 +0100 Subject: [PATCH 337/347] Naruto 3: Probably a better fix for the video hang issue. Fixes #9591, replaces #11772 --- .gitignore | 2 +- Core/HLE/sceMpeg.cpp | 2 +- Core/HLE/sceMpeg.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index b0bc906ca8..e391987ab1 100644 --- a/.gitignore +++ b/.gitignore @@ -65,7 +65,7 @@ desc.txt Logs Memstick -memstick +memstick* Cheats /git-version.cpp diff --git a/Core/HLE/sceMpeg.cpp b/Core/HLE/sceMpeg.cpp index e6bd1e0680..a76a216fa4 100644 --- a/Core/HLE/sceMpeg.cpp +++ b/Core/HLE/sceMpeg.cpp @@ -1599,7 +1599,6 @@ static int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr) Memory::Write_U32(1, attrAddr); } - DEBUG_LOG(ME, "%x=sceMpegGetAvcAu(%08x, %08x, %08x, %08x)", result, mpeg, streamId, auAddr, attrAddr); // TODO: sceMpegGetAvcAu seems to modify esSize, and delay when it's > 1000 or something. // There's definitely more to it, but ultimately it seems games should expect it to delay randomly. @@ -1664,6 +1663,7 @@ static int sceMpegGetAtracAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr) // Instead, let's abuse it to keep track of the stream number. if (streamInfo != ctx->streamMap.end()) { atracAu.esBuffer = streamInfo->second.num; + ctx->mediaengine->setAudioStream(streamInfo->second.num); } int result = 0; diff --git a/Core/HLE/sceMpeg.h b/Core/HLE/sceMpeg.h index ca310bf409..bf5b0dfcce 100644 --- a/Core/HLE/sceMpeg.h +++ b/Core/HLE/sceMpeg.h @@ -49,7 +49,7 @@ static const int PSMF_AUDIO_STREAM_ID = 0xBD; struct SceMpegAu { s64_le pts; // presentation time stamp s64_le dts; // decode time stamp - u32_le esBuffer; + u32_le esBuffer; // WARNING: We abuse this to keep track of the stream number! u32_le esSize; void read(u32 addr); From 259cb0f128223d860696c17b0d11557ac3a698e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 10 Feb 2019 15:55:00 +0100 Subject: [PATCH 338/347] Fix issue where too long filenames could wreck the Install Zip dialog layout. Well, technically just shortens the path to avoid the issue. --- Common/StringUtils.cpp | 18 +++++++++++++++++- Common/StringUtils.h | 2 ++ UI/InstallZipScreen.cpp | 4 +++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Common/StringUtils.cpp b/Common/StringUtils.cpp index 1946d0df92..c1289720b0 100644 --- a/Common/StringUtils.cpp +++ b/Common/StringUtils.cpp @@ -95,4 +95,20 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _ *_pExtension = full_path.substr(fname_end); return true; -} \ No newline at end of file +} + +std::string GetFilenameFromPath(std::string full_path) { + size_t pos; +#ifdef _WIN32 + pos = full_path.rfind('\\'); + if (pos != std::string::npos) { + return full_path.substr(pos + 1); + } +#endif + pos = full_path.rfind('/'); + if (pos != std::string::npos) { + return full_path.substr(pos + 1); + } + // No directory components, just return the full path. + return full_path; +} diff --git a/Common/StringUtils.h b/Common/StringUtils.h index 5b53423a03..58d433697c 100644 --- a/Common/StringUtils.h +++ b/Common/StringUtils.h @@ -45,3 +45,5 @@ inline void CharArrayFromFormat(char (& out)[Count], const char* format, ...) // "C:/Windows/winhelp.exe" to "C:/Windows/", "winhelp", ".exe" bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension); + +std::string GetFilenameFromPath(std::string full_path); diff --git a/UI/InstallZipScreen.cpp b/UI/InstallZipScreen.cpp index 353a71878f..943d0c9908 100644 --- a/UI/InstallZipScreen.cpp +++ b/UI/InstallZipScreen.cpp @@ -23,6 +23,7 @@ #include "UI/ui_atlas.h" #include "file/file_util.h" +#include "Common/StringUtils.h" #include "Core/Util/GameManager.h" #include "UI/InstallZipScreen.h" #include "UI/MainScreen.h" @@ -43,8 +44,9 @@ void InstallZipScreen::CreateViews() { ViewGroup *leftColumn = new AnchorLayout(new LinearLayoutParams(1.0f)); root_->Add(leftColumn); + std::string shortFilename = GetFilenameFromPath(zipPath_); leftColumn->Add(new TextView(iz->T("Install game from ZIP file?"), ALIGN_LEFT, false, new AnchorLayoutParams(10, 10, NONE, NONE))); - leftColumn->Add(new TextView(zipPath_, ALIGN_LEFT, false, new AnchorLayoutParams(10, 60, NONE, NONE))); + leftColumn->Add(new TextView(shortFilename, ALIGN_LEFT, false, new AnchorLayoutParams(10, 60, NONE, NONE))); doneView_ = leftColumn->Add(new TextView("", new AnchorLayoutParams(10, 120, NONE, NONE))); progressBar_ = leftColumn->Add(new ProgressBar(new AnchorLayoutParams(10, 200, 200, NONE))); From b955ec70c94cfc2a77c04023c4e9a36a50cb5368 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 10 Feb 2019 09:58:01 -0800 Subject: [PATCH 339/347] GPU: Correct depth clamp range in range cull. It was just wrong before, causing wrong culling when using a non-standard viewport scale/center for depth. Fixes #11701, fixes #11781. --- GPU/Common/GPUStateUtils.cpp | 18 +++++++----------- GPU/Common/GPUStateUtils.h | 2 +- GPU/Common/ShaderUniforms.cpp | 24 +++++++++++++++++++++--- GPU/Common/SoftwareTransformCommon.cpp | 2 +- 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 515caa74d9..92b1d5f974 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -520,7 +520,7 @@ float DepthSliceFactor() { } // This is used for float values which might not be integers, but are in the integer scale of 65535. -static float ToScaledDepthFromInteger(float z) { +float ToScaledDepthFromIntegerScale(float z) { if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { return z * (1.0f / 65535.0f); } @@ -536,10 +536,6 @@ static float ToScaledDepthFromInteger(float z) { } } -float ToScaledDepth(u16 z) { - return ToScaledDepthFromInteger((float)(int)z); -} - float FromScaledDepth(float z) { if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { return z * 65535.0f; @@ -605,8 +601,8 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo out.viewportY = renderY + displayOffsetY; out.viewportW = curRTWidth * renderWidthFactor; out.viewportH = curRTHeight * renderHeightFactor; - out.depthRangeMin = ToScaledDepthFromInteger(0); - out.depthRangeMax = ToScaledDepthFromInteger(65536); + out.depthRangeMin = ToScaledDepthFromIntegerScale(0); + out.depthRangeMax = ToScaledDepthFromIntegerScale(65536); } else { // These we can turn into a glViewport call, offset by offsetX and offsetY. Math after. float vpXScale = gstate.getViewportXScale(); @@ -715,11 +711,11 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { zScale = 1.0f; zOffset = 0.0f; - out.depthRangeMin = ToScaledDepthFromInteger(vpZCenter - vpZScale); - out.depthRangeMax = ToScaledDepthFromInteger(vpZCenter + vpZScale); + out.depthRangeMin = ToScaledDepthFromIntegerScale(vpZCenter - vpZScale); + out.depthRangeMax = ToScaledDepthFromIntegerScale(vpZCenter + vpZScale); } else { - out.depthRangeMin = ToScaledDepthFromInteger(minz); - out.depthRangeMax = ToScaledDepthFromInteger(maxz); + out.depthRangeMin = ToScaledDepthFromIntegerScale(minz); + out.depthRangeMax = ToScaledDepthFromIntegerScale(maxz); } // OpenGL will clamp these for us anyway, and Direct3D will error if not clamped. diff --git a/GPU/Common/GPUStateUtils.h b/GPU/Common/GPUStateUtils.h index 957c6c42b3..6cf95f84b7 100644 --- a/GPU/Common/GPUStateUtils.h +++ b/GPU/Common/GPUStateUtils.h @@ -72,7 +72,7 @@ struct ViewportAndScissor { bool dirtyDepth; }; void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, float renderHeight, int bufferWidth, int bufferHeight, ViewportAndScissor &out); -float ToScaledDepth(u16 z); +float ToScaledDepthFromIntegerScale(float z); float FromScaledDepth(float z); float DepthSliceFactor(); diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index 26bdbd7c17..f8fb3456e9 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -42,9 +42,27 @@ void CalcCullRange(float minValues[4], float maxValues[4], bool flipViewport, bo return (pspViewport - gstate_c.vpYOffset) * heightScale; }; auto reverseViewportZ = [hasNegZ](float z) { - float pspViewport = (z - gstate.getViewportZCenter()) * (1.0f / gstate.getViewportZScale()); - // Differs from GLES: depth is 0 to 1, not -1 to 1. - float realViewport = (pspViewport - gstate_c.vpZOffset) * gstate_c.vpDepthScale; + float vpZScale = gstate.getViewportZScale(); + float vpZCenter = gstate.getViewportZCenter(); + + float scale, center; + if (gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { + // These are just the reverse of the formulas in GPUStateUtils. + float halfActualZRange = vpZScale * (1.0f / gstate_c.vpDepthScale); + float minz = -((gstate_c.vpZOffset * halfActualZRange) - vpZCenter) - halfActualZRange; + + // In accurate depth mode, we're comparing against a value scaled to (minz, maxz). + // And minz might be very negative, (e.g. if we're clamping in that direction.) + scale = halfActualZRange; + center = minz + halfActualZRange; + } else { + // In old-style depth mode, we're comparing against a value scaled to viewport. + // (and possibly incorrectly clipped against it.) + scale = vpZScale; + center = vpZCenter; + } + + float realViewport = (z - center) * (1.0f / scale); return hasNegZ ? realViewport : (realViewport * 0.5f + 0.5f); }; auto sortPair = [](float a, float b) { diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index 66909cb2d0..4a77731f00 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -460,7 +460,7 @@ void SoftwareTransform( if (params->allowSeparateAlphaClear || (alphaMatchesColor && depthMatchesStencil)) { result->color = transformed[1].color0_32; // Need to rescale from a [0, 1] float. This is the final transformed value. - result->depth = ToScaledDepth((s16)(int)(transformed[1].z * 65535.0f)); + result->depth = ToScaledDepthFromIntegerScale((int)(transformed[1].z * 65535.0f)); result->action = SW_CLEAR; gpuStats.numClears++; return; From 3e1197f5f31409c4e13d6c8bfc2f034f84ef4bc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 10 Feb 2019 20:13:06 +0100 Subject: [PATCH 340/347] Android: Add some logging --- android/jni/app-android.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 0a99555895..2180522782 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -193,6 +193,7 @@ static void EmuThreadFunc() { while (emuThreadState != (int)EmuThreadState::QUIT_REQUESTED) { UpdateRunLoopAndroid(env); } + ILOG("QUIT_REQUESTED found, left loop. Setting state to STOPPED."); emuThreadState = (int)EmuThreadState::STOPPED; NativeShutdownGraphics(); @@ -213,8 +214,8 @@ static void EmuThreadStart() { // Call EmuThreadStop first, then keep running the GPU (or eat commands) // as long as emuThreadState isn't STOPPED and/or there are still things queued up. // Only after that, call EmuThreadJoin. -static void EmuThreadStop() { - ILOG("EmuThreadStop - stopping..."); +static void EmuThreadStop(const char *caller) { + ILOG("EmuThreadStop - stopping (%s)...", caller); emuThreadState = (int)EmuThreadState::QUIT_REQUESTED; } @@ -527,15 +528,16 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_pause(JNIEnv *, jclass) { extern "C" void Java_org_ppsspp_ppsspp_NativeApp_shutdown(JNIEnv *, jclass) { if (renderer_inited && useCPUThread && graphicsContext) { // Only used in Java EGL path. - EmuThreadStop(); + EmuThreadStop("shutdown"); + ILOG("BeginAndroidShutdown"); graphicsContext->BeginAndroidShutdown(); // Skipping GL calls, the old context is gone. while (graphicsContext->ThreadFrame()) { ILOG("graphicsContext->ThreadFrame executed to clear buffers"); - continue; } ILOG("Joining emuthread"); EmuThreadJoin(); + ILOG("Joined emuthread"); graphicsContext->ThreadEnd(); graphicsContext->ShutdownFromRenderThread(); @@ -566,15 +568,17 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env, // We should be running on the render thread here. std::string errorMessage; if (renderer_inited) { - // Would be really nice if we could get something on the GL thread immediately when shutting down... + // Would be really nice if we could get something on the GL thread immediately when shutting down. ILOG("NativeApp.displayInit() restoring"); if (useCPUThread) { - EmuThreadStop(); + EmuThreadStop("displayInit"); graphicsContext->BeginAndroidShutdown(); + ILOG("BeginAndroidShutdown. Looping until emu thread done..."); // Skipping GL calls here because the old context is lost. while (graphicsContext->ThreadFrame()) { continue; } + ILOG("Joining emu thread"); EmuThreadJoin(); } else { NativeShutdownGraphics(); @@ -1018,7 +1022,7 @@ retry: ILOG("Leaving EGL/Vulkan render loop."); if (useCPUThread) { - EmuThreadStop(); + EmuThreadStop("exitrenderloop"); while (graphicsContext->ThreadFrame()) { continue; } From c509650bec3ff15094378d026741352f500d4e0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 10 Feb 2019 20:13:39 +0100 Subject: [PATCH 341/347] OpenGL: Disable the mapped buffer strategy for Adreno (Qualcomm). It's a race during shutdown between the EmuThread writing commands, and the render thread which just lost the buffer. --- ext/native/thin3d/GLRenderManager.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/ext/native/thin3d/GLRenderManager.cpp b/ext/native/thin3d/GLRenderManager.cpp index b7585b7a03..8affe78c8f 100644 --- a/ext/native/thin3d/GLRenderManager.cpp +++ b/ext/native/thin3d/GLRenderManager.cpp @@ -112,9 +112,14 @@ void GLRenderManager::ThreadStart(Draw::DrawContext *draw) { bufferStrategy_ = GLBufferStrategy::FRAME_UNMAP; break; - case GPU_VENDOR_QUALCOMM: - bufferStrategy_ = GLBufferStrategy::FLUSH_INVALIDATE_UNMAP; - break; + // Temporarily disabled because it doesn't work with task switching on Android. + // The mapped buffer seems to just be pulled out like a rug from under us, crashing + // as soon as any write happens, which can happen during shutdown since we write from the + // Emu thread which may not yet have shut down. There may be solutions to this, but for now, + // disable this strategy to avoid crashing. + //case GPU_VENDOR_QUALCOMM: + // bufferStrategy_ = GLBufferStrategy::FLUSH_INVALIDATE_UNMAP; + // break; default: bufferStrategy_ = GLBufferStrategy::SUBDATA; From e96360dedcdd6448a8fbbc2aa9c19cd990ac0503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 10 Feb 2019 20:30:35 +0100 Subject: [PATCH 342/347] Android: Update gradle to 3.3.1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e5bb841343..62ec80d1ce 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.3.0' + classpath 'com.android.tools.build:gradle:3.3.1' } } From 957c3d5b899d5a775fb2da1f1f5bd7bcf2881dc7 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 10 Feb 2019 11:36:23 -0800 Subject: [PATCH 343/347] GLES: Disable range culling on VideoCore/Vivante. Was only disabled before on Vivante GL3/GLES3 devices. --- ext/native/thin3d/thin3d_gl.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index 872c169aff..a94b318bbb 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -560,6 +560,7 @@ OpenGLContext::OpenGLContext() { // Don't use this extension on sub 3.0 OpenGL versions as it does not seem reliable. bugs_.Infest(Bugs::DUAL_SOURCE_BLENDING_BROKEN); } else if (caps_.vendor == GPUVendor::VENDOR_INTEL) { + // Note: this is for Intel drivers with GL3+. // Also on Intel, see https://github.com/hrydgard/ppsspp/issues/10117 // TODO: Remove entirely sometime reasonably far in driver years after 2015. const std::string ver = GetInfoString(Draw::InfoField::APIVERSION); @@ -569,7 +570,9 @@ OpenGLContext::OpenGLContext() { bugs_.Infest(Bugs::DUAL_SOURCE_BLENDING_BROKEN); } } - } else if (caps_.vendor == GPUVendor::VENDOR_VIVANTE) { + } + + if (caps_.vendor == GPUVendor::VENDOR_VIVANTE || caps_.vendor == GPUVendor::VENDOR_BROADCOM) { bugs_.Infest(Bugs::BROKEN_NAN_IN_CONDITIONAL); } From 906d2dff7beb3752c108cc9e63fb875a6284093f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 10 Feb 2019 22:40:34 +0100 Subject: [PATCH 344/347] Lie about success of loading flash0:/kd/audiocodec_260.prx, just like we already lie about audiocodec.prx. Fixes #11733 --- Core/HLE/sceKernelModule.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index fe5cd6acf5..55366beef4 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -84,13 +84,14 @@ enum { }; // This is a workaround for misbehaving homebrew (like TBL's Suicide Barbie (Final)). -static const char *lieAboutSuccessModules[] = { +static const char * const lieAboutSuccessModules[] = { "flash0:/kd/audiocodec.prx", + "flash0:/kd/audiocodec_260.prx", "flash0:/kd/libatrac3plus.prx", "disc0:/PSP_GAME/SYSDIR/UPDATE/EBOOT.BIN", }; -static const char *blacklistedModules[] = { +static const char * const blacklistedModules[] = { "sceATRAC3plus_Library", "sceFont_Library", "SceFont_Library", From 82fec6510a7b2c3a8c322ded7ed6a7d0d381f359 Mon Sep 17 00:00:00 2001 From: 6alileo <42245908+6alileo@users.noreply.github.com> Date: Sun, 10 Feb 2019 16:40:02 -0800 Subject: [PATCH 345/347] add controllers --- assets/gamecontrollerdb.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/assets/gamecontrollerdb.txt b/assets/gamecontrollerdb.txt index fbf1009a11..885bb1c744 100644 --- a/assets/gamecontrollerdb.txt +++ b/assets/gamecontrollerdb.txt @@ -189,3 +189,5 @@ bd1200000000000015d0000000000000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,b 050000004c050000cc09000001000000,Sony DualShock 4 V2 BT,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux, 03000000bc2000006412000011010000,BETOP CONTROLLER,a:b2,b:b1,y:b0,x:b3,start:b9,guide:b30,back:b8,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux, 05000000c82d00000161000000010000,8Bitdo SN30 Pro,platform:Linux,a:b1,b:b0,x:b4,y:b3,back:b10,guide:b2,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4, +03000000380700008532000010010000,MadCatz Madcatz Fightpad,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,lefttrigger:b5,righttrigger:b7, +030000000d0f0000ee00000011010000,HORI CO.,LTD. HORIPAD mini4,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, From c9819ab5e76ca9e9ae54e1f2a0751a51cf505a4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 11 Feb 2019 23:10:55 +0100 Subject: [PATCH 346/347] Update pspautotest submodule --- pspautotests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pspautotests b/pspautotests index d02ba74070..98b83d2cb0 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit d02ba7407050f445edf9e908374ad4bf3b2f237b +Subproject commit 98b83d2cb06e78c6e24f287b24a89a0ef87ac53b From cbf735e2e2e13038cc75f6545d64fd1820bac0ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 12 Feb 2019 20:18:52 +0100 Subject: [PATCH 347/347] CwCheat warning fixes --- UI/CwCheatScreen.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/UI/CwCheatScreen.cpp b/UI/CwCheatScreen.cpp index 3aabf8571e..7c6de132f1 100644 --- a/UI/CwCheatScreen.cpp +++ b/UI/CwCheatScreen.cpp @@ -229,7 +229,7 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) { continue; } loop:; - } while (fs.good() && (line[0] == '_' && line[1] != 'S') || line[0] == '/' || line[0] == '#'); + } while (fs.good() && ((line[0] == '_' && line[1] != 'S') || line[0] == '/' || line[0] == '#')); finished = true; } if (finished == true) @@ -243,7 +243,7 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) { File::OpenCPPFile(fs, activeCheatFile, std::ios::out | std::ios::app); auto it = title.begin(); - if ((title2[0] == '_' && title2[1] != 'S') || title2[0] == '/' || title2[0] == '#' && it != title.end() && (++it) != title.end()) { + if (((title2[0] == '_' && title2[1] != 'S') || title2[0] == '/' || title2[0] == '#') && it != title.end() && (++it) != title.end()) { fs << title[0] << "\n" << title[1]; }