From 28b60a724f16da43923162a41c4277cd0b71a866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 24 Nov 2017 17:54:56 +0100 Subject: [PATCH 1/6] Process immediate draw commands. Not yet sending to graphics backends. --- GPU/Common/VertexDecoderCommon.h | 26 ++---------------- GPU/GPUCommon.cpp | 46 +++++++++++++++++++++++++------- GPU/GPUCommon.h | 34 +++++++++++++++++++++++ GPU/GPUState.h | 14 ++++++++-- 4 files changed, 84 insertions(+), 36 deletions(-) diff --git a/GPU/Common/VertexDecoderCommon.h b/GPU/Common/VertexDecoderCommon.h index fbe60c1756..2066defced 100644 --- a/GPU/Common/VertexDecoderCommon.h +++ b/GPU/Common/VertexDecoderCommon.h @@ -26,6 +26,8 @@ #include "Core/Reporting.h" #include "GPU/ge_constants.h" #include "GPU/Common/ShaderCommon.h" +#include "GPU/GPUCommon.h" + #if PPSSPP_ARCH(ARM) #include "Common/ArmEmitter.h" #elif PPSSPP_ARCH(ARM64) @@ -78,30 +80,6 @@ struct DecVtxFormat { void ComputeID(); }; -struct TransformedVertex -{ - union { - struct { - float x, y, z, fog; // in case of morph, preblend during decode - }; - float pos[4]; - }; - union { - struct { - float u; float v; float w; // scaled by uscale, vscale, if there - }; - float uv[3]; - }; - union { - u8 color0[4]; // prelit - u32 color0_32; - }; - union { - u8 color1[4]; // prelit - u32 color1_32; - }; -}; - void GetIndexBounds(const void *inds, int count, u32 vertType, u16 *indexLowerBound, u16 *indexUpperBound); inline int RoundUp4(int x) { diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 4a836550f1..23d9577725 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -303,16 +303,16 @@ const CommonCommandTableEntry commonCommandTable[] = { { GE_CMD_BONEMATRIXDATA, FLAG_EXECUTE, 0, &GPUCommon::Execute_BoneMtxData }, // Vertex Screen/Texture/Color - { GE_CMD_VSCX, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, - { GE_CMD_VSCY, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, - { GE_CMD_VSCZ, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, - { GE_CMD_VTCS, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, - { GE_CMD_VTCT, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, - { GE_CMD_VTCQ, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, - { GE_CMD_VCV, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, - { GE_CMD_VAP, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, - { GE_CMD_VFC, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, - { GE_CMD_VSCV, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_VSCX }, + { GE_CMD_VSCY }, + { GE_CMD_VSCZ }, + { GE_CMD_VTCS }, + { GE_CMD_VTCT }, + { GE_CMD_VTCQ }, + { GE_CMD_VCV }, + { GE_CMD_VAP, FLAG_EXECUTE, 0, &GPUCommon::Execute_ImmVertexAlphaPrim }, + { GE_CMD_VFC }, + { GE_CMD_VSCV }, // "Missing" commands (gaps in the sequence) { GE_CMD_UNKNOWN_03, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, @@ -1808,6 +1808,32 @@ void GPUCommon::Execute_MorphWeight(u32 op, u32 diff) { gstate_c.morphWeights[(op >> 24) - GE_CMD_MORPHWEIGHT0] = getFloat24(op); } +void GPUCommon::Execute_ImmVertexAlphaPrim(u32 op, u32 diff) { + uint32_t data = op & 0xFFFFFF; + TransformedVertex &v = immBuffer_[immCount_++]; + + // Formula deduced from ThrillVille's clear. + int offsetX = gstate.getOffsetX16(); + int offsetY = gstate.getOffsetY16(); + v.x = ((gstate.imm_vscx & 0xFFFFFF) - offsetX) / 16.0f; + v.y = ((gstate.imm_vscy & 0xFFFFFF) - offsetY) / 16.0f; + v.z = gstate.imm_vscz & 0xFFFF; + v.u = 0.0f; // we have no information about the scale here + v.v = 0.0f; // we have no information about the scale here + v.w = 0.0f; // we have no information about the scale here + v.color0_32 = (gstate.imm_cv & 0xFFFFFF) | (gstate.imm_ap << 24); + v.fog = 0.0f; // we have no information about the scale here + v.color1_32 = gstate.imm_scv & 0xFFFFFF; + int prim = (op >> 8) & 0xF; + if (prim != 7) { + immPrim_ = prim; + } else { + // Time to submit! This can go through the software transform path but skipping the actual transform... + // drawEngineCommon_->SubmitImm(immBuffer_, immCount_); + immCount_ = 0; + } +} + void GPUCommon::ExecuteOp(u32 op, u32 diff) { const u32 cmd = op >> 24; diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index c4d22dc904..41db2a9f3f 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -39,6 +39,29 @@ enum { FLAG_DIRTYONCHANGE = 64, // NOTE: Either this or FLAG_EXECUTE*, not both! }; +struct TransformedVertex { + union { + struct { + float x, y, z, fog; // in case of morph, preblend during decode + }; + float pos[4]; + }; + union { + struct { + float u; float v; float w; // scaled by uscale, vscale, if there + }; + float uv[3]; + }; + union { + u8 color0[4]; // prelit + u32 color0_32; + }; + union { + u8 color1[4]; // prelit + u32 color1_32; + }; +}; + class GPUCommon : public GPUInterface, public GPUDebugInterface { public: GPUCommon(GraphicsContext *gfxCtx, Draw::DrawContext *draw); @@ -124,6 +147,8 @@ public: void Execute_MorphWeight(u32 op, u32 diff); + void Execute_ImmVertexAlphaPrim(u32 op, u32 diff); + void Execute_Unknown(u32 op, u32 diff); int EstimatePerVertexCost(); @@ -291,6 +316,15 @@ protected: DrawType lastDraw_; GEPrimitiveType lastPrim_; + // No idea how big this buffer needs to be. + enum { + MAX_IMMBUFFER_SIZE = 32, + }; + + TransformedVertex immBuffer_[MAX_IMMBUFFER_SIZE]; + int immCount_ = 0; + int immPrim_ = 0; + private: // Debug stats. double timeSteppingStarted_; diff --git a/GPU/GPUState.h b/GPU/GPUState.h index a78aa10307..cd41c10a76 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -185,8 +185,18 @@ struct GPUgstate { transfersrcpos, transferdstpos, pad99, - transfersize; // 0xEE - + transfersize, // 0xEE + pad100, // 0xEF + imm_vscx, // 0xF0 + imm_vscy, + imm_vscz, + imm_vtcs, + imm_vtct, + imm_vtcq, + imm_cv, + imm_ap, + imm_fc, + imm_scv; u32 pad05[0xFF- 0xEE]; }; }; From f2db0339ade4e07f6ce8ebc7a0519dd661b89207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 24 Nov 2017 21:45:25 +0100 Subject: [PATCH 2/6] Hack that converts immediate draws to through-mode draws. This won't work correctly in all cases - but it's enough for Thrillville which uses it to clear only. Works around #7459. --- GPU/GPUCommon.cpp | 42 +++++++++++++++++++++++++++++++++++++----- GPU/GPUCommon.h | 3 ++- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 23d9577725..4b2e21e33c 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1826,14 +1826,46 @@ void GPUCommon::Execute_ImmVertexAlphaPrim(u32 op, u32 diff) { v.color1_32 = gstate.imm_scv & 0xFFFFFF; int prim = (op >> 8) & 0xF; if (prim != 7) { - immPrim_ = prim; - } else { - // Time to submit! This can go through the software transform path but skipping the actual transform... - // drawEngineCommon_->SubmitImm(immBuffer_, immCount_); - immCount_ = 0; + immPrim_ = (GEPrimitiveType)prim; + } else if (prim == 7 && immCount_ == 2) { + FlushImm(); } } +void GPUCommon::FlushImm() { + SetDrawType(DRAW_PRIM, immPrim_); + framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason); + if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) { + // No idea how many cycles to skip, heh. + return; + } + UpdateUVScaleOffset(); + // Instead of finding a proper point to flush, we just emit a full rectangle every time one + // is finished. + + // And instead of plumbing through, we'll cheat and just turn these into through vertices. + // Since the only known use is Thrillville and it only uses it to clear, we just use color and pos. + struct ImmVertex { + uint32_t color; + float xyz[3]; + }; + ImmVertex temp[MAX_IMMBUFFER_SIZE]; + for (int i = 0; i < immCount_; i++) { + temp[i].color = immBuffer_[i].color0_32; + temp[i].xyz[0] = immBuffer_[i].pos[0]; + temp[i].xyz[1] = immBuffer_[i].pos[1]; + temp[i].xyz[2] = immBuffer_[i].pos[2]; + } + int vtype = GE_VTYPE_POS_FLOAT | GE_VTYPE_COL_8888 | GE_VTYPE_THROUGH; + + int bytesRead; + drawEngineCommon_->DispatchSubmitPrim(temp, nullptr, immPrim_, immCount_, vtype, &bytesRead); + drawEngineCommon_->DispatchFlush(); + // TOOD: In the future, make a special path for these. + // drawEngineCommon_->DispatchSubmitImm(immBuffer_, immCount_); + immCount_ = 0; +} + void GPUCommon::ExecuteOp(u32 op, u32 diff) { const u32 cmd = op >> 24; diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 41db2a9f3f..784293578c 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -323,9 +323,10 @@ protected: TransformedVertex immBuffer_[MAX_IMMBUFFER_SIZE]; int immCount_ = 0; - int immPrim_ = 0; + GEPrimitiveType immPrim_; private: + void FlushImm(); // Debug stats. double timeSteppingStarted_; double timeSpentStepping_; From ed2028aa5e0e3c1e9b774d2631e78df21b33dd61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 24 Nov 2017 21:55:25 +0100 Subject: [PATCH 3/6] Add safety check. --- GPU/GPUCommon.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 4b2e21e33c..d4450af033 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1809,6 +1809,10 @@ void GPUCommon::Execute_MorphWeight(u32 op, u32 diff) { } void GPUCommon::Execute_ImmVertexAlphaPrim(u32 op, u32 diff) { + // Safety check. + if (immCount_ >= MAX_IMMBUFFER_SIZE) + return; + uint32_t data = op & 0xFFFFFF; TransformedVertex &v = immBuffer_[immCount_++]; From 5c9436f2760c022b8181a42b7aa613291e91812e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 24 Nov 2017 21:58:55 +0100 Subject: [PATCH 4/6] Fix some comments --- GPU/GPUCommon.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index d4450af033..aa156543f2 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1832,6 +1832,8 @@ void GPUCommon::Execute_ImmVertexAlphaPrim(u32 op, u32 diff) { if (prim != 7) { immPrim_ = (GEPrimitiveType)prim; } else if (prim == 7 && immCount_ == 2) { + // Instead of finding a proper point to flush, we just emit a full rectangle every time one + // is finished. FlushImm(); } } @@ -1844,10 +1846,10 @@ void GPUCommon::FlushImm() { return; } UpdateUVScaleOffset(); - // Instead of finding a proper point to flush, we just emit a full rectangle every time one - // is finished. - // And instead of plumbing through, we'll cheat and just turn these into through vertices. + // Instead of plumbing through properly (we'd need to inject these pretransformed vertices in the middle + // of SoftwareTransform(), which would take a lot of refactoring), we'll cheat and just turn these into + // through vertices. // Since the only known use is Thrillville and it only uses it to clear, we just use color and pos. struct ImmVertex { uint32_t color; From b52b8b1329e05c4fdb0674013a2729f44d6a270f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 25 Nov 2017 12:13:02 +0100 Subject: [PATCH 5/6] Unbreak save states, fix other minor issues from review --- GPU/GPUCommon.cpp | 23 ++++++++++++++++------- GPU/GPUState.h | 5 +++-- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index aa156543f2..3e37f99075 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1810,8 +1810,15 @@ void GPUCommon::Execute_MorphWeight(u32 op, u32 diff) { void GPUCommon::Execute_ImmVertexAlphaPrim(u32 op, u32 diff) { // Safety check. - if (immCount_ >= MAX_IMMBUFFER_SIZE) + if (immCount_ >= MAX_IMMBUFFER_SIZE) { + // Only print once for each overrun. + if (immCount_ == MAX_IMMBUFFER_SIZE) { + ERROR_LOG_REPORT_ONCE(exceed_imm_buffer, G3D, "Exceeded immediate draw buffer size"); + } + if (immCount_ < 0x7fffffff) // Paranoia :) + immCount_++; return; + } uint32_t data = op & 0xFFFFFF; TransformedVertex &v = immBuffer_[immCount_++]; @@ -1822,19 +1829,21 @@ void GPUCommon::Execute_ImmVertexAlphaPrim(u32 op, u32 diff) { v.x = ((gstate.imm_vscx & 0xFFFFFF) - offsetX) / 16.0f; v.y = ((gstate.imm_vscy & 0xFFFFFF) - offsetY) / 16.0f; v.z = gstate.imm_vscz & 0xFFFF; - v.u = 0.0f; // we have no information about the scale here - v.v = 0.0f; // we have no information about the scale here - v.w = 0.0f; // we have no information about the scale here + v.u = getFloat24(gstate.imm_vtcs); + v.v = getFloat24(gstate.imm_vtct); + v.w = getFloat24(gstate.imm_vtcq); v.color0_32 = (gstate.imm_cv & 0xFFFFFF) | (gstate.imm_ap << 24); v.fog = 0.0f; // we have no information about the scale here v.color1_32 = gstate.imm_scv & 0xFFFFFF; - int prim = (op >> 8) & 0xF; - if (prim != 7) { + int prim = (op >> 8) & 0x7; + if (prim != GE_PRIM_KEEP_PREVIOUS) { immPrim_ = (GEPrimitiveType)prim; - } else if (prim == 7 && immCount_ == 2) { + } else if (prim == GE_PRIM_KEEP_PREVIOUS && immCount_ == 2) { // Instead of finding a proper point to flush, we just emit a full rectangle every time one // is finished. FlushImm(); + } else { + ERROR_LOG_REPORT_ONCE(imm_draw_prim, G3D, "Immediate draw: Unexpected primitive %d at count %d", prim, immCount_); } } diff --git a/GPU/GPUState.h b/GPU/GPUState.h index cd41c10a76..c67db91dfe 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -196,8 +196,9 @@ struct GPUgstate { imm_cv, imm_ap, imm_fc, - imm_scv; - u32 pad05[0xFF- 0xEE]; + imm_scv; // 0xF9 + // In the unlikely case we ever add anything else here, don't forget to update the padding on the next line! + u32 pad05[0xFF- 0xF9]; }; }; From 89f0ffc1bcef95bba47eadda4ca7933b19266115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 25 Nov 2017 12:13:27 +0100 Subject: [PATCH 6/6] Just reduce some log levels --- Core/HLE/sceIo.cpp | 2 +- Core/HLE/scePower.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index ead6f487a5..b778a3af00 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -2330,7 +2330,7 @@ static int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, case 0x01020004: // TODO: Should not work for umd0:/, ms0:/, etc. // TODO: Should probably move this to something common between ISOFileSystem and VirtualDiscSystem. - INFO_LOG(SCEIO, "sceIoIoctl: Asked for file offset of file %i", id); + DEBUG_LOG(SCEIO, "sceIoIoctl: Asked for file offset of file %d", id); if (Memory::IsValidAddress(outdataPtr) && outlen >= 4) { u32 offset = (u32)pspFileSystem.GetSeekPos(f->handle); Memory::Write_U32(offset, outdataPtr); diff --git a/Core/HLE/scePower.cpp b/Core/HLE/scePower.cpp index 9e85693f67..8204a51c58 100644 --- a/Core/HLE/scePower.cpp +++ b/Core/HLE/scePower.cpp @@ -431,7 +431,7 @@ static u32 scePowerSetBusClockFrequency(u32 busfreq) { static u32 scePowerGetCpuClockFrequencyInt() { int cpuFreq = CoreTiming::GetClockFrequencyMHz(); - INFO_LOG(HLE,"%i=scePowerGetCpuClockFrequencyInt()", cpuFreq); + DEBUG_LOG(HLE,"%i=scePowerGetCpuClockFrequencyInt()", cpuFreq); return cpuFreq; } @@ -447,7 +447,7 @@ static u32 scePowerGetBusClockFrequencyInt() { static float scePowerGetCpuClockFrequencyFloat() { int cpuFreq = CoreTiming::GetClockFrequencyMHz(); - INFO_LOG(HLE, "%f=scePowerGetCpuClockFrequencyFloat()", (float)cpuFreq); + DEBUG_LOG(HLE, "%f=scePowerGetCpuClockFrequencyFloat()", (float)cpuFreq); return (float) cpuFreq; }