diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index 80eaf2ea4a..fd31925077 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -314,7 +314,6 @@ public: const VkPhysicalDeviceFeatures &GetFeaturesEnabled() const { return featuresEnabled_; } const VulkanPhysicalDeviceInfo &GetDeviceInfo() const { return deviceInfo_; } - private: VkSemaphore acquireSemaphore; VkSemaphore renderingCompleteSemaphore; @@ -381,7 +380,6 @@ private: VulkanDeleteList deleteList; }; - FrameData frame_[2]; int curFrame_; diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 75ac25c4d1..b21e0e957d 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -73,6 +73,7 @@ struct D3D11CommandTableEntry { GPU_D3D11::CmdFunc func; }; +// This table gets crunched into a faster form by init. static const D3D11CommandTableEntry commandTable[] = { // Changes that dirty the current texture. { GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_D3D11::Execute_TexSize0 }, @@ -88,7 +89,6 @@ static const D3D11CommandTableEntry commandTable[] = { // Changes that trigger data copies. Only flushing on change for LOADCLUT must be a bit of a hack... { GE_CMD_LOADCLUT, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_D3D11::Execute_LoadClut }, - { GE_CMD_TRANSFERSTART, FLAG_FLUSHBEFORE | FLAG_EXECUTE | FLAG_READS_PC, 0, &GPUCommon::Execute_BlockTransferStart }, }; GPU_D3D11::CommandInfo GPU_D3D11::cmdInfo_[256]{}; @@ -389,27 +389,38 @@ void GPU_D3D11::CopyDisplayToOutputInternal() { void GPU_D3D11::FastRunLoop(DisplayList &list) { PROFILE_THIS_SCOPE("gpuloop"); const CommandInfo *cmdInfo = cmdInfo_; - for (; downcount > 0; --downcount) { + int dc = downcount; + for (; dc > 0; --dc) { // We know that display list PCs have the upper nibble == 0 - no need to mask the pointer const u32 op = *(const u32 *)(Memory::base + list.pc); const u32 cmd = op >> 24; - const CommandInfo info = cmdInfo[cmd]; - const u8 cmdFlags = info.flags; // If we stashed the cmdFlags in the top bits of the cmdmem, we could get away with one table lookup instead of two + const CommandInfo &info = cmdInfo[cmd]; const u32 diff = op ^ gstate.cmdmem[cmd]; - // Inlined CheckFlushOp here to get rid of the dumpThisFrame_ check. - if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) { - drawEngine_.Flush(); - } - gstate.cmdmem[cmd] = op; // TODO: no need to write if diff==0... - if ((cmdFlags & FLAG_EXECUTE) || (diff && (cmdFlags & FLAG_EXECUTEONCHANGE))) { - (this->*info.func)(op, diff); - } else if (diff) { - uint64_t dirty = info.flags >> 8; - if (dirty) - gstate_c.Dirty(dirty); + if (diff == 0) { + if (info.flags & FLAG_EXECUTE) { + downcount = dc; + (this->*info.func)(op, diff); + dc = downcount; + } + } else { + uint64_t flags = info.flags; + if (flags & FLAG_FLUSHBEFOREONCHANGE) { + drawEngine_.Flush(); + } + gstate.cmdmem[cmd] = op; + if (flags & (FLAG_EXECUTE | FLAG_EXECUTEONCHANGE)) { + downcount = dc; + (this->*info.func)(op, diff); + dc = downcount; + } else { + uint64_t dirty = flags >> 8; + if (dirty) + gstate_c.Dirty(dirty); + } } list.pc += 4; } + downcount = 0; } void GPU_D3D11::FinishDeferred() { @@ -533,6 +544,7 @@ void GPU_D3D11::Execute_Prim(u32 op, u32 diff) { #endif int bytesRead = 0; + UpdateUVScaleOffset(); drawEngine_.SubmitPrim(verts, inds, prim, count, vertexType, &bytesRead); int vertexCost = EstimatePerVertexCost() * count; @@ -546,6 +558,8 @@ void GPU_D3D11::Execute_Prim(u32 op, u32 diff) { } void GPU_D3D11::Execute_Bezier(u32 op, u32 diff) { + Flush(); + // We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier. gstate_c.Dirty(DIRTY_UVSCALEOFFSET); @@ -596,6 +610,7 @@ void GPU_D3D11::Execute_Bezier(u32 op, u32 diff) { } int bytesRead = 0; + UpdateUVScaleOffset(); drawEngine_.SubmitBezier(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), bz_ucount, bz_vcount, patchPrim, computeNormals, patchFacing, gstate.vertType, &bytesRead); if (gstate_c.bezier) @@ -608,6 +623,8 @@ void GPU_D3D11::Execute_Bezier(u32 op, u32 diff) { } void GPU_D3D11::Execute_Spline(u32 op, u32 diff) { + Flush(); + // We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier. gstate_c.Dirty(DIRTY_UVSCALEOFFSET); @@ -664,6 +681,7 @@ void GPU_D3D11::Execute_Spline(u32 op, u32 diff) { } } int bytesRead = 0; + UpdateUVScaleOffset(); drawEngine_.SubmitSpline(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), sp_ucount, sp_vcount, sp_utype, sp_vtype, patchPrim, computeNormals, patchFacing, vertType, &bytesRead); if (gstate_c.spline) diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index 2029a9b123..2ca25db5cc 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -57,6 +57,7 @@ struct D3D9CommandTableEntry { GPU_DX9::CmdFunc func; }; +// This table gets crunched into a faster form by init. static const D3D9CommandTableEntry commandTable[] = { // Changes that dirty the current texture. { GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_DX9::Execute_TexSize0 }, @@ -72,7 +73,6 @@ static const D3D9CommandTableEntry commandTable[] = { // Changes that trigger data copies. Only flushing on change for LOADCLUT must be a bit of a hack... { GE_CMD_LOADCLUT, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_DX9::Execute_LoadClut }, - { GE_CMD_TRANSFERSTART, FLAG_FLUSHBEFORE | FLAG_EXECUTE | FLAG_READS_PC, 0, &GPUCommon::Execute_BlockTransferStart }, }; GPU_DX9::CommandInfo GPU_DX9::cmdInfo_[256]; @@ -356,27 +356,38 @@ void GPU_DX9::CopyDisplayToOutputInternal() { void GPU_DX9::FastRunLoop(DisplayList &list) { PROFILE_THIS_SCOPE("gpuloop"); const CommandInfo *cmdInfo = cmdInfo_; - for (; downcount > 0; --downcount) { + int dc = downcount; + for (; dc > 0; --dc) { // We know that display list PCs have the upper nibble == 0 - no need to mask the pointer const u32 op = *(const u32 *)(Memory::base + list.pc); const u32 cmd = op >> 24; - const CommandInfo info = cmdInfo[cmd]; - const u8 cmdFlags = info.flags; // If we stashed the cmdFlags in the top bits of the cmdmem, we could get away with one table lookup instead of two + const CommandInfo &info = cmdInfo[cmd]; const u32 diff = op ^ gstate.cmdmem[cmd]; - // Inlined CheckFlushOp here to get rid of the dumpThisFrame_ check. - if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) { - drawEngine_.Flush(); - } - gstate.cmdmem[cmd] = op; // TODO: no need to write if diff==0... - if ((cmdFlags & FLAG_EXECUTE) || (diff && (cmdFlags & FLAG_EXECUTEONCHANGE))) { - (this->*info.func)(op, diff); - } else if (diff) { - uint64_t dirty = info.flags >> 8; - if (dirty) - gstate_c.Dirty(dirty); + if (diff == 0) { + if (info.flags & FLAG_EXECUTE) { + downcount = dc; + (this->*info.func)(op, diff); + dc = downcount; + } + } else { + uint64_t flags = info.flags; + if (flags & FLAG_FLUSHBEFOREONCHANGE) { + drawEngine_.Flush(); + } + gstate.cmdmem[cmd] = op; + if (flags & (FLAG_EXECUTE | FLAG_EXECUTEONCHANGE)) { + downcount = dc; + (this->*info.func)(op, diff); + dc = downcount; + } else { + uint64_t dirty = flags >> 8; + if (dirty) + gstate_c.Dirty(dirty); + } } list.pc += 4; } + downcount = 0; } void GPU_DX9::FinishDeferred() { @@ -386,7 +397,7 @@ void GPU_DX9::FinishDeferred() { inline void GPU_DX9::CheckFlushOp(int cmd, u32 diff) { const u8 cmdFlags = cmdInfo_[cmd].flags; - if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) { + if (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE)) { if (dumpThisFrame_) { NOTICE_LOG(G3D, "================ FLUSH ================"); } @@ -499,6 +510,7 @@ void GPU_DX9::Execute_Prim(u32 op, u32 diff) { #endif int bytesRead = 0; + UpdateUVScaleOffset(); drawEngine_.SubmitPrim(verts, inds, prim, count, vertexType, &bytesRead); int vertexCost = EstimatePerVertexCost() * count; @@ -512,6 +524,8 @@ void GPU_DX9::Execute_Prim(u32 op, u32 diff) { } void GPU_DX9::Execute_Bezier(u32 op, u32 diff) { + Flush(); + // We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier. gstate_c.Dirty(DIRTY_UVSCALEOFFSET); @@ -551,6 +565,7 @@ void GPU_DX9::Execute_Bezier(u32 op, u32 diff) { bool computeNormals = gstate.isLightingEnabled(); bool patchFacing = gstate.patchfacing & 1; int bytesRead = 0; + UpdateUVScaleOffset(); 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. @@ -559,6 +574,8 @@ void GPU_DX9::Execute_Bezier(u32 op, u32 diff) { } void GPU_DX9::Execute_Spline(u32 op, u32 diff) { + Flush(); + // We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier. gstate_c.Dirty(DIRTY_UVSCALEOFFSET); @@ -601,6 +618,7 @@ void GPU_DX9::Execute_Spline(u32 op, u32 diff) { bool patchFacing = gstate.patchfacing & 1; u32 vertType = gstate.vertType; int bytesRead = 0; + UpdateUVScaleOffset(); drawEngine_.SubmitSpline(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), sp_ucount, sp_vcount, sp_utype, sp_vtype, patchPrim, computeNormals, patchFacing, vertType, &bytesRead); // After drawing, we advance pointers - see SubmitPrim which does the same. diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 83914e8871..27b911f1b9 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -76,7 +76,6 @@ static const GLESCommandTableEntry commandTable[] = { // Changes that trigger data copies. Only flushing on change for LOADCLUT must be a bit of a hack... { GE_CMD_LOADCLUT, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_GLES::Execute_LoadClut }, - { GE_CMD_TRANSFERSTART, FLAG_FLUSHBEFORE | FLAG_EXECUTE | FLAG_READS_PC, 0, &GPUCommon::Execute_BlockTransferStart }, }; GPU_GLES::CommandInfo GPU_GLES::cmdInfo_[256]; @@ -567,22 +566,29 @@ void GPU_GLES::FastRunLoop(DisplayList &list) { // We know that display list PCs have the upper nibble == 0 - no need to mask the pointer const u32 op = *(const u32 *)(Memory::base + list.pc); const u32 cmd = op >> 24; - const CommandInfo info = cmdInfo[cmd]; - const u8 cmdFlags = info.flags; // If we stashed the cmdFlags in the top bits of the cmdmem, we could get away with one table lookup instead of two + const CommandInfo &info = cmdInfo[cmd]; const u32 diff = op ^ gstate.cmdmem[cmd]; - // Inlined CheckFlushOp here to get rid of the dumpThisFrame_ check. - if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) { - drawEngine_.Flush(); - } - gstate.cmdmem[cmd] = op; // TODO: no need to write if diff==0... - if ((cmdFlags & FLAG_EXECUTE) || (diff && (cmdFlags & FLAG_EXECUTEONCHANGE))) { - downcount = dc; - (this->*info.func)(op, diff); - dc = downcount; - } else if (diff) { - uint64_t dirty = info.flags >> 8; - if (dirty) - gstate_c.Dirty(dirty); + if (diff == 0) { + if (info.flags & FLAG_EXECUTE) { + downcount = dc; + (this->*info.func)(op, diff); + dc = downcount; + } + } else { + uint64_t flags = info.flags; + if (flags & FLAG_FLUSHBEFOREONCHANGE) { + drawEngine_.Flush(); + } + gstate.cmdmem[cmd] = op; + if (flags & (FLAG_EXECUTE | FLAG_EXECUTEONCHANGE)) { + downcount = dc; + (this->*info.func)(op, diff); + dc = downcount; + } else { + uint64_t dirty = flags >> 8; + if (dirty) + gstate_c.Dirty(dirty); + } } list.pc += 4; } @@ -596,7 +602,7 @@ void GPU_GLES::FinishDeferred() { inline void GPU_GLES::CheckFlushOp(int cmd, u32 diff) { const u8 cmdFlags = cmdInfo_[cmd].flags; - if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) { + if (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE)) { if (dumpThisFrame_) { NOTICE_LOG(G3D, "================ FLUSH ================"); } @@ -676,6 +682,7 @@ void GPU_GLES::Execute_Prim(u32 op, u32 diff) { #endif int bytesRead = 0; + UpdateUVScaleOffset(); drawEngine_.SubmitPrim(verts, inds, prim, count, gstate.vertType, &bytesRead); int vertexCost = EstimatePerVertexCost(); @@ -720,6 +727,8 @@ void GPU_GLES::Execute_VertexTypeSkinning(u32 op, u32 diff) { } void GPU_GLES::Execute_Bezier(u32 op, u32 diff) { + Flush(); + // We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier. gstate_c.Dirty(DIRTY_UVSCALEOFFSET); @@ -770,6 +779,7 @@ void GPU_GLES::Execute_Bezier(u32 op, u32 diff) { } int bytesRead = 0; + UpdateUVScaleOffset(); drawEngine_.SubmitBezier(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), bz_ucount, bz_vcount, patchPrim, computeNormals, patchFacing, gstate.vertType, &bytesRead); if (gstate_c.bezier) @@ -782,6 +792,8 @@ void GPU_GLES::Execute_Bezier(u32 op, u32 diff) { } void GPU_GLES::Execute_Spline(u32 op, u32 diff) { + Flush(); + // We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier. gstate_c.Dirty(DIRTY_UVSCALEOFFSET); @@ -839,6 +851,7 @@ void GPU_GLES::Execute_Spline(u32 op, u32 diff) { } int bytesRead = 0; + UpdateUVScaleOffset(); drawEngine_.SubmitSpline(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), sp_ucount, sp_vcount, sp_utype, sp_vtype, patchPrim, computeNormals, patchFacing, vertType, &bytesRead); if (gstate_c.spline) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index b29d8370cc..ddab4454bf 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -111,10 +111,12 @@ const CommonCommandTableEntry commonCommandTable[] = { { GE_CMD_LOGICOPENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE }, { GE_CMD_TEXMAPMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE }, - { GE_CMD_TEXSCALEU, FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_TexScaleU }, - { GE_CMD_TEXSCALEV, FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_TexScaleV }, - { GE_CMD_TEXOFFSETU, FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_TexOffsetU }, - { GE_CMD_TEXOFFSETV, FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_TexOffsetV }, + + // These are read on every SubmitPrim, no need for dirtying or flushing. + { GE_CMD_TEXSCALEU }, + { GE_CMD_TEXSCALEV }, + { GE_CMD_TEXOFFSETU }, + { GE_CMD_TEXOFFSETV }, // TEXSIZE0 is handled by each backend. { GE_CMD_TEXSIZE1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, @@ -278,6 +280,7 @@ const CommonCommandTableEntry commonCommandTable[] = { { GE_CMD_TRANSFERSRCPOS, 0 }, { GE_CMD_TRANSFERDSTPOS, 0 }, { GE_CMD_TRANSFERSIZE, 0 }, + { GE_CMD_TRANSFERSTART, FLAG_FLUSHBEFORE | FLAG_EXECUTE | FLAG_READS_PC, 0, &GPUCommon::Execute_BlockTransferStart }, // We don't use the dither table. { GE_CMD_DITH0 }, @@ -1267,6 +1270,8 @@ void GPUCommon::Execute_Ret(u32 op, u32 diff) { } void GPUCommon::Execute_End(u32 op, u32 diff) { + Flush(); + easy_guard guard(listLock); const u32 prev = Memory::ReadUnchecked_U32(currentList->pc - 4); UpdatePC(currentList->pc, currentList->pc); @@ -1423,22 +1428,6 @@ void GPUCommon::Execute_End(u32 op, u32 diff) { } } -void GPUCommon::Execute_TexScaleU(u32 op, u32 diff) { - gstate_c.uv.uScale = getFloat24(op); -} - -void GPUCommon::Execute_TexScaleV(u32 op, u32 diff) { - gstate_c.uv.vScale = getFloat24(op); -} - -void GPUCommon::Execute_TexOffsetU(u32 op, u32 diff) { - gstate_c.uv.uOff = getFloat24(op); -} - -void GPUCommon::Execute_TexOffsetV(u32 op, u32 diff) { - gstate_c.uv.vOff = getFloat24(op); -} - void GPUCommon::Execute_TexLevel(u32 op, u32 diff) { if (diff == 0xFFFFFFFF) return; @@ -1451,6 +1440,7 @@ void GPUCommon::Execute_TexLevel(u32 op, u32 diff) { } void GPUCommon::Execute_Bezier(u32 op, u32 diff) { + Flush(); // This also make skipping drawing very effective. framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason); if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) { @@ -1494,6 +1484,7 @@ void GPUCommon::Execute_Bezier(u32 op, u32 diff) { } void GPUCommon::Execute_Spline(u32 op, u32 diff) { + Flush(); // This also make skipping drawing very effective. framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason); if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) { @@ -1568,6 +1559,7 @@ void GPUCommon::Execute_BoundingBox(u32 op, u32 diff) { } void GPUCommon::Execute_BlockTransferStart(u32 op, u32 diff) { + Flush(); // and take appropriate action. This is a block transfer between RAM and VRAM, or vice versa. // Can we skip this on SkipDraw? DoBlockTransfer(gstate_c.skipDrawReason); diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index ca2d8ac931..529032ce47 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -9,7 +9,9 @@ #if defined(__ANDROID__) #include -#elif defined(_M_SSE) +#endif + +#if defined(_M_SSE) #include #endif @@ -196,6 +198,21 @@ public: GPUgstate GetGState() override; void SetCmdValue(u32 op) override; + void UpdateUVScaleOffset() { +#ifdef _M_SSE + __m128i values = _mm_slli_epi32(_mm_load_si128((const __m128i *)&gstate.texscaleu), 8); + _mm_storeu_si128((__m128i *)&gstate_c.uv, values); +#elif PPSSPP_PLATFORM(ARM_NEON) + const uint32x4_t values = vshlq_n_u32(vld1q_u32(&gstate.texscaleu), 8); + vst1q_u32(&gstate_c.uv, values); +#else + gstate_c.uv.uScale = getFloat24(gstate.texscaleu); + gstate_c.uv.vScale = getFloat24(gstate.texscalev); + gstate_c.uv.uOff = getFloat24(gstate.texoffsetu); + gstate_c.uv.vOff = getFloat24(gstate.texoffsetv); +#endif + } + DisplayList* getList(int listid) override { return &dls[listid]; } diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index fe4c87ec6b..13761165da 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -56,7 +56,6 @@ struct VulkanCommandTableEntry { GPU_Vulkan::CommandInfo GPU_Vulkan::cmdInfo_[256]; // This table gets crunched into a faster form by init. -// TODO: Share this table between the backends. Will have to make another indirection for the function pointers though.. static const VulkanCommandTableEntry commandTable[] = { // Changes that dirty the current texture. { GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_Vulkan::Execute_TexSize0 }, @@ -72,7 +71,6 @@ static const VulkanCommandTableEntry commandTable[] = { // Changes that trigger data copies. Only flushing on change for LOADCLUT must be a bit of a hack... { GE_CMD_LOADCLUT, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_Vulkan::Execute_LoadClut }, - { GE_CMD_TRANSFERSTART, FLAG_FLUSHBEFORE | FLAG_EXECUTE | FLAG_READS_PC, 0, &GPUCommon::Execute_BlockTransferStart }, }; GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw) @@ -398,22 +396,29 @@ void GPU_Vulkan::FastRunLoop(DisplayList &list) { // We know that display list PCs have the upper nibble == 0 - no need to mask the pointer const u32 op = *(const u32 *)(Memory::base + list.pc); const u32 cmd = op >> 24; - const CommandInfo info = cmdInfo[cmd]; - const u8 cmdFlags = info.flags; // If we stashed the cmdFlags in the top bits of the cmdmem, we could get away with one table lookup instead of two + const CommandInfo &info = cmdInfo[cmd]; const u32 diff = op ^ gstate.cmdmem[cmd]; - // Inlined CheckFlushOp here to get rid of the dumpThisFrame_ check. - if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) { - drawEngine_.Flush(); - } - gstate.cmdmem[cmd] = op; // TODO: no need to write if diff==0... - if ((cmdFlags & FLAG_EXECUTE) || (diff && (cmdFlags & FLAG_EXECUTEONCHANGE))) { - downcount = dc; - (this->*info.func)(op, diff); - dc = downcount; - } else if (diff) { - uint64_t dirty = info.flags >> 8; - if (dirty) - gstate_c.Dirty(dirty); + if (diff == 0) { + if (info.flags & FLAG_EXECUTE) { + downcount = dc; + (this->*info.func)(op, diff); + dc = downcount; + } + } else { + uint64_t flags = info.flags; + if (flags & FLAG_FLUSHBEFOREONCHANGE) { + drawEngine_.Flush(); + } + gstate.cmdmem[cmd] = op; + if (flags & (FLAG_EXECUTE | FLAG_EXECUTEONCHANGE)) { + downcount = dc; + (this->*info.func)(op, diff); + dc = downcount; + } else { + uint64_t dirty = flags >> 8; + if (dirty) + gstate_c.Dirty(dirty); + } } list.pc += 4; } @@ -507,6 +512,7 @@ void GPU_Vulkan::Execute_Prim(u32 op, u32 diff) { #endif int bytesRead = 0; + UpdateUVScaleOffset(); drawEngine_.SubmitPrim(verts, inds, prim, count, gstate.vertType, &bytesRead); int vertexCost = EstimatePerVertexCost() * count; @@ -551,6 +557,8 @@ void GPU_Vulkan::Execute_VertexTypeSkinning(u32 op, u32 diff) { } void GPU_Vulkan::Execute_Bezier(u32 op, u32 diff) { + Flush(); + // We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier. gstate_c.Dirty(DIRTY_UVSCALEOFFSET); @@ -601,6 +609,7 @@ void GPU_Vulkan::Execute_Bezier(u32 op, u32 diff) { } } + UpdateUVScaleOffset(); drawEngine_.SubmitBezier(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), bz_ucount, bz_vcount, patchPrim, computeNormals, patchFacing, gstate.vertType, &bytesRead); if (gstate_c.bezier) @@ -613,6 +622,8 @@ void GPU_Vulkan::Execute_Bezier(u32 op, u32 diff) { } void GPU_Vulkan::Execute_Spline(u32 op, u32 diff) { + Flush(); + // We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier. gstate_c.Dirty(DIRTY_UVSCALEOFFSET); @@ -670,6 +681,7 @@ void GPU_Vulkan::Execute_Spline(u32 op, u32 diff) { } int bytesRead = 0; + UpdateUVScaleOffset(); drawEngine_.SubmitSpline(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), sp_ucount, sp_vcount, sp_utype, sp_vtype, patchPrim, computeNormals, patchFacing, vertType, &bytesRead); if (gstate_c.spline)