From 868bbb8ebe8c92246dd77692c86fad0f84057969 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 10 Apr 2016 12:59:06 -0700 Subject: [PATCH 1/3] Advance vertex/index pointers on bezier submit. Just like other primitives. --- GPU/Common/DrawEngineCommon.h | 2 +- GPU/Common/SplineCommon.cpp | 20 ++++++++++++-------- GPU/Directx9/GPU_DX9.cpp | 16 +++++++++++++++- GPU/GLES/GPU_GLES.cpp | 16 +++++++++++++++- GPU/Vulkan/GPU_Vulkan.cpp | 16 +++++++++++++++- 5 files changed, 58 insertions(+), 12 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 4d862698f6..8004e8676d 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -52,7 +52,7 @@ public: virtual void DispatchSubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int *bytesRead) = 0; 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); - 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); + 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); std::vector DebugGetVertexLoaderIDs(); std::string DebugGetVertexLoaderString(std::string id, DebugShaderStringType stringType); diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 083f938608..170c426344 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -874,16 +874,11 @@ 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) { +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; - u16 index_lower_bound = 0; u16 index_upper_bound = count_u * count_v - 1; bool indices_16bit = (vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_16BIT; @@ -894,6 +889,15 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi if (indices) GetIndexBounds(indices, count_u*count_v, vertType, &index_lower_bound, &index_upper_bound); + 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 *)(decoded + 65536 * 12); @@ -967,8 +971,8 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi gstate_c.uv.vOff = 0; } - int bytesRead; - DispatchSubmitPrim(splineBuffer, quadIndices_, primType[prim_type], count, vertTypeWithIndex16, &bytesRead); + int generatedBytesRead; + DispatchSubmitPrim(splineBuffer, quadIndices_, primType[prim_type], count, vertTypeWithIndex16, &generatedBytesRead); DispatchFlush(); diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index b154444650..86928f1023 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -883,7 +883,21 @@ void GPU_DX9::Execute_Bezier(u32 op, u32 diff) { int bz_vcount = (op >> 8) & 0xFF; bool computeNormals = gstate.isLightingEnabled(); bool patchFacing = gstate.patchfacing & 1; - drawEngine_.SubmitBezier(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), bz_ucount, bz_vcount, patchPrim, computeNormals, patchFacing, gstate.vertType); + int bytesRead = 0; + drawEngine_.SubmitBezier(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), bz_ucount, bz_vcount, patchPrim, computeNormals, patchFacing, gstate.vertType, &bytesRead); + + // After drawing, we advance pointers - see SubmitPrim which does the same. + int count = bz_ucount * bz_vcount; + if ((gstate.vertType & GE_VTYPE_IDX_MASK) != 0) { + int indexSize = 1; + if ((gstate.vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_16BIT) + indexSize = 2; + else if ((gstate.vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_32BIT) + indexSize = 4; + gstate_c.indexAddr += count * indexSize; + } else { + gstate_c.vertexAddr += bytesRead; + } } void GPU_DX9::Execute_Spline(u32 op, u32 diff) { diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index bd51831588..a84d80568d 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -1076,7 +1076,21 @@ void GPU_GLES::Execute_Bezier(u32 op, u32 diff) { int bz_vcount = (op >> 8) & 0xFF; bool computeNormals = gstate.isLightingEnabled(); bool patchFacing = gstate.patchfacing & 1; - drawEngine_.SubmitBezier(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), bz_ucount, bz_vcount, patchPrim, computeNormals, patchFacing, gstate.vertType); + int bytesRead = 0; + drawEngine_.SubmitBezier(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), bz_ucount, bz_vcount, patchPrim, computeNormals, patchFacing, gstate.vertType, &bytesRead); + + // After drawing, we advance pointers - see SubmitPrim which does the same. + int count = bz_ucount * bz_vcount; + if ((gstate.vertType & GE_VTYPE_IDX_MASK) != 0) { + int indexSize = 1; + if ((gstate.vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_16BIT) + indexSize = 2; + else if ((gstate.vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_32BIT) + indexSize = 4; + gstate_c.indexAddr += count * indexSize; + } else { + gstate_c.vertexAddr += bytesRead; + } } void GPU_GLES::Execute_Spline(u32 op, u32 diff) { diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index d12ef79340..36312b4a4e 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -933,7 +933,21 @@ void GPU_Vulkan::Execute_Bezier(u32 op, u32 diff) { int bz_vcount = (op >> 8) & 0xFF; bool computeNormals = gstate.isLightingEnabled(); bool patchFacing = gstate.patchfacing & 1; - drawEngine_.SubmitBezier(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), bz_ucount, bz_vcount, patchPrim, computeNormals, patchFacing, gstate.vertType); + int bytesRead = 0; + drawEngine_.SubmitBezier(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), bz_ucount, bz_vcount, patchPrim, computeNormals, patchFacing, gstate.vertType, &bytesRead); + + // After drawing, we advance pointers - see SubmitPrim which does the same. + int count = bz_ucount * bz_vcount; + if ((gstate.vertType & GE_VTYPE_IDX_MASK) != 0) { + int indexSize = 1; + if ((gstate.vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_16BIT) + indexSize = 2; + else if ((gstate.vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_32BIT) + indexSize = 4; + gstate_c.indexAddr += count * indexSize; + } else { + gstate_c.vertexAddr += bytesRead; + } } void GPU_Vulkan::Execute_Spline(u32 op, u32 diff) { From e95b2cf0d5920a0df2d28d27800d10c47266c9f2 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 10 Apr 2016 13:07:08 -0700 Subject: [PATCH 2/3] Reduce some repetitive code. --- GPU/Directx9/GPU_DX9.cpp | 22 ++-------------------- GPU/GLES/GPU_GLES.cpp | 22 ++-------------------- GPU/GPUCommon.cpp | 13 +++++++++++++ GPU/GPUCommon.h | 2 ++ GPU/Software/SoftGpu.cpp | 11 +---------- GPU/Vulkan/GPU_Vulkan.cpp | 22 ++-------------------- 6 files changed, 22 insertions(+), 70 deletions(-) diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index 86928f1023..be499769ca 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -836,16 +836,7 @@ void GPU_DX9::Execute_Prim(u32 op, u32 diff) { // After drawing, we advance the vertexAddr (when non indexed) or indexAddr (when indexed). // Some games rely on this, they don't bother reloading VADDR and IADDR. // The VADDR/IADDR registers are NOT updated. - if (inds) { - int indexSize = 1; - if ((vertexType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_16BIT) - indexSize = 2; - else if ((vertexType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_32BIT) - indexSize = 4; - gstate_c.indexAddr += count * indexSize; - } else { - gstate_c.vertexAddr += bytesRead; - } + AdvanceVerts(vertexType, count, bytesRead); } void GPU_DX9::Execute_Bezier(u32 op, u32 diff) { @@ -888,16 +879,7 @@ void GPU_DX9::Execute_Bezier(u32 op, u32 diff) { // After drawing, we advance pointers - see SubmitPrim which does the same. int count = bz_ucount * bz_vcount; - if ((gstate.vertType & GE_VTYPE_IDX_MASK) != 0) { - int indexSize = 1; - if ((gstate.vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_16BIT) - indexSize = 2; - else if ((gstate.vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_32BIT) - indexSize = 4; - gstate_c.indexAddr += count * indexSize; - } else { - gstate_c.vertexAddr += bytesRead; - } + AdvanceVerts(gstate.vertType, count, bytesRead); } void GPU_DX9::Execute_Spline(u32 op, u32 diff) { diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index a84d80568d..e70db2434b 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -1005,16 +1005,7 @@ void GPU_GLES::Execute_Prim(u32 op, u32 diff) { // After drawing, we advance the vertexAddr (when non indexed) or indexAddr (when indexed). // Some games rely on this, they don't bother reloading VADDR and IADDR. // The VADDR/IADDR registers are NOT updated. - if (inds) { - int indexSize = 1; - if ((gstate.vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_16BIT) - indexSize = 2; - else if ((gstate.vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_32BIT) - indexSize = 4; - gstate_c.indexAddr += count * indexSize; - } else { - gstate_c.vertexAddr += bytesRead; - } + AdvanceVerts(gstate.vertType, count, bytesRead); } void GPU_GLES::Execute_VertexType(u32 op, u32 diff) { @@ -1081,16 +1072,7 @@ void GPU_GLES::Execute_Bezier(u32 op, u32 diff) { // After drawing, we advance pointers - see SubmitPrim which does the same. int count = bz_ucount * bz_vcount; - if ((gstate.vertType & GE_VTYPE_IDX_MASK) != 0) { - int indexSize = 1; - if ((gstate.vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_16BIT) - indexSize = 2; - else if ((gstate.vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_32BIT) - indexSize = 4; - gstate_c.indexAddr += count * indexSize; - } else { - gstate_c.vertexAddr += bytesRead; - } + AdvanceVerts(gstate.vertType, count, bytesRead); } void GPU_GLES::Execute_Spline(u32 op, u32 diff) { diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 3bec703e06..9436393efe 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1299,3 +1299,16 @@ void GPUCommon::SetCmdValue(u32 op) { gstate.cmdmem[cmd] = op; ExecuteOp(op, diff); } + +void GPUCommon::AdvanceVerts(u32 vertType, int count, int bytesRead) { + if ((vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { + int indexSize = 1; + if ((vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_16BIT) + indexSize = 2; + else if ((vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_32BIT) + indexSize = 4; + gstate_c.indexAddr += count * indexSize; + } else { + gstate_c.vertexAddr += bytesRead; + } +} diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 72abc7eefd..bec039e544 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -156,6 +156,8 @@ protected: virtual void FinishDeferred() { } + void AdvanceVerts(u32 vertType, int count, int bytesRead); + // Allows early unlocking with a guard. Do not double unlock. class easy_guard { public: diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 0e4a1e212f..573871a632 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -332,16 +332,7 @@ void SoftGPU::ExecuteOp(u32 op, u32 diff) // After drawing, we advance the vertexAddr (when non indexed) or indexAddr (when indexed). // Some games rely on this, they don't bother reloading VADDR and IADDR. // The VADDR/IADDR registers are NOT updated. - if (indices) { - int indexSize = 1; - if ((gstate.vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_16BIT) - indexSize = 2; - else if ((gstate.vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_32BIT) - indexSize = 4; - gstate_c.indexAddr += count * indexSize; - } else { - gstate_c.vertexAddr += bytesRead; - } + AdvanceVerts(gstate.vertType, count, bytesRead); } break; diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 36312b4a4e..b5aa4109e7 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -880,16 +880,7 @@ void GPU_Vulkan::Execute_Prim(u32 op, u32 diff) { // After drawing, we advance the vertexAddr (when non indexed) or indexAddr (when indexed). // Some games rely on this, they don't bother reloading VADDR and IADDR. // The VADDR/IADDR registers are NOT updated. - if (inds) { - int indexSize = 1; - if ((gstate.vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_16BIT) - indexSize = 2; - else if ((gstate.vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_32BIT) - indexSize = 4; - gstate_c.indexAddr += count * indexSize; - } else { - gstate_c.vertexAddr += bytesRead; - } + AdvanceVerts(gstate.vertType, count, bytesRead); } void GPU_Vulkan::Execute_VertexType(u32 op, u32 diff) { @@ -938,16 +929,7 @@ void GPU_Vulkan::Execute_Bezier(u32 op, u32 diff) { // After drawing, we advance pointers - see SubmitPrim which does the same. int count = bz_ucount * bz_vcount; - if ((gstate.vertType & GE_VTYPE_IDX_MASK) != 0) { - int indexSize = 1; - if ((gstate.vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_16BIT) - indexSize = 2; - else if ((gstate.vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_32BIT) - indexSize = 4; - gstate_c.indexAddr += count * indexSize; - } else { - gstate_c.vertexAddr += bytesRead; - } + AdvanceVerts(gstate.vertType, count, bytesRead); } void GPU_Vulkan::Execute_Spline(u32 op, u32 diff) { From d920ffdcad86bf43d1e0aaef3cff92179d5bb417 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 10 Apr 2016 13:11:55 -0700 Subject: [PATCH 3/3] Ignore upper bits of prim type. This matches tests on what hardware does. --- GPU/Directx9/GPU_DX9.cpp | 3 ++- GPU/GLES/GPU_GLES.cpp | 3 ++- GPU/Vulkan/GPU_Vulkan.cpp | 3 ++- Windows/GEDebugger/VertexPreview.cpp | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index be499769ca..7cb0d66143 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -776,7 +776,8 @@ void GPU_DX9::Execute_Prim(u32 op, u32 diff) { u32 data = op & 0xFFFFFF; u32 count = data & 0xFFFF; - GEPrimitiveType prim = static_cast(data >> 16); + // Upper bits are ignored. + GEPrimitiveType prim = static_cast((data >> 16) & 7); if (count == 0) return; diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index e70db2434b..8e4b064767 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -948,7 +948,8 @@ void GPU_GLES::Execute_Prim(u32 op, u32 diff) { u32 data = op & 0xFFFFFF; u32 count = data & 0xFFFF; - GEPrimitiveType prim = static_cast(data >> 16); + // Upper bits are ignored. + GEPrimitiveType prim = static_cast((data >> 16) & 7); if (count == 0) return; diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index b5aa4109e7..9e5a1f6c33 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -822,7 +822,8 @@ void GPU_Vulkan::Execute_Prim(u32 op, u32 diff) { u32 data = op & 0xFFFFFF; u32 count = data & 0xFFFF; - GEPrimitiveType prim = static_cast(data >> 16); + // Upper bits are ignored. + GEPrimitiveType prim = static_cast((data >> 16) & 7); if (count == 0) return; diff --git a/Windows/GEDebugger/VertexPreview.cpp b/Windows/GEDebugger/VertexPreview.cpp index bb18f0f68b..9fb8864ff3 100644 --- a/Windows/GEDebugger/VertexPreview.cpp +++ b/Windows/GEDebugger/VertexPreview.cpp @@ -152,7 +152,7 @@ static void ExpandRectangles(std::vector &vertices, std::vector< } void CGEDebugger::UpdatePrimPreview(u32 op) { - const u32 prim_type = (op >> 16) & 0xFF; + const u32 prim_type = (op >> 16) & 0x7; int count = op & 0xFFFF; if (prim_type >= 7) { ERROR_LOG(COMMON, "Unsupported prim type: %x", op);