From d0f4e5c2d14e95d237b044e29117f31a28af4248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 3 Jun 2026 13:46:17 +0200 Subject: [PATCH] Visualize bounding boxes in ImGe debugger by drawing their corners --- GPU/Common/SoftwareTransformCommon.cpp | 58 +++--- GPU/Common/SoftwareTransformCommon.h | 3 +- GPU/Debugger/State.cpp | 65 +++--- GPU/Debugger/State.h | 2 +- GPU/GPUCommon.cpp | 35 ++-- GPU/GPUCommon.h | 5 +- GPU/GeConstants.cpp | 263 +++++++++++++++++++++++++ GPU/ge_constants.h | 2 + UI/ImDebugger/ImGe.cpp | 48 +++-- UI/ImDebugger/ImGe.h | 1 + Windows/GEDebugger/TabVertices.cpp | 5 +- Windows/GEDebugger/VertexPreview.cpp | 2 +- 12 files changed, 386 insertions(+), 103 deletions(-) diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index 52094ec8f8..ae9e9d5d37 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -37,7 +37,7 @@ static bool ExpandRectangles(int vertexCount, int &numDecodedVerts, int vertsSize, u16 *&inds, int indsSize, const TransformedVertex *transformed, TransformedVertex *transformedExpanded, int *drawIndexCount, bool throughmode, bool *pixelMappedExactly); static bool ExpandLines(int vertexCount, int &numDecodedVerts, int vertsSize, u16 *&inds, int indsSize, const TransformedVertex *transformed, TransformedVertex *transformedExpanded, int *drawIndexCount, bool throughmode); -static bool ExpandPoints(int vertexCount, int &maxIndex, int vertsSize, u16 *&inds, int indsSize, const TransformedVertex *transformed, TransformedVertex *transformedExpanded, int *drawIndexCount, bool throughmode); +static bool ExpandPoints(int vertexCount, int &maxIndex, int vertsSize, u16 *&inds, int indsSize, const TransformedVertex *transformed, TransformedVertex *transformedExpanded, int *drawIndexCount, bool throughmode, float pointScale); static SoftwareTransformAction ProjectClipAndExpand(SoftwareTransformParams ¶ms, int prim, int vertexCount, u32 vertType, u16 *&inds, int indsSize, int &numDecodedVerts, int vertsSize, SoftwareTransformResult *result); // This is the software transform pipeline, which is necessary for supporting RECT @@ -636,7 +636,7 @@ static SoftwareTransformAction ProjectClipAndExpand(SoftwareTransformParams &par } result->pixelMapped = false; - if (!ExpandPoints(vertexCount, numDecodedVerts, vertsSize, inds, indsSize, transformed, transformedExpanded, &drawIndexCount, throughmode)) { + if (!ExpandPoints(vertexCount, numDecodedVerts, vertsSize, inds, indsSize, transformed, transformedExpanded, &drawIndexCount, throughmode, params.pointScale)) { result->drawVertexCount = 0; result->drawIndexCount = 0; result->drawBuffer = nullptr; @@ -1104,7 +1104,7 @@ static bool ExpandLines(int vertexCount, int &numDecodedVerts, int vertsSize, u1 return true; } -static bool ExpandPoints(int vertexCount, int &maxIndex, int vertsSize, u16 *&inds, int indsSize, const TransformedVertex *transformed, TransformedVertex *transformedExpanded, int *drawIndexCount, bool throughmode) { +static bool ExpandPoints(int vertexCount, int &maxIndex, int vertsSize, u16 *&inds, int indsSize, const TransformedVertex *transformed, TransformedVertex *transformedExpanded, int *drawIndexCount, bool throughmode, float pointScale) { // Before we start, do a sanity check - does the output fit? if (vertexCount * 6 > indsSize) { // Won't fit, kill the draw. @@ -1121,17 +1121,22 @@ static bool ExpandPoints(int vertexCount, int &maxIndex, int vertsSize, u16 *&in u16 *newInds = inds + vertexCount; u16 *indsOut = newInds; - float dx = 1.0f; - float dy = 1.0f; + const float offset = pointScale != 1.0f ? -pointScale * 0.5f : 0.0f; - float du = 1.0f / gstate_c.curTextureWidth; - float dv = 1.0f / gstate_c.curTextureHeight; + const float dx = 1.0f * pointScale; + const float dy = 1.0f * pointScale; + + const float du = 1.0f / gstate_c.curTextureWidth; + const float dv = 1.0f / gstate_c.curTextureHeight; maxIndex = 4 * vertexCount; for (int i = 0; i < vertexCount; ++i) { - const TransformedVertex &transVtxTL = transformed[indsIn[i]]; + TransformedVertex transVtxTL = transformed[indsIn[i]]; + // Centering, if the logic below enables it. + transVtxTL.x += offset; + transVtxTL.y += offset; - // Create the bottom right version. + // Create the bottom right corner. TransformedVertex transVtxBR = transVtxTL; transVtxBR.x += dx; transVtxBR.y += dy; @@ -1311,7 +1316,7 @@ static Vec3f ScreenToDrawing(const Vec3f& coords) { // This is really just for vertex preview in the debugger, not for actual rendering! // TODO: Support tessellation!! That's currently entirely broken (I guess maybe we'll draw the control points as something). // count is the input vertex count (describes the draw together with prim). -bool GetCurrentDrawAsDebugVertices(DrawEngineCommon *drawEngine, GEPrimitiveType prim, GEPrimitiveType *outPrim, int count, std::vector &debugVertices, std::vector &debugIndices, int *outLowerIndexBound, TransformStats *stats, DebugVertexFlags flags) { +bool GetCurrentDrawAsDebugVertices(DrawEngineCommon *drawEngine, GECommand cmd, GEPrimitiveType prim, GEPrimitiveType *outPrim, int count, std::vector *debugVertices, std::vector *debugIndices, int *outLowerIndexBound, TransformStats *stats, DebugVertexFlags flags) { // This is always for the current vertices. u16 indexLowerBound = 0; u16 indexUpperBound = count - 1; @@ -1374,7 +1379,7 @@ bool GetCurrentDrawAsDebugVertices(DrawEngineCommon *drawEngine, GEPrimitiveType if (!(flags & DebugVertexFlags::Transformed)) { // Output the untransformed vertices (although with skinning and morph baked-in from decode), // and the original indices. Might be interesting to look at. - debugVertices.resize(verticesToDecode); + debugVertices->resize(verticesToDecode); VertexReader reader(vertsTemp.data(), dec->GetDecVtxFmt(), vertTypeID); const u8 defaultColor[4] = { @@ -1386,7 +1391,7 @@ bool GetCurrentDrawAsDebugVertices(DrawEngineCommon *drawEngine, GEPrimitiveType for (int i = 0; i < verticesToDecode; i++) { reader.Goto(i); - GPUDebugVertex &sv = debugVertices[i]; + GPUDebugVertex &sv = (*debugVertices)[i]; sv = {}; if (vertTypeID & GE_VTYPE_TC_MASK) { reader.ReadUV(&sv.u); @@ -1418,24 +1423,24 @@ bool GetCurrentDrawAsDebugVertices(DrawEngineCommon *drawEngine, GEPrimitiveType // Output the indices straight switch (vertTypeID & GE_VTYPE_IDX_MASK) { case GE_VTYPE_IDX_NONE: - debugIndices.clear(); // it's just a sequence, effectively. + debugIndices->clear(); // it's just a sequence, effectively. break; case GE_VTYPE_IDX_8BIT: - debugIndices.resize(verticesToDecode); + debugIndices->resize(verticesToDecode); for (int i = 0; i < verticesToDecode; i++) { - debugIndices[i] = ((const u8 *)indsPtr)[i]; + (*debugIndices)[i] = ((const u8 *)indsPtr)[i]; } break; case GE_VTYPE_IDX_16BIT: - debugIndices.resize(verticesToDecode); + debugIndices->resize(verticesToDecode); for (int i = 0; i < verticesToDecode; i++) { - debugIndices[i] = ((const u16_le *)indsPtr)[i]; + (*debugIndices)[i] = ((const u16_le *)indsPtr)[i]; } break; case GE_VTYPE_IDX_32BIT: - debugIndices.resize(verticesToDecode); + debugIndices->resize(verticesToDecode); for (int i = 0; i < verticesToDecode; i++) { - debugIndices[i] = ((const u32_le *)indsPtr)[i]; + (*debugIndices)[i] = ((const u32_le *)indsPtr)[i]; } break; } @@ -1466,7 +1471,7 @@ bool GetCurrentDrawAsDebugVertices(DrawEngineCommon *drawEngine, GEPrimitiveType break; } - // After this, strips and fans have been collapsed to triangles. + // After index generation, strips and fans have been collapsed to triangles. switch (prim) { case GE_PRIM_LINE_STRIP: prim = GE_PRIM_LINES; @@ -1489,14 +1494,15 @@ bool GetCurrentDrawAsDebugVertices(DrawEngineCommon *drawEngine, GEPrimitiveType params.decoded = vertsTemp.data(); params.transformed = transformed.data(); params.transformedExpanded = transformedExpanded.data(); + params.pointScale = cmd == GE_CMD_BOUNDINGBOX ? 4.0f : 1.0f; // Just make them more visible, for eas of debugging. RunSoftwareTransform(params, prim, vertTypeID, dec->GetDecVtxFmt(), numDecodedVerts, 65536, generatedIndices, inds, (int)indexTemp.size(), &result); // Output of software transform is always an indexed triangle list (or nothing). if (result.drawIndexCount == 0) { // Not a failue, but everything got culled. - debugVertices.clear(); - debugIndices.clear(); + debugVertices->clear(); + debugIndices->clear(); return true; } @@ -1510,18 +1516,18 @@ bool GetCurrentDrawAsDebugVertices(DrawEngineCommon *drawEngine, GEPrimitiveType gstate_c.vertexFullAlpha = savedVertexFullAlpha; // Supply indices in a correctly-sized vector. - debugIndices.resize(result.drawIndexCount); - memcpy(debugIndices.data(), inds, result.drawIndexCount * sizeof(u16)); + debugIndices->resize(result.drawIndexCount); + memcpy(debugIndices->data(), inds, result.drawIndexCount * sizeof(u16)); const bool applyOffset = (flags & DebugVertexFlags::DrawCoords) && !throughMode; const float offsetX = applyOffset ? -gstate.getOffsetX() : 0.0f; const float offsetY = applyOffset ? -gstate.getOffsetY() : 0.0f; // Convert the transformed vertices to the debug vertex format. - debugVertices.resize(result.drawVertexCount); + debugVertices->resize(result.drawVertexCount); for (int i = 0; i < result.drawVertexCount; i++) { const TransformedVertex &vtx = result.drawBuffer[i]; - GPUDebugVertex &dv = debugVertices[i]; + GPUDebugVertex &dv = (*debugVertices)[i]; dv.x = vtx.x + offsetX; dv.y = vtx.y + offsetY; dv.z = vtx.z; diff --git a/GPU/Common/SoftwareTransformCommon.h b/GPU/Common/SoftwareTransformCommon.h index 3c9814ac57..c7b8a84ade 100644 --- a/GPU/Common/SoftwareTransformCommon.h +++ b/GPU/Common/SoftwareTransformCommon.h @@ -65,6 +65,7 @@ struct SoftwareTransformParams { bool allowClear; bool allowSeparateAlphaClear; bool everUsedEqualDepth; + float pointScale = 1.0f; // Useful to increase these for debug views of bounding box corners. }; // Converts an index buffer to make the provoking vertex the last. @@ -86,4 +87,4 @@ u32 NormalizeVertices(SimpleVertex *sverts, u8 *bufPtr, const u8 *inPtr, int low // In the returned data, you should subtract the value of lowerIndexBound from the indices to get the actual vertex index in the vertices array. // This is because some draws in some games use very large indices, but they only use a small range of them in each PRIM submission. // Additionally, if the transformed flag is set in flags, the indices will be transformed into "generic" types (triangles instead of strips), etc. -bool GetCurrentDrawAsDebugVertices(DrawEngineCommon *drawEngine, GEPrimitiveType prim, GEPrimitiveType *outPrim, int count, std::vector &vertices, std::vector &indices, int *lowerIndexBound, TransformStats *stats, DebugVertexFlags flags); +bool GetCurrentDrawAsDebugVertices(DrawEngineCommon *drawEngine, GECommand cmd, GEPrimitiveType prim, GEPrimitiveType *outPrim, int count, std::vector *vertices, std::vector *indices, int *lowerIndexBound, TransformStats *stats, DebugVertexFlags flags); diff --git a/GPU/Debugger/State.cpp b/GPU/Debugger/State.cpp index 30c0adcd53..ef496f54b2 100644 --- a/GPU/Debugger/State.cpp +++ b/GPU/Debugger/State.cpp @@ -805,26 +805,28 @@ static void ExpandSpline(int &count, int op, const std::vector &si FreeAlignedMemory(cpoints.col); } -bool GetPrimPreview(u32 op, GEPrimitiveType &prim, std::vector &vertices, std::vector &indices, int *lowerIndexBound, bool transformed) { - u32 prim_type = GE_PRIM_INVALID; +bool GetPrimPreview(u32 op, GEPrimitiveType *prim, std::vector *vertices, std::vector *indices, int *lowerIndexBound, bool transformed) { int count_u = 0; int count_v = 0; int count = 0; - const u32 cmd = op >> 24; + const GECommand cmd = static_cast(op >> 24); if (cmd == GE_CMD_PRIM) { - prim_type = (op >> 16) & 0x7; + *prim = static_cast((op >> 16) & 0x7); // irrelevant for bbox + count = op & 0xFFFF; + } else if (cmd == GE_CMD_BOUNDINGBOX) { + *prim = GE_PRIM_POINTS; // There's no set order for these, so drawing lines might look strange. Maybe if we draw lines from every vertex to every other... count = op & 0xFFFF; } else { constexpr GEPrimitiveType primLookup[] = { GE_PRIM_TRIANGLES, GE_PRIM_LINES, GE_PRIM_POINTS, GE_PRIM_POINTS }; - prim_type = primLookup[gstate.getPatchPrimitiveType()]; + *prim = primLookup[gstate.getPatchPrimitiveType()]; count_u = (op & 0x00FF) >> 0; count_v = (op & 0xFF00) >> 8; count = count_u * count_v; } - if (prim_type >= 7) { + if (*prim >= 7) { ERROR_LOG(Log::G3D, "Unsupported prim type: %x", op); return false; } @@ -836,8 +838,6 @@ bool GetPrimPreview(u32 op, GEPrimitiveType &prim, std::vector & return false; } - prim = static_cast(prim_type); - DebugVertexFlags flags = DebugVertexFlags::DrawCoords; if (cmd == GE_CMD_PRIM) { flags |= DebugVertexFlags::Clipped; @@ -845,57 +845,58 @@ bool GetPrimPreview(u32 op, GEPrimitiveType &prim, std::vector & flags |= DebugVertexFlags::Transformed; } } else { - flags = DebugVertexFlags::Transformed; + flags |= DebugVertexFlags::Transformed; } GEPrimitiveType outPrim; - if (!gpu->GetCurrentDrawAsDebugVertices(prim, &outPrim, count, vertices, indices, lowerIndexBound, nullptr, flags)) { + if (!gpu->GetCurrentDrawAsDebugVertices(cmd, *prim, &outPrim, count, vertices, indices, lowerIndexBound, nullptr, flags)) { ERROR_LOG(Log::G3D, "Vertex preview not yet supported"); return false; } // Sanity check the output (for debugging) - if (indices.size()) { - for (int i = 0; i < indices.size(); ++i) { - int offsetIndex = indices[i] - *lowerIndexBound; - if (offsetIndex >= vertices.size() || offsetIndex < 0) { - ERROR_LOG(Log::G3D, "Invalid vertex index %d (%d) (vertex count %d)", indices[i], offsetIndex, (int)vertices.size()); + if (indices->size()) { + for (int i = 0; i < indices->size(); ++i) { + int offsetIndex = (*indices)[i] - *lowerIndexBound; + if (offsetIndex >= vertices->size() || offsetIndex < 0) { + ERROR_LOG(Log::G3D, "Invalid vertex index %d (%d) (vertex count %d)", (*indices)[i], offsetIndex, (int)vertices->size()); return false; } } } - prim = outPrim; + *prim = outPrim; - if (cmd != GE_CMD_PRIM) { + if (cmd != GE_CMD_PRIM && cmd != GE_CMD_BOUNDINGBOX) { static std::vector generatedVerts; static std::vector generatedInds; static std::vector simpleVerts; - simpleVerts.resize(vertices.size()); - for (size_t i = 0; i < vertices.size(); ++i) { + simpleVerts.resize(vertices->size()); + for (size_t i = 0; i < vertices->size(); ++i) { // For now, let's just copy back so we can use TessellateBezierPatch/TessellateSplinePatch... - simpleVerts[i].uv[0] = vertices[i].u; - simpleVerts[i].uv[1] = vertices[i].v; - simpleVerts[i].pos = Vec3Packedf(vertices[i].x, vertices[i].y, vertices[i].z); + simpleVerts[i].uv[0] = (*vertices)[i].u; + simpleVerts[i].uv[1] = (*vertices)[i].v; + simpleVerts[i].pos = Vec3Packedf((*vertices)[i].x, (*vertices)[i].y, (*vertices)[i].z); } *lowerIndexBound = 0; if (cmd == GE_CMD_BEZIER) { - ExpandBezier(count, op, simpleVerts, indices, generatedVerts, generatedInds); + ExpandBezier(count, op, simpleVerts, *indices, generatedVerts, generatedInds); } else if (cmd == GE_CMD_SPLINE) { - ExpandSpline(count, op, simpleVerts, indices, generatedVerts, generatedInds); + ExpandSpline(count, op, simpleVerts, *indices, generatedVerts, generatedInds); } - vertices.resize(generatedVerts.size()); - for (size_t i = 0; i < vertices.size(); ++i) { - vertices[i].u = generatedVerts[i].uv[0]; - vertices[i].v = generatedVerts[i].uv[1]; - vertices[i].x = generatedVerts[i].pos.x; - vertices[i].y = generatedVerts[i].pos.y; - vertices[i].z = generatedVerts[i].pos.z; + vertices->resize(generatedVerts.size()); + for (size_t i = 0; i < vertices->size(); ++i) { + auto vertex = &(*vertices)[i]; + vertex->u = generatedVerts[i].uv[0]; + vertex->v = generatedVerts[i].uv[1]; + vertex->x = generatedVerts[i].pos.x; + vertex->y = generatedVerts[i].pos.y; + vertex->z = generatedVerts[i].pos.z; } - indices = generatedInds; + *indices = generatedInds; } /* diff --git a/GPU/Debugger/State.h b/GPU/Debugger/State.h index 6f44a0e8f9..04ffcf0b70 100644 --- a/GPU/Debugger/State.h +++ b/GPU/Debugger/State.h @@ -68,6 +68,6 @@ void FormatVertColDecoded(char *dest, size_t destSize, const GPUDebugVertex &ver void FormatVertColTransformed(char *dest, size_t destSize, const GPUDebugVertex &vert, VertexListTransformedCol col); // These are utilities used by the debugger vertex preview. -bool GetPrimPreview(u32 op, GEPrimitiveType &prim, std::vector &vertices, std::vector &indices, int *lowerIndexBound, bool transformed); +bool GetPrimPreview(u32 op, GEPrimitiveType *prim, std::vector *vertices, std::vector *indices, int *lowerIndexBound, bool transformed); void DescribePixel(u32 pix, GPUDebugBufferFormat fmt, int x, int y, char desc[256]); void DescribePixelRGBA(u32 pix, GPUDebugBufferFormat fmt, int x, int y, char desc[256]); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index b1c091c969..c59da1dcbd 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1579,23 +1579,29 @@ bool GPUCommon::GetCurrentDisplayList(DisplayList &list) const { return true; } -int GPUCommon::GetCurrentPrimCount(GEPrimitiveType *prim) const { +int GPUCommon::GetCurrentPrim(GEPrimitiveType *prim, GECommand *outCmd) const { DisplayList list; - u32 cmd; + u32 cmdWord; if (GetCurrentDisplayList(list)) { - cmd = Memory::Read_U32(list.pc); + cmdWord = Memory::Read_U32(list.pc); } else { // Current prim value. - cmd = gstate.cmdmem[GE_CMD_PRIM]; + cmdWord = gstate.cmdmem[GE_CMD_PRIM]; } - if ((cmd >> 24) == GE_CMD_PRIM || (cmd >> 24) == GE_CMD_BOUNDINGBOX) { - *prim = GEPrimitiveType((cmd >> 16) & 7); - return cmd & 0xFFFF; - } else if ((cmd >> 24) == GE_CMD_BEZIER || (cmd >> 24) == GE_CMD_SPLINE) { + GECommand cmd = static_cast(cmdWord >> 24); + *outCmd = cmd; + + if (cmd == GE_CMD_PRIM) { + *prim = GEPrimitiveType((cmdWord >> 16) & 7); + return cmdWord & 0xFFFF; + } else if (cmd == GE_CMD_BOUNDINGBOX) { + *prim = GE_PRIM_POINTS; + return cmdWord & 0xFFFF; + } else if (cmd == GE_CMD_BEZIER || cmd == GE_CMD_SPLINE) { *prim = GE_PRIM_TRIANGLES; // no correct answer - u32 u = (cmd & 0x00FF) >> 0; - u32 v = (cmd & 0xFF00) >> 8; + u32 u = (cmdWord & 0x00FF) >> 0; + u32 v = (cmdWord & 0xFF00) >> 8; return u * v; } else { // Unknown primitive. @@ -2028,8 +2034,8 @@ bool GPUCommon::PerformWriteStencilFromMemory(u32 dest, int size, WriteStencil f return false; } -bool GPUCommon::GetCurrentDrawAsDebugVertices(GEPrimitiveType prim, GEPrimitiveType *outPrim, int count, std::vector &vertices, std::vector &indices, int *lowerIndexBound, TransformStats *stats, DebugVertexFlags flags) const { - return ::GetCurrentDrawAsDebugVertices(drawEngineCommon_, prim, outPrim, count, vertices, indices, lowerIndexBound, stats, flags); +bool GPUCommon::GetCurrentDrawAsDebugVertices(GECommand cmd, GEPrimitiveType prim, GEPrimitiveType *outPrim, int count, std::vector *vertices, std::vector *indices, int *lowerIndexBound, TransformStats *stats, DebugVertexFlags flags) const { + return ::GetCurrentDrawAsDebugVertices(drawEngineCommon_, cmd, prim, outPrim, count, vertices, indices, lowerIndexBound, stats, flags); } bool GPUCommon::DescribeCodePtr(const u8 *ptr, std::string &name) { @@ -2057,6 +2063,7 @@ void GPUCommon::SetBreakNext(GPUDebug::BreakNext next) { break; case GPUDebug::BreakNext::PRIM: case GPUDebug::BreakNext::COUNT: + breakpoints_.AddCmdBreakpoint(GE_CMD_BOUNDINGBOX, true); breakpoints_.AddCmdBreakpoint(GE_CMD_PRIM, true); breakpoints_.AddCmdBreakpoint(GE_CMD_BEZIER, true); breakpoints_.AddCmdBreakpoint(GE_CMD_SPLINE, true); @@ -2106,7 +2113,9 @@ GPUDebug::NotifyResult GPUCommon::NotifyCommand(u32 pc, GPUBreakpoints *breakpoi bool isPrim = false; bool process = true; // Process is only for the restrictPrimRanges functionality - if (cmd == GE_CMD_PRIM || cmd == GE_CMD_BEZIER || cmd == GE_CMD_SPLINE || cmd == GE_CMD_VAP || cmd == GE_CMD_TRANSFERSTART) { // VAP is immediate mode prims. + + // NOTE: We now consider BBOX a PRIM command. + if (cmd == GE_CMD_PRIM || cmd == GE_CMD_BEZIER || cmd == GE_CMD_SPLINE || cmd == GE_CMD_VAP || cmd == GE_CMD_TRANSFERSTART || cmd == GE_CMD_BOUNDINGBOX) { // VAP is immediate mode prims. isPrim = true; primsThisFrame_++; diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index e11d0b31c4..8178114656 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -75,8 +75,8 @@ public: virtual bool GetOutputFramebuffer(GPUDebugBuffer &buffer) { return false; } bool GetCurrentDisplayList(DisplayList &list) const; - bool GetCurrentDrawAsDebugVertices(GEPrimitiveType prim, GEPrimitiveType *outPrim, int count, std::vector &vertices, std::vector &indices, int *lowerIndexBound, TransformStats *stats, DebugVertexFlags flags) const; - int GetCurrentPrimCount(GEPrimitiveType *prim) const; + bool GetCurrentDrawAsDebugVertices(GECommand cmd, GEPrimitiveType prim, GEPrimitiveType *outPrim, int count, std::vector *vertices, std::vector *indices, int *lowerIndexBound, TransformStats *stats, DebugVertexFlags flags) const; + int GetCurrentPrim(GEPrimitiveType *prim, GECommand *outCmd) const; // Return value has the count. // FinishInitOnMainThread runs on the main thread, of course. virtual void FinishInitOnMainThread() {} @@ -201,6 +201,7 @@ public: virtual FramebufferManagerCommon *GetFramebufferManagerCommon() { return nullptr; } virtual TextureCacheCommon *GetTextureCacheCommon() { return nullptr; } + const DrawEngineCommon *GetDrawEngineCommon() const { return drawEngineCommon_; } virtual std::vector DebugGetShaderIDs(DebugShaderType shader) { return std::vector(); }; virtual std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) { diff --git a/GPU/GeConstants.cpp b/GPU/GeConstants.cpp index 95c9ffdf8d..6cb9bfd361 100644 --- a/GPU/GeConstants.cpp +++ b/GPU/GeConstants.cpp @@ -1,5 +1,268 @@ #include "GPU/ge_constants.h" +const char *GeCmdToString(GECommand cmd) { + switch (cmd) { + case GE_CMD_NOP: return "NOP"; + case GE_CMD_VADDR: return "VADDR"; + case GE_CMD_IADDR: return "IADDR"; + case GE_CMD_PRIM: return "PRIM"; + case GE_CMD_BEZIER: return "BEZIER"; + case GE_CMD_SPLINE: return "SPLINE"; + case GE_CMD_BOUNDINGBOX: return "BOUNDINGBOX"; + case GE_CMD_JUMP: return "JUMP"; + case GE_CMD_BJUMP: return "BJUMP"; + case GE_CMD_CALL: return "CALL"; + case GE_CMD_RET: return "RET"; + case GE_CMD_END: return "END"; + case GE_CMD_SIGNAL: return "SIGNAL"; + case GE_CMD_FINISH: return "FINISH"; + case GE_CMD_BASE: return "BASE"; + case GE_CMD_VERTEXTYPE: return "VERTEXTYPE"; + case GE_CMD_OFFSETADDR: return "OFFSETADDR"; + case GE_CMD_ORIGIN: return "ORIGIN"; + case GE_CMD_REGION1: return "REGION1"; + case GE_CMD_REGION2: return "REGION2"; + case GE_CMD_LIGHTINGENABLE: return "LIGHTINGENABLE"; + case GE_CMD_LIGHTENABLE0: return "LIGHTENABLE0"; + case GE_CMD_LIGHTENABLE1: return "LIGHTENABLE1"; + case GE_CMD_LIGHTENABLE2: return "LIGHTENABLE2"; + case GE_CMD_LIGHTENABLE3: return "LIGHTENABLE3"; + case GE_CMD_DEPTHCLIPENABLE: return "DEPTHCLIPENABLE"; + case GE_CMD_CULLFACEENABLE: return "CULLFACEENABLE"; + case GE_CMD_TEXTUREMAPENABLE: return "TEXTUREMAPENABLE"; + case GE_CMD_FOGENABLE: return "FOGENABLE"; + case GE_CMD_DITHERENABLE: return "DITHERENABLE"; + case GE_CMD_ALPHABLENDENABLE: return "ALPHABLENDENABLE"; + case GE_CMD_ALPHATESTENABLE: return "ALPHATESTENABLE"; + case GE_CMD_ZTESTENABLE: return "ZTESTENABLE"; + case GE_CMD_STENCILTESTENABLE: return "STENCILTESTENABLE"; + case GE_CMD_ANTIALIASENABLE: return "ANTIALIASENABLE"; + case GE_CMD_PATCHCULLENABLE: return "PATCHCULLENABLE"; + case GE_CMD_COLORTESTENABLE: return "COLORTESTENABLE"; + case GE_CMD_LOGICOPENABLE: return "LOGICOPENABLE"; + case GE_CMD_BONEMATRIXNUMBER: return "BONEMATRIXNUMBER"; + case GE_CMD_BONEMATRIXDATA: return "BONEMATRIXDATA"; + case GE_CMD_MORPHWEIGHT0: return "MORPHWEIGHT0"; + case GE_CMD_MORPHWEIGHT1: return "MORPHWEIGHT1"; + case GE_CMD_MORPHWEIGHT2: return "MORPHWEIGHT2"; + case GE_CMD_MORPHWEIGHT3: return "MORPHWEIGHT3"; + case GE_CMD_MORPHWEIGHT4: return "MORPHWEIGHT4"; + case GE_CMD_MORPHWEIGHT5: return "MORPHWEIGHT5"; + case GE_CMD_MORPHWEIGHT6: return "MORPHWEIGHT6"; + case GE_CMD_MORPHWEIGHT7: return "MORPHWEIGHT7"; + case GE_CMD_PATCHDIVISION: return "PATCHDIVISION"; + case GE_CMD_PATCHPRIMITIVE: return "PATCHPRIMITIVE"; + case GE_CMD_PATCHFACING: return "PATCHFACING"; + case GE_CMD_WORLDMATRIXNUMBER: return "WORLDMATRIXNUMBER"; + case GE_CMD_WORLDMATRIXDATA: return "WORLDMATRIXDATA"; + case GE_CMD_VIEWMATRIXNUMBER: return "VIEWMATRIXNUMBER"; + case GE_CMD_VIEWMATRIXDATA: return "VIEWMATRIXDATA"; + case GE_CMD_PROJMATRIXNUMBER: return "PROJMATRIXNUMBER"; + case GE_CMD_PROJMATRIXDATA: return "PROJMATRIXDATA"; + case GE_CMD_TGENMATRIXNUMBER: return "TGENMATRIXNUMBER"; + case GE_CMD_TGENMATRIXDATA: return "TGENMATRIXDATA"; + case GE_CMD_VIEWPORTXSCALE: return "VIEWPORTXSCALE"; + case GE_CMD_VIEWPORTYSCALE: return "VIEWPORTYSCALE"; + case GE_CMD_VIEWPORTZSCALE: return "VIEWPORTZSCALE"; + case GE_CMD_VIEWPORTXCENTER: return "VIEWPORTXCENTER"; + case GE_CMD_VIEWPORTYCENTER: return "VIEWPORTYCENTER"; + case GE_CMD_VIEWPORTZCENTER: return "VIEWPORTZCENTER"; + case GE_CMD_TEXSCALEU: return "TEXSCALEU"; + case GE_CMD_TEXSCALEV: return "TEXSCALEV"; + case GE_CMD_TEXOFFSETU: return "TEXOFFSETU"; + case GE_CMD_TEXOFFSETV: return "TEXOFFSETV"; + case GE_CMD_OFFSETX: return "OFFSETX"; + case GE_CMD_OFFSETY: return "OFFSETY"; + case GE_CMD_SHADEMODE: return "SHADEMODE"; // flat or gouraud + case GE_CMD_REVERSENORMAL: return "REVERSENORMAL"; + case GE_CMD_MATERIALUPDATE: return "MATERIALUPDATE"; + case GE_CMD_MATERIALEMISSIVE: return "MATERIALEMISSIVE"; //not sure about these but this makes sense + case GE_CMD_MATERIALAMBIENT: return "MATERIALAMBIENT"; //gotta try enabling lighting and check :) + case GE_CMD_MATERIALDIFFUSE: return "MATERIALDIFFUSE"; + case GE_CMD_MATERIALSPECULAR: return "MATERIALSPECULAR"; + case GE_CMD_MATERIALALPHA: return "MATERIALALPHA"; + case GE_CMD_MATERIALSPECULARCOEF: return "MATERIALSPECULARCOEF"; + case GE_CMD_AMBIENTCOLOR: return "AMBIENTCOLOR"; + case GE_CMD_AMBIENTALPHA: return "AMBIENTALPHA"; + case GE_CMD_LIGHTMODE: return "LIGHTMODE"; + case GE_CMD_LIGHTTYPE0: return "LIGHTTYPE0"; + case GE_CMD_LIGHTTYPE1: return "LIGHTTYPE1"; + case GE_CMD_LIGHTTYPE2: return "LIGHTTYPE2"; + case GE_CMD_LIGHTTYPE3: return "LIGHTTYPE3"; + case GE_CMD_LX0: return "LX0"; + case GE_CMD_LY0: return "LY0"; + case GE_CMD_LZ0: return "LZ0"; + case GE_CMD_LX1: return "LX1"; + case GE_CMD_LY1: return "LY1"; + case GE_CMD_LZ1: return "LZ1"; + case GE_CMD_LX2: return "LX2"; + case GE_CMD_LY2: return "LY2"; + case GE_CMD_LZ2: return "LZ2"; + case GE_CMD_LX3: return "LX3"; + case GE_CMD_LY3: return "LY3"; + case GE_CMD_LZ3: return "LZ3"; + case GE_CMD_LDX0: return "LDX0"; + case GE_CMD_LDY0: return "LDY0"; + case GE_CMD_LDZ0: return "LDZ0"; + case GE_CMD_LDX1: return "LDX1"; + case GE_CMD_LDY1: return "LDY1"; + case GE_CMD_LDZ1: return "LDZ1"; + case GE_CMD_LDX2: return "LDX2"; + case GE_CMD_LDY2: return "LDY2"; + case GE_CMD_LDZ2: return "LDZ2"; + case GE_CMD_LDX3: return "LDX3"; + case GE_CMD_LDY3: return "LDY3"; + case GE_CMD_LDZ3: return "LDZ3"; + case GE_CMD_LKA0: return "LKA0"; + case GE_CMD_LKB0: return "LKB0"; + case GE_CMD_LKC0: return "LKC0"; + case GE_CMD_LKA1: return "LKA1"; + case GE_CMD_LKB1: return "LKB1"; + case GE_CMD_LKC1: return "LKC1"; + case GE_CMD_LKA2: return "LKA2"; + case GE_CMD_LKB2: return "LKB2"; + case GE_CMD_LKC2: return "LKC2"; + case GE_CMD_LKA3: return "LKA3"; + case GE_CMD_LKB3: return "LKB3"; + case GE_CMD_LKC3: return "LKC3"; + case GE_CMD_LKS0: return "LKS0"; + case GE_CMD_LKS1: return "LKS1"; + case GE_CMD_LKS2: return "LKS2"; + case GE_CMD_LKS3: return "LKS3"; + case GE_CMD_LKO0: return "LKO0"; + case GE_CMD_LKO1: return "LKO1"; + case GE_CMD_LKO2: return "LKO2"; + case GE_CMD_LKO3: return "LKO3"; + case GE_CMD_LAC0: return "LAC0"; + case GE_CMD_LDC0: return "LDC0"; + case GE_CMD_LSC0: return "LSC0"; + case GE_CMD_LAC1: return "LAC1"; + case GE_CMD_LDC1: return "LDC1"; + case GE_CMD_LSC1: return "LSC1"; + case GE_CMD_LAC2: return "LAC2"; + case GE_CMD_LDC2: return "LDC2"; + case GE_CMD_LSC2: return "LSC2"; + case GE_CMD_LAC3: return "LAC3"; + case GE_CMD_LDC3: return "LDC3"; + case GE_CMD_LSC3: return "LSC3"; + case GE_CMD_CULL: return "CULL"; + case GE_CMD_FRAMEBUFPTR: return "FRAMEBUFPTR"; + case GE_CMD_FRAMEBUFWIDTH: return "FRAMEBUFWIDTH"; + case GE_CMD_ZBUFPTR: return "ZBUFPTR"; + case GE_CMD_ZBUFWIDTH: return "ZBUFWIDTH"; + case GE_CMD_TEXADDR0: return "TEXADDR0"; + case GE_CMD_TEXADDR1: return "TEXADDR1"; + case GE_CMD_TEXADDR2: return "TEXADDR2"; + case GE_CMD_TEXADDR3: return "TEXADDR3"; + case GE_CMD_TEXADDR4: return "TEXADDR4"; + case GE_CMD_TEXADDR5: return "TEXADDR5"; + case GE_CMD_TEXADDR6: return "TEXADDR6"; + case GE_CMD_TEXADDR7: return "TEXADDR7"; + case GE_CMD_TEXBUFWIDTH0: return "TEXBUFWIDTH0"; + case GE_CMD_TEXBUFWIDTH1: return "TEXBUFWIDTH1"; + case GE_CMD_TEXBUFWIDTH2: return "TEXBUFWIDTH2"; + case GE_CMD_TEXBUFWIDTH3: return "TEXBUFWIDTH3"; + case GE_CMD_TEXBUFWIDTH4: return "TEXBUFWIDTH4"; + case GE_CMD_TEXBUFWIDTH5: return "TEXBUFWIDTH5"; + case GE_CMD_TEXBUFWIDTH6: return "TEXBUFWIDTH6"; + case GE_CMD_TEXBUFWIDTH7: return "TEXBUFWIDTH7"; + case GE_CMD_CLUTADDR: return "CLUTADDR"; + case GE_CMD_CLUTADDRUPPER: return "CLUTADDRUPPER"; + case GE_CMD_TRANSFERSRC: return "TRANSFERSRC"; + case GE_CMD_TRANSFERSRCW: return "TRANSFERSRCW"; + case GE_CMD_TRANSFERDST: return "TRANSFERDST"; + case GE_CMD_TRANSFERDSTW: return "TRANSFERDSTW"; + case GE_CMD_TEXSIZE0: return "TEXSIZE0"; + case GE_CMD_TEXSIZE1: return "TEXSIZE1"; + case GE_CMD_TEXSIZE2: return "TEXSIZE2"; + case GE_CMD_TEXSIZE3: return "TEXSIZE3"; + case GE_CMD_TEXSIZE4: return "TEXSIZE4"; + case GE_CMD_TEXSIZE5: return "TEXSIZE5"; + case GE_CMD_TEXSIZE6: return "TEXSIZE6"; + case GE_CMD_TEXSIZE7: return "TEXSIZE7"; + case GE_CMD_TEXMAPMODE: return "TEXMAPMODE"; + case GE_CMD_TEXSHADELS: return "TEXSHADELS"; + case GE_CMD_TEXMODE: return "TEXMODE"; + case GE_CMD_TEXFORMAT: return "TEXFORMAT"; + case GE_CMD_LOADCLUT: return "LOADCLUT"; + case GE_CMD_CLUTFORMAT: return "CLUTFORMAT"; + case GE_CMD_TEXFILTER: return "TEXFILTER"; + case GE_CMD_TEXWRAP: return "TEXWRAP"; + case GE_CMD_TEXLEVEL: return "TEXLEVEL"; + case GE_CMD_TEXFUNC: return "TEXFUNC"; + case GE_CMD_TEXENVCOLOR: return "TEXENVCOLOR"; + case GE_CMD_TEXFLUSH: return "TEXFLUSH"; + case GE_CMD_TEXSYNC: return "TEXSYNC"; + case GE_CMD_FOG1: return "FOG1"; + case GE_CMD_FOG2: return "FOG2"; + case GE_CMD_FOGCOLOR: return "FOGCOLOR"; + case GE_CMD_TEXLODSLOPE: return "TEXLODSLOPE"; + case GE_CMD_FRAMEBUFPIXFORMAT: return "FRAMEBUFPIXFORMAT"; + case GE_CMD_CLEARMODE: return "CLEARMODE"; + case GE_CMD_SCISSOR1: return "SCISSOR1"; + case GE_CMD_SCISSOR2: return "SCISSOR2"; + case GE_CMD_MINZ: return "MINZ"; + case GE_CMD_MAXZ: return "MAXZ"; + case GE_CMD_COLORTEST: return "COLORTEST"; + case GE_CMD_COLORREF: return "COLORREF"; + case GE_CMD_COLORTESTMASK: return "COLORTESTMASK"; + case GE_CMD_ALPHATEST: return "ALPHATEST"; + case GE_CMD_STENCILTEST: return "STENCILTEST"; + case GE_CMD_STENCILOP: return "STENCILOP"; + case GE_CMD_ZTEST: return "ZTEST"; + case GE_CMD_BLENDMODE: return "BLENDMODE"; + case GE_CMD_BLENDFIXEDA: return "BLENDFIXEDA"; + case GE_CMD_BLENDFIXEDB: return "BLENDFIXEDB"; + case GE_CMD_DITH0: return "DITH0"; + case GE_CMD_DITH1: return "DITH1"; + case GE_CMD_DITH2: return "DITH2"; + case GE_CMD_DITH3: return "DITH3"; + case GE_CMD_LOGICOP: return "LOGICOP"; + case GE_CMD_ZWRITEDISABLE: return "ZWRITEDISABLE"; + case GE_CMD_MASKRGB: return "MASKRGB"; + case GE_CMD_MASKALPHA: return "MASKALPHA"; + case GE_CMD_TRANSFERSTART: return "TRANSFERSTART"; + case GE_CMD_TRANSFERSRCPOS: return "TRANSFERSRCPOS"; + case GE_CMD_TRANSFERDSTPOS: return "TRANSFERDSTPOS"; + case GE_CMD_TRANSFERSIZE: return "TRANSFERSIZE"; + case GE_CMD_VSCX: return "VSCX"; + case GE_CMD_VSCY: return "VSCY"; + case GE_CMD_VSCZ: return "VSCZ"; + case GE_CMD_VTCS: return "VTCS"; + case GE_CMD_VTCT: return "VTCT"; + case GE_CMD_VTCQ: return "VTCQ"; + case GE_CMD_VCV: return "VCV"; + case GE_CMD_VAP: return "VAP"; + case GE_CMD_VFC: return "VFC"; + case GE_CMD_VSCV: return "VSCV"; + case GE_CMD_UNKNOWN_03: return "UNKNOWN_03"; + case GE_CMD_UNKNOWN_0D: return "UNKNOWN_0D"; + case GE_CMD_UNKNOWN_11: return "UNKNOWN_11"; + case GE_CMD_UNKNOWN_29: return "UNKNOWN_29"; + case GE_CMD_UNKNOWN_34: return "UNKNOWN_34"; + case GE_CMD_UNKNOWN_35: return "UNKNOWN_35"; + case GE_CMD_UNKNOWN_39: return "UNKNOWN_39"; + case GE_CMD_UNKNOWN_4E: return "UNKNOWN_4E"; + case GE_CMD_UNKNOWN_4F: return "UNKNOWN_4F"; + case GE_CMD_UNKNOWN_52: return "UNKNOWN_52"; + case GE_CMD_UNKNOWN_59: return "UNKNOWN_59"; + case GE_CMD_UNKNOWN_5A: return "UNKNOWN_5A"; + case GE_CMD_UNKNOWN_B6: return "UNKNOWN_B6"; + case GE_CMD_UNKNOWN_B7: return "UNKNOWN_B7"; + case GE_CMD_UNKNOWN_D1: return "UNKNOWN_D1"; + case GE_CMD_UNKNOWN_ED: return "UNKNOWN_ED"; + case GE_CMD_UNKNOWN_EF: return "UNKNOWN_EF"; + case GE_CMD_UNKNOWN_FA: return "UNKNOWN_FA"; + case GE_CMD_UNKNOWN_FB: return "UNKNOWN_FB"; + case GE_CMD_UNKNOWN_FC: return "UNKNOWN_FC"; + case GE_CMD_UNKNOWN_FD: return "UNKNOWN_FD"; + case GE_CMD_UNKNOWN_FE: return "UNKNOWN_FE"; + case GE_CMD_NOP_FF: return "NOP_FF"; + default: + return "INVALID"; + } +} + const char *GePrimTypeToString(GEPrimitiveType prim) { static constexpr const char * primTypes[8] = { "POINTS", diff --git a/GPU/ge_constants.h b/GPU/ge_constants.h index 69b95ba9e1..64648f68be 100644 --- a/GPU/ge_constants.h +++ b/GPU/ge_constants.h @@ -278,6 +278,8 @@ enum GECommand : uint8_t { GE_CMD_NOP_FF = 0xFF, }; +const char *GeCmdToString(GECommand cmd); + #define GE_VTYPE_TRANSFORM (0<<23) #define GE_VTYPE_THROUGH (1<<23) #define GE_VTYPE_THROUGH_MASK (1<<23) diff --git a/UI/ImDebugger/ImGe.cpp b/UI/ImDebugger/ImGe.cpp index 9510049e7b..a28a5dc1ec 100644 --- a/UI/ImDebugger/ImGe.cpp +++ b/UI/ImDebugger/ImGe.cpp @@ -11,6 +11,7 @@ #include "GPU/Common/TextureCacheCommon.h" #include "GPU/Common/VertexDecoderCommon.h" #include "GPU/Common/SoftwareTransformCommon.h" +#include "GPU/Common/DrawEngineCommon.h" #include "Core/HLE/sceDisplay.h" #include "Core/HW/Display.h" @@ -891,7 +892,7 @@ static const char *DLStateToString(DisplayListState state) { } // TODO: Backport this to the Win32 debugger (ugh). -static void DrawPreviewPrimitive(ImDrawList *drawList, ImVec2 p0, GEPrimitiveType prim, const std::vector &indices, const std::vector &verts, int indexOffset, bool transformed, bool uvToPos, float sx, float sy) { +static void DrawPreviewPrimitive(ImDrawList *drawList, ImVec2 p0, GECommand cmd, GEPrimitiveType prim, const std::vector &indices, const std::vector &verts, int indexOffset, bool transformed, bool uvToPos, float sx, float sy) { // These wrappers are to either draw using the positions or the UV coordinates. auto x = [sx, uvToPos](const GPUDebugVertex &vert) { return sx * (uvToPos ? vert.u : vert.x); @@ -1208,34 +1209,25 @@ void ImGeDebuggerWindow::Draw(ImConfig &cfg, ImControl &control, GPUCommon *gpuD u32 op = 0; DisplayList list; - bool isOnBlockTransfer = false; if (gpuDebug->GetCurrentDisplayList(list)) { _dbg_assert_(Memory::IsValid4AlignedAddress(list.pc)); op = Memory::ReadUnchecked_U32(list.pc); + GECommand cmd = static_cast(op >> 24); + previewCmd_ = cmd; // TODO: Also add support for block transfer previews! - - bool isOnPrim = false; - switch (op >> 24) { - case GE_CMD_PRIM: - isOnPrim = true; + if (cmd == GE_CMD_PRIM || cmd == GE_CMD_BOUNDINGBOX) { if (reloadPreview_) { - GetPrimPreview(op, previewPrim_, previewVertices_, previewIndices_, &previewIndexOffset_, previewTransformed_); + GetPrimPreview(op, &previewPrim_, &previewVertices_, &previewIndices_, &previewIndexOffset_, previewTransformed_); reloadPreview_ = false; } - break; - case GE_CMD_TRANSFERSTART: - isOnBlockTransfer = true; - break; - default: + } else { // Disable the current preview. previewVertices_.clear(); previewIndices_.clear(); previewIndexOffset_ = 0; previewTransformed_ = true; - break; } - } ImGui::BeginChild("texture/fb view"); @@ -1243,7 +1235,7 @@ void ImGeDebuggerWindow::Draw(ImConfig &cfg, ImControl &control, GPUCommon *gpuD ImDrawList *drawList = ImGui::GetWindowDrawList(); if (coreState == CORE_STEPPING_GE) { - if (isOnBlockTransfer) { + if (previewCmd_ == GE_CMD_TRANSFERSTART) { ImGui::Text("Block transfer! Proper preview coming in the future.\n"); ImGui::Text("%08x -> %08x, %d bpp (strides: %d, %d)", gstate.getTransferSrcAddress(), gstate.getTransferDstAddress(), gstate.getTransferBpp(), gstate.getTransferSrcStride(), gstate.getTransferDstStride()); ImGui::Text("%dx%d pixels", gstate.getTransferWidth(), gstate.getTransferHeight()); @@ -1318,7 +1310,7 @@ void ImGeDebuggerWindow::Draw(ImConfig &cfg, ImControl &control, GPUCommon *gpuD // Draw vertex preview on top! if (!previewVertices_.empty()) { - DrawPreviewPrimitive(drawList, p0, previewPrim_, previewIndices_, previewVertices_, previewIndexOffset_, previewTransformed_, false, scale * previewZoom_, scale * previewZoom_); + DrawPreviewPrimitive(drawList, p0, previewCmd_, previewPrim_, previewIndices_, previewVertices_, previewIndexOffset_, previewTransformed_, false, scale * previewZoom_, scale * previewZoom_); } drawList->PopClipRect(); @@ -1347,7 +1339,7 @@ void ImGeDebuggerWindow::Draw(ImConfig &cfg, ImControl &control, GPUCommon *gpuD ImGui::Text("(clear mode - texturing not used)"); } else if (!gstate.isTextureMapEnabled()) { ImGui::Text("(texturing not enabled"); - } else { + } else { // We don't bother with the texture if previewCmd is BOUNDING_BOX - no texturing happens there. TextureCacheCommon *texcache = gpuDebug->GetTextureCacheCommon(); TexCacheEntry *tex = texcache ? texcache->SetTexture() : nullptr; if (tex) { @@ -1369,8 +1361,11 @@ void ImGeDebuggerWindow::Draw(ImConfig &cfg, ImControl &control, GPUCommon *gpuD ImGui::Image(texId, ImVec2(texW, texH)); - // Show the preview as texcoords. TODO: We should probably use unclipped data here? - DrawPreviewPrimitive(drawList, p0, previewPrim_, previewIndices_, previewVertices_, previewIndexOffset_, previewTransformed_, true, texW, texH); + // Don't bother with trying to preview bounding box here, it only has positions, no texcoords. + if (previewCmd_ == GE_CMD_PRIM || previewCmd_ == GE_CMD_BEZIER || previewCmd_ == GE_CMD_SPLINE) { + // Show the preview as texcoords. TODO: We should probably use unclipped data here? + DrawPreviewPrimitive(drawList, p0, previewCmd_, previewPrim_, previewIndices_, previewVertices_, previewIndexOffset_, previewTransformed_, true, texW, texH); + } drawList->PopClipRect(); @@ -1705,7 +1700,7 @@ void ImGeStateWindow::Draw(ImConfig &cfg, ImControl &control, GPUCommon *gpuDebu ImGui::End(); } -void DrawImGeVertsWindow(ImConfig &cfg, ImControl &control, GPUCommon *gpuDebug) { +void DrawImGeVertsWindow(ImConfig &cfg, ImControl &control, GPUCommon *gpu) { ImGui::SetNextWindowSize(ImVec2(300, 500), ImGuiCond_FirstUseEver); if (!ImGui::Begin("GE Vertices", &cfg.geVertsOpen)) { ImGui::End(); @@ -1724,7 +1719,7 @@ void DrawImGeVertsWindow(ImConfig &cfg, ImControl &control, GPUCommon *gpuDebug) ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_ScrollY; if (ImGui::BeginTabBar("vertexmode", ImGuiTabBarFlags_None)) { - auto state = gpuDebug->GetGState(); + auto state = gpu->GetGState(); auto buildVertexTable = [&](bool transformed) { // Let's see if it's fast enough to just do all this each frame. GEPrimitiveType prim; @@ -1740,11 +1735,14 @@ void DrawImGeVertsWindow(ImConfig &cfg, ImControl &control, GPUCommon *gpuDebug) flags |= DebugVertexFlags::Clipped; } - int inputVertexCount = gpuDebug->GetCurrentPrimCount(&prim); + GECommand cmd; + int inputVertexCount = gpu->GetCurrentPrim(&prim, &cmd); + + // TODO: If cmd is BOUNDING_BOX, actually test the bounding box here and show the result. // This performs software transform, if transformed is checked. We might want to cache it? Although, it's only for a single draw... TransformStats stats; - if (!gpuDebug->GetCurrentDrawAsDebugVertices(prim, &prim, inputVertexCount, vertices, indices, &indexOffset, &stats, flags)) { + if (!gpu->GetCurrentDrawAsDebugVertices(cmd, prim, &prim, inputVertexCount, &vertices, &indices, &indexOffset, &stats, flags)) { inputVertexCount = 0; } @@ -1752,7 +1750,7 @@ void DrawImGeVertsWindow(ImConfig &cfg, ImControl &control, GPUCommon *gpuDebug) char statusLine[256]; StringWriter w(statusLine); - w.F("%s: ", GePrimTypeToString(prim)); + w.F("%s - %s: ", GeCmdToString(cmd), GePrimTypeToString(prim)); char fmtTemp[256]; FormatStateRow(fmtTemp, sizeof(fmtTemp), CMD_FMT_VERTEXTYPE, state.vertType, true, false, false); w.F("%s", fmtTemp); diff --git a/UI/ImDebugger/ImGe.h b/UI/ImDebugger/ImGe.h index c114ed92e9..4a6dd12a73 100644 --- a/UI/ImDebugger/ImGe.h +++ b/UI/ImDebugger/ImGe.h @@ -158,6 +158,7 @@ private: ImGePixelViewer swViewer_; int showBannerInFrames_ = 0; bool reloadPreview_ = false; + GECommand previewCmd_{}; GEPrimitiveType previewPrim_ = GEPrimitiveType::GE_PRIM_TRIANGLES; std::vector previewIndices_; std::vector previewVertices_; diff --git a/Windows/GEDebugger/TabVertices.cpp b/Windows/GEDebugger/TabVertices.cpp index c062d4d01f..799f8a15b2 100644 --- a/Windows/GEDebugger/TabVertices.cpp +++ b/Windows/GEDebugger/TabVertices.cpp @@ -200,7 +200,8 @@ int CtrlVertexList::GetRowCount() { auto state = gpu->GetGState(); GEPrimitiveType prim; - rowCount_ = gpu->GetCurrentPrimCount(&prim); + GECommand cmd; + rowCount_ = gpu->GetCurrentPrim(&prim, &cmd); previewIndexOffset_ = 0; @@ -213,7 +214,7 @@ int CtrlVertexList::GetRowCount() { } TransformStats stats; - if (!gpu->GetCurrentDrawAsDebugVertices(prim, &prim, rowCount_, vertices, indices, &previewIndexOffset_, &stats, flags)) { + if (!gpu->GetCurrentDrawAsDebugVertices(cmd, prim, &prim, rowCount_, &vertices, &indices, &previewIndexOffset_, &stats, flags)) { rowCount_ = 0; } diff --git a/Windows/GEDebugger/VertexPreview.cpp b/Windows/GEDebugger/VertexPreview.cpp index 078d3ee42b..9c3481c50f 100644 --- a/Windows/GEDebugger/VertexPreview.cpp +++ b/Windows/GEDebugger/VertexPreview.cpp @@ -99,7 +99,7 @@ void CGEDebugger::UpdatePrimPreview(u32 op, int which) { GEPrimitiveType prim; int previewIndexOffset; bool previewTransformed; - if (!GetPrimPreview(op, prim, vertices, indices, &previewIndexOffset, &previewTransformed)) { + if (!GetPrimPreview(op, &prim, &vertices, &indices, &previewIndexOffset, &previewTransformed)) { return; }