From d2150cda68fa9cf74ec8550c4d6a412065efb51c 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] 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. --- Core/HLE/sceIo.cpp | 2 +- Core/MIPS/x86/JitSafeMem.cpp | 2 ++ GPU/Common/DrawEngineCommon.h | 2 ++ GPU/GPUCommon.cpp | 42 +++++++++++++++++++++++++++++---- GPU/GPUCommon.h | 3 ++- GPU/Vulkan/DrawEngineVulkan.cpp | 4 ++++ GPU/Vulkan/DrawEngineVulkan.h | 6 +++++ 7 files changed, 54 insertions(+), 7 deletions(-) diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index ead6f487a552..f22bf20493d2 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(0x01020004): 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/MIPS/x86/JitSafeMem.cpp b/Core/MIPS/x86/JitSafeMem.cpp index 339f5e0ec1b4..c16f5a0e16db 100644 --- a/Core/MIPS/x86/JitSafeMem.cpp +++ b/Core/MIPS/x86/JitSafeMem.cpp @@ -78,6 +78,8 @@ bool JitSafeMem::PrepareWrite(OpArg &dest, int size) { MemCheckImm(MEM_WRITE); u32 addr = (iaddr_ & alignMask_); + _dbg_assert_msg_(JIT, Memory::IsValidAddress(addr), "Memory access - invalid address! %08x", addr); + #ifdef MASKED_PSP_MEMORY addr &= Memory::MEMVIEW32_MASK; #endif diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 961e5dad5ea6..547faf3f16b1 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -63,6 +63,8 @@ class DrawEngineCommon { 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); + virtual void DispatchSubmitImm(const TransformedVertex *transformed, int count, GEPrimitiveType prim) {} + std::vector DebugGetVertexLoaderIDs(); std::string DebugGetVertexLoaderString(std::string id, DebugShaderStringType stringType); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 23d9577725e8..4b2e21e33c3e 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 41db2a9f3f08..784293578cc5 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -323,9 +323,10 @@ class GPUCommon : public GPUInterface, public GPUDebugInterface { TransformedVertex immBuffer_[MAX_IMMBUFFER_SIZE]; int immCount_ = 0; - int immPrim_ = 0; + GEPrimitiveType immPrim_; private: + void FlushImm(); // Debug stats. double timeSteppingStarted_; double timeSpentStepping_; diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 82908e0048ed..e021571ab206 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -593,6 +593,10 @@ void MarkUnreliable(VertexArrayInfoVulkan *vai) { // For now we just leave it in the pushbuffer. } +void DrawEngineVulkan::SubmitImm(const TransformedVertex *transformed, int count, GEPrimitiveType prim) { + +} + // The inline wrapper in the header checks for numDrawCalls == 0 void DrawEngineVulkan::DoFlush() { PROFILE_THIS_SCOPE("Flush"); diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index e6dc71e8f15e..dd1c76f1a6ec 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -184,7 +184,13 @@ class DrawEngineVulkan : public DrawEngineCommon { void SetLineWidth(float lineWidth); + void DispatchSubmitImm(const TransformedVertex *transformed, int count, GEPrimitiveType prim) override { + SubmitImm(transformed, count, prim); + } + private: + void SubmitImm(const TransformedVertex *transformed, int count, GEPrimitiveType prim); + struct FrameData; void ApplyDrawStateLate(VulkanRenderManager *renderManager, bool applyStencilRef, uint8_t stencilRef, bool useBlendConstant); void ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManager, ShaderManagerVulkan *shaderManager, int prim, VulkanPipelineRasterStateKey &key, VulkanDynamicState &dynState);