From 71baecabd6a55dd17a96924016921e673e1695fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 17 Aug 2017 13:05:13 +0200 Subject: [PATCH 1/4] Make FLAG_FLUSHBEFORE a no-op, move flushes into the execution functions. It would only be necessary if we needed the previous value, which we don't do in any of these. --- GPU/D3D11/GPU_D3D11.cpp | 6 +++++- GPU/Directx9/GPU_DX9.cpp | 8 ++++++-- GPU/GLES/GPU_GLES.cpp | 8 ++++++-- GPU/GPUCommon.cpp | 5 +++++ GPU/Vulkan/GPU_Vulkan.cpp | 6 +++++- 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 75ac25c4d1..a7f9885a69 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -397,7 +397,7 @@ void GPU_D3D11::FastRunLoop(DisplayList &list) { 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 u32 diff = op ^ gstate.cmdmem[cmd]; // Inlined CheckFlushOp here to get rid of the dumpThisFrame_ check. - if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) { + if (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE)) { drawEngine_.Flush(); } gstate.cmdmem[cmd] = op; // TODO: no need to write if diff==0... @@ -546,6 +546,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); @@ -608,6 +610,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); diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index 2029a9b123..100b84c84e 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -364,7 +364,7 @@ void GPU_DX9::FastRunLoop(DisplayList &list) { 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 u32 diff = op ^ gstate.cmdmem[cmd]; // Inlined CheckFlushOp here to get rid of the dumpThisFrame_ check. - if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) { + if (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE)) { drawEngine_.Flush(); } gstate.cmdmem[cmd] = op; // TODO: no need to write if diff==0... @@ -386,7 +386,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 ================"); } @@ -512,6 +512,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); @@ -559,6 +561,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); diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 83914e8871..cc095c571c 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -571,7 +571,7 @@ void GPU_GLES::FastRunLoop(DisplayList &list) { 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 u32 diff = op ^ gstate.cmdmem[cmd]; // Inlined CheckFlushOp here to get rid of the dumpThisFrame_ check. - if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) { + if (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE)) { drawEngine_.Flush(); } gstate.cmdmem[cmd] = op; // TODO: no need to write if diff==0... @@ -596,7 +596,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 ================"); } @@ -720,6 +720,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); @@ -782,6 +784,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); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index b29d8370cc..6858985785 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1267,6 +1267,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); @@ -1451,6 +1453,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 +1497,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 +1572,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/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index fe4c87ec6b..412cbcbb63 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -402,7 +402,7 @@ void GPU_Vulkan::FastRunLoop(DisplayList &list) { 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 u32 diff = op ^ gstate.cmdmem[cmd]; // Inlined CheckFlushOp here to get rid of the dumpThisFrame_ check. - if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) { + if (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE)) { drawEngine_.Flush(); } gstate.cmdmem[cmd] = op; // TODO: no need to write if diff==0... @@ -551,6 +551,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); @@ -613,6 +615,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); From 2c4e5e2303fc6f0fd1cc880cbed1154013f540b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 17 Aug 2017 13:53:13 +0200 Subject: [PATCH 2/4] Fastpath in fastrunloop when diff=0. Remove need for Execute for UV scale/offset. --- Common/Vulkan/VulkanContext.h | 2 -- GPU/D3D11/GPU_D3D11.cpp | 42 +++++++++++++++++++++++------------ GPU/Directx9/GPU_DX9.cpp | 42 +++++++++++++++++++++++------------ GPU/GLES/GPU_GLES.cpp | 40 ++++++++++++++++++++------------- GPU/GPUCommon.cpp | 26 +++++----------------- GPU/GPUCommon.h | 15 +++++++++++++ GPU/Vulkan/GPU_Vulkan.cpp | 40 ++++++++++++++++++++------------- 7 files changed, 127 insertions(+), 80 deletions(-) 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 a7f9885a69..19d281a822 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -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 (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; // TODO: no need to write if diff==0... + 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; @@ -598,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) @@ -668,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 100b84c84e..b052ae1641 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -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 (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; // TODO: no need to write if diff==0... + 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() { @@ -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; @@ -553,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. @@ -605,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 cc095c571c..1392dda2c7 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -567,22 +567,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 (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; // TODO: no need to write if diff==0... + 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; } @@ -676,6 +683,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(); @@ -772,6 +780,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) @@ -843,6 +852,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 6858985785..424ea7a004 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 }, @@ -1425,22 +1427,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; diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index ca2d8ac931..33a69ba97f 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -196,6 +196,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 412cbcbb63..1dcae39ad6 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -398,22 +398,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 (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; // TODO: no need to write if diff==0... + 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 +514,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; @@ -603,6 +611,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) @@ -674,6 +683,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) From 5680332343b3e136ccc61fcb5f98e93e8e4f3d83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 17 Aug 2017 14:26:52 +0200 Subject: [PATCH 3/4] Minor cleanups --- GPU/D3D11/GPU_D3D11.cpp | 4 ++-- GPU/Directx9/GPU_DX9.cpp | 4 ++-- GPU/GLES/GPU_GLES.cpp | 3 +-- GPU/GPUCommon.cpp | 1 + GPU/Vulkan/GPU_Vulkan.cpp | 4 +--- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 19d281a822..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]{}; @@ -407,7 +407,7 @@ void GPU_D3D11::FastRunLoop(DisplayList &list) { if (flags & FLAG_FLUSHBEFOREONCHANGE) { drawEngine_.Flush(); } - gstate.cmdmem[cmd] = op; // TODO: no need to write if diff==0... + gstate.cmdmem[cmd] = op; if (flags & (FLAG_EXECUTE | FLAG_EXECUTEONCHANGE)) { downcount = dc; (this->*info.func)(op, diff); diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index b052ae1641..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]; @@ -374,7 +374,7 @@ void GPU_DX9::FastRunLoop(DisplayList &list) { if (flags & FLAG_FLUSHBEFOREONCHANGE) { drawEngine_.Flush(); } - gstate.cmdmem[cmd] = op; // TODO: no need to write if diff==0... + gstate.cmdmem[cmd] = op; if (flags & (FLAG_EXECUTE | FLAG_EXECUTEONCHANGE)) { downcount = dc; (this->*info.func)(op, diff); diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 1392dda2c7..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]; @@ -580,7 +579,7 @@ void GPU_GLES::FastRunLoop(DisplayList &list) { if (flags & FLAG_FLUSHBEFOREONCHANGE) { drawEngine_.Flush(); } - gstate.cmdmem[cmd] = op; // TODO: no need to write if diff==0... + gstate.cmdmem[cmd] = op; if (flags & (FLAG_EXECUTE | FLAG_EXECUTEONCHANGE)) { downcount = dc; (this->*info.func)(op, diff); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 424ea7a004..ddab4454bf 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -280,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 }, diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 1dcae39ad6..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) @@ -411,7 +409,7 @@ void GPU_Vulkan::FastRunLoop(DisplayList &list) { if (flags & FLAG_FLUSHBEFOREONCHANGE) { drawEngine_.Flush(); } - gstate.cmdmem[cmd] = op; // TODO: no need to write if diff==0... + gstate.cmdmem[cmd] = op; if (flags & (FLAG_EXECUTE | FLAG_EXECUTEONCHANGE)) { downcount = dc; (this->*info.func)(op, diff); From 319df97bc709fbdc338f8685a4a6fac4cca34fda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 17 Aug 2017 15:48:52 +0200 Subject: [PATCH 4/4] Buildfix for X86 Android --- GPU/GPUCommon.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 33a69ba97f..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