diff --git a/pcsx2/GS/Renderers/Common/GSTexture.cpp b/pcsx2/GS/Renderers/Common/GSTexture.cpp index 0a9d60ceff..c57fe0791f 100644 --- a/pcsx2/GS/Renderers/Common/GSTexture.cpp +++ b/pcsx2/GS/Renderers/Common/GSTexture.cpp @@ -16,6 +16,12 @@ GSTexture::GSTexture() = default; GSTexture::~GSTexture() = default; +bool GSTexture::Update(const GSVector4i& r, const void* data, int pitch, int layer) +{ + g_gs_device->FlushDeferredDraws(); + return DoUpdate(r, data, pitch, layer); +} + bool GSTexture::ValidateUsageAndFormat(Usage usage, Format format) { if (IsDepthStencil(usage) && (usage & (Usage::ShaderWrite | Usage::RenderTarget))) @@ -229,6 +235,13 @@ GSDownloadTexture::GSDownloadTexture(u32 width, u32 height, GSTexture::Format fo GSDownloadTexture::~GSDownloadTexture() = default; +void GSDownloadTexture::CopyFromTexture( + const GSVector4i& drc, GSTexture* stex, const GSVector4i& src, u32 src_level, bool use_transfer_pitch) +{ + g_gs_device->FlushDeferredDraws(); + DoCopyFromTexture(drc, stex, src, src_level, use_transfer_pitch); +} + u32 GSDownloadTexture::GetBufferSize(u32 width, u32 height, GSTexture::Format format, u32 pitch_align /* = 1 */) { const u32 block_size = GSTexture::GetCompressedBlockSize(format); diff --git a/pcsx2/GS/Renderers/Common/GSTexture.h b/pcsx2/GS/Renderers/Common/GSTexture.h index 6eac6a59f9..8151edbd28 100644 --- a/pcsx2/GS/Renderers/Common/GSTexture.h +++ b/pcsx2/GS/Renderers/Common/GSTexture.h @@ -97,6 +97,9 @@ protected: #ifdef PCSX2_DEVBUILD std::string m_debug_name; #endif + + virtual bool DoUpdate(const GSVector4i& r, const void* data, int pitch, int layer = 0) = 0; + public: GSTexture(); virtual ~GSTexture(); @@ -104,7 +107,10 @@ public: // Returns the native handle of a texture. virtual void* GetNativeHandle() const = 0; - virtual bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0) = 0; + /// Uploads CPU data into the texture. Flushes any deferred draws first: a draw held + /// back by GSPassScheduler must not be reordered past an upload into a texture it + /// writes, nor past one into a texture it samples. + bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0); virtual bool Map(GSMap& m, const GSVector4i* r = nullptr, int layer = 0) = 0; virtual void Unmap() = 0; virtual void GenerateMipmap() = 0; @@ -262,6 +268,10 @@ public: class GSDownloadTexture { +protected: + virtual void DoCopyFromTexture( + const GSVector4i& drc, GSTexture* stex, const GSVector4i& src, u32 src_level, bool use_transfer_pitch) = 0; + public: GSDownloadTexture(u32 width, u32 height, GSTexture::Format format); virtual ~GSDownloadTexture(); @@ -285,8 +295,10 @@ public: /// Does not complete immediately, you should flush before accessing the buffer. /// use_transfer_pitch should be true if there's only a single texture being copied to this buffer before /// it will be used. This allows the image to be packed tighter together, and buffer reuse. - virtual void CopyFromTexture( - const GSVector4i& drc, GSTexture* stex, const GSVector4i& src, u32 src_level, bool use_transfer_pitch = true) = 0; + /// Flushes any deferred draws first, so a readback always sees every draw that had been + /// submitted when it was issued. + void CopyFromTexture( + const GSVector4i& drc, GSTexture* stex, const GSVector4i& src, u32 src_level, bool use_transfer_pitch = true); /// Maps the texture into the CPU address space, enabling it to read the contents. /// The Map call may not perform synchronization. If the contents of the staging texture diff --git a/pcsx2/GS/Renderers/DX11/GSTexture11.cpp b/pcsx2/GS/Renderers/DX11/GSTexture11.cpp index 0e736cf1cb..0cbc1bc602 100644 --- a/pcsx2/GS/Renderers/DX11/GSTexture11.cpp +++ b/pcsx2/GS/Renderers/DX11/GSTexture11.cpp @@ -55,7 +55,7 @@ void* GSTexture11::GetNativeHandle() const return static_cast(*const_cast(this)); } -bool GSTexture11::Update(const GSVector4i& r, const void* data, int pitch, int layer) +bool GSTexture11::DoUpdate(const GSVector4i& r, const void* data, int pitch, int layer) { if (layer >= m_mipmap_levels) return false; @@ -232,7 +232,7 @@ std::unique_ptr GSDownloadTexture11::Create(u32 width, u32 return std::unique_ptr(new GSDownloadTexture11(std::move(tex), width, height, format)); } -void GSDownloadTexture11::CopyFromTexture( +void GSDownloadTexture11::DoCopyFromTexture( const GSVector4i& drc, GSTexture* stex, const GSVector4i& src, u32 src_level, bool use_transfer_pitch) { pxAssert(stex->GetFormat() == m_format); diff --git a/pcsx2/GS/Renderers/DX11/GSTexture11.h b/pcsx2/GS/Renderers/DX11/GSTexture11.h index 1ce1487422..8e0918b614 100644 --- a/pcsx2/GS/Renderers/DX11/GSTexture11.h +++ b/pcsx2/GS/Renderers/DX11/GSTexture11.h @@ -27,7 +27,7 @@ public: void* GetNativeHandle() const override; - bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0) override; + bool DoUpdate(const GSVector4i& r, const void* data, int pitch, int layer = 0) override; bool Map(GSMap& m, const GSVector4i* r = NULL, int layer = 0) override; void Unmap() override; void GenerateMipmap() override; @@ -52,7 +52,7 @@ public: static std::unique_ptr Create(u32 width, u32 height, GSTexture::Format format); - void CopyFromTexture( + void DoCopyFromTexture( const GSVector4i& drc, GSTexture* stex, const GSVector4i& src, u32 src_level, bool use_transfer_pitch) override; bool Map(const GSVector4i& rc) override; diff --git a/pcsx2/GS/Renderers/DX12/GSTexture12.cpp b/pcsx2/GS/Renderers/DX12/GSTexture12.cpp index d4fab3f018..7d9ec327d3 100644 --- a/pcsx2/GS/Renderers/DX12/GSTexture12.cpp +++ b/pcsx2/GS/Renderers/DX12/GSTexture12.cpp @@ -578,7 +578,7 @@ void GSTexture12::CopyTextureDataForUpload(void* dst, const void* src, u32 pitch StringUtil::StrideMemCpy(dst, upload_pitch, src, pitch, std::min(upload_pitch, pitch), count); } -bool GSTexture12::Update(const GSVector4i& r, const void* data, int pitch, int layer) +bool GSTexture12::DoUpdate(const GSVector4i& r, const void* data, int pitch, int layer) { if (layer >= m_mipmap_levels) return false; @@ -631,7 +631,7 @@ bool GSTexture12::Update(const GSVector4i& r, const void* data, int pitch, int l } const D3D12CommandList& cmdlist = GetCommandBufferForUpdate(); - GL_PUSH("GSTexture12::Update({%d,%d} %dx%d Lvl:%u", r.x, r.y, r.width(), r.height(), layer); + GL_PUSH("GSTexture12::DoUpdate({%d,%d} %dx%d Lvl:%u", r.x, r.y, r.width(), r.height(), layer); // first time the texture is used? don't leave it undefined if (m_resource_state == GSTexture12::ResourceState::Undefined) @@ -676,7 +676,7 @@ bool GSTexture12::Map(GSMap& m, const GSVector4i* r, int layer) m_map_level = layer; m.pitch = Common::AlignUpPow2(CalcUploadPitch(m_map_area.width()), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); - // see note in Update() for the reason why. + // see note in DoUpdate() for the reason why. const u32 required_size = CalcUploadSize(m_map_area.height(), m.pitch); D3D12StreamBuffer& buffer = GSDevice12::GetInstance()->GetTextureStreamBuffer(); if (required_size >= (buffer.GetSize() / 2)) @@ -709,7 +709,7 @@ void GSTexture12::Unmap() buffer.CommitMemory(required_size); const D3D12CommandList& cmdlist = GetCommandBufferForUpdate(); - GL_PUSH("GSTexture12::Update({%d,%d} %dx%d Lvl:%u", m_map_area.x, m_map_area.y, m_map_area.width(), + GL_PUSH("GSTexture12::DoUpdate({%d,%d} %dx%d Lvl:%u", m_map_area.x, m_map_area.y, m_map_area.width(), m_map_area.height(), m_map_level); // first time the texture is used? don't leave it undefined @@ -1209,7 +1209,7 @@ std::unique_ptr GSDownloadTexture12::Create(u32 width, u32 return tex; } -void GSDownloadTexture12::CopyFromTexture( +void GSDownloadTexture12::DoCopyFromTexture( const GSVector4i& drc, GSTexture* stex, const GSVector4i& src, u32 src_level, bool use_transfer_pitch) { GSTexture12* const tex12 = static_cast(stex); diff --git a/pcsx2/GS/Renderers/DX12/GSTexture12.h b/pcsx2/GS/Renderers/DX12/GSTexture12.h index ecfe618876..14e16cf845 100644 --- a/pcsx2/GS/Renderers/DX12/GSTexture12.h +++ b/pcsx2/GS/Renderers/DX12/GSTexture12.h @@ -60,7 +60,7 @@ public: void* GetNativeHandle() const override; - bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0) override; + bool DoUpdate(const GSVector4i& r, const void* data, int pitch, int layer = 0) override; bool Map(GSMap& m, const GSVector4i* r = NULL, int layer = 0) override; void Unmap() override; void GenerateMipmap() override; @@ -140,7 +140,7 @@ public: static std::unique_ptr Create(u32 width, u32 height, GSTexture::Format format); - void CopyFromTexture( + void DoCopyFromTexture( const GSVector4i& drc, GSTexture* stex, const GSVector4i& src, u32 src_level, bool use_transfer_pitch) override; bool Map(const GSVector4i& read_rc) override; diff --git a/pcsx2/GS/Renderers/Metal/GSTextureMTL.h b/pcsx2/GS/Renderers/Metal/GSTextureMTL.h index c7f87886c7..b848c27560 100644 --- a/pcsx2/GS/Renderers/Metal/GSTextureMTL.h +++ b/pcsx2/GS/Renderers/Metal/GSTextureMTL.h @@ -37,7 +37,7 @@ public: void FlushClears(); void* GetNativeHandle() const override; - bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0) override; + bool DoUpdate(const GSVector4i& r, const void* data, int pitch, int layer = 0) override; bool Map(GSMap& m, const GSVector4i* r = NULL, int layer = 0) override; void* MapWithPitch(const GSVector4i& r, int pitch, int layer); void Unmap() override; @@ -57,7 +57,7 @@ public: static std::unique_ptr Create(GSDeviceMTL* dev, u32 width, u32 height, GSTexture::Format format); - void CopyFromTexture(const GSVector4i& drc, GSTexture* stex, const GSVector4i& src, u32 src_level, bool use_transfer_pitch) override; + void DoCopyFromTexture(const GSVector4i& drc, GSTexture* stex, const GSVector4i& src, u32 src_level, bool use_transfer_pitch) override; bool Map(const GSVector4i& read_rc) override; void Unmap() override; diff --git a/pcsx2/GS/Renderers/Metal/GSTextureMTL.mm b/pcsx2/GS/Renderers/Metal/GSTextureMTL.mm index e785a927d1..9d8ed5bf6f 100644 --- a/pcsx2/GS/Renderers/Metal/GSTextureMTL.mm +++ b/pcsx2/GS/Renderers/Metal/GSTextureMTL.mm @@ -43,7 +43,7 @@ void* GSTextureMTL::GetNativeHandle() const return (__bridge void*)m_texture; } -bool GSTextureMTL::Update(const GSVector4i& r, const void* data, int pitch, int layer) +bool GSTextureMTL::DoUpdate(const GSVector4i& r, const void* data, int pitch, int layer) { if (void* buffer = MapWithPitch(r, pitch, layer)) { @@ -176,7 +176,7 @@ std::unique_ptr GSDownloadTextureMTL::Create(GSDeviceMTL* return std::unique_ptr(new GSDownloadTextureMTL(dev, buffer, width, height, format)); }} -void GSDownloadTextureMTL::CopyFromTexture( +void GSDownloadTextureMTL::DoCopyFromTexture( const GSVector4i& drc, GSTexture* stex, const GSVector4i& src, u32 src_level, bool use_transfer_pitch) { @autoreleasepool { GSTextureMTL* const mtlTex = static_cast(stex); @@ -199,7 +199,7 @@ void GSDownloadTextureMTL::CopyFromTexture( m_copy_cmdbuffer = MRCRetain(m_dev->GetRenderCmdBuf()); - [m_copy_cmdbuffer pushDebugGroup:@"GSDownloadTextureMTL::CopyFromTexture"]; + [m_copy_cmdbuffer pushDebugGroup:@"GSDownloadTextureMTL::DoCopyFromTexture"]; id encoder = [m_copy_cmdbuffer blitCommandEncoder]; [encoder copyFromTexture:mtlTex->GetTexture() sourceSlice:0 diff --git a/pcsx2/GS/Renderers/Null/GSDeviceNone.cpp b/pcsx2/GS/Renderers/Null/GSDeviceNone.cpp index b50b5261d8..4fa9ec2b2a 100644 --- a/pcsx2/GS/Renderers/Null/GSDeviceNone.cpp +++ b/pcsx2/GS/Renderers/Null/GSDeviceNone.cpp @@ -20,7 +20,7 @@ void* GSTextureNone::GetNativeHandle() const return nullptr; } -bool GSTextureNone::Update(const GSVector4i& r, const void* data, int pitch, int layer) +bool GSTextureNone::DoUpdate(const GSVector4i& r, const void* data, int pitch, int layer) { return true; } @@ -61,7 +61,7 @@ GSDownloadTextureNone::GSDownloadTextureNone(u32 width, u32 height, GSTexture::F m_buffer.resize(GetBufferSize(width, height, format)); } -void GSDownloadTextureNone::CopyFromTexture( +void GSDownloadTextureNone::DoCopyFromTexture( const GSVector4i& drc, GSTexture* stex, const GSVector4i& src, u32 src_level, bool use_transfer_pitch) { m_current_pitch = GetTransferPitch(use_transfer_pitch ? static_cast(drc.width()) : m_width, 1); diff --git a/pcsx2/GS/Renderers/Null/GSDeviceNone.h b/pcsx2/GS/Renderers/Null/GSDeviceNone.h index 4822468b0c..4328138693 100644 --- a/pcsx2/GS/Renderers/Null/GSDeviceNone.h +++ b/pcsx2/GS/Renderers/Null/GSDeviceNone.h @@ -20,7 +20,7 @@ public: GSTextureNone(Usage usage, int width, int height, int levels, Format format); void* GetNativeHandle() const override; - bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0) override; + bool DoUpdate(const GSVector4i& r, const void* data, int pitch, int layer = 0) override; bool Map(GSMap& m, const GSVector4i* r = nullptr, int layer = 0) override; void Unmap() override; void GenerateMipmap() override; @@ -38,7 +38,7 @@ class GSDownloadTextureNone final : public GSDownloadTexture public: GSDownloadTextureNone(u32 width, u32 height, GSTexture::Format format); - void CopyFromTexture(const GSVector4i& drc, GSTexture* stex, const GSVector4i& src, u32 src_level, + void DoCopyFromTexture(const GSVector4i& drc, GSTexture* stex, const GSVector4i& src, u32 src_level, bool use_transfer_pitch = true) override; bool Map(const GSVector4i& read_rc) override; void Unmap() override; diff --git a/pcsx2/GS/Renderers/OpenGL/GSTextureOGL.cpp b/pcsx2/GS/Renderers/OpenGL/GSTextureOGL.cpp index aa20db069b..556c37bc8a 100644 --- a/pcsx2/GS/Renderers/OpenGL/GSTextureOGL.cpp +++ b/pcsx2/GS/Renderers/OpenGL/GSTextureOGL.cpp @@ -179,7 +179,7 @@ void* GSTextureOGL::GetNativeHandle() const return reinterpret_cast(static_cast(m_texture_id)); } -bool GSTextureOGL::Update(const GSVector4i& r, const void* data, int pitch, int layer) +bool GSTextureOGL::DoUpdate(const GSVector4i& r, const void* data, int pitch, int layer) { pxAssert(!IsDepthStencil()); @@ -416,7 +416,7 @@ std::unique_ptr GSDownloadTextureOGL::Create(u32 width, u3 return ret; } -void GSDownloadTextureOGL::CopyFromTexture( +void GSDownloadTextureOGL::DoCopyFromTexture( const GSVector4i& drc, GSTexture* stex, const GSVector4i& src, u32 src_level, bool use_transfer_pitch) { GSTextureOGL* const glTex = static_cast(stex); diff --git a/pcsx2/GS/Renderers/OpenGL/GSTextureOGL.h b/pcsx2/GS/Renderers/OpenGL/GSTextureOGL.h index 44a9d7ad90..b22ac9aae7 100644 --- a/pcsx2/GS/Renderers/OpenGL/GSTextureOGL.h +++ b/pcsx2/GS/Renderers/OpenGL/GSTextureOGL.h @@ -38,7 +38,7 @@ public: void* GetNativeHandle() const override; - bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0) override; + bool DoUpdate(const GSVector4i& r, const void* data, int pitch, int layer = 0) override; bool Map(GSMap& m, const GSVector4i* r = NULL, int layer = 0) override; void Unmap() override; void GenerateMipmap() override; @@ -67,7 +67,7 @@ public: static std::unique_ptr Create(u32 width, u32 height, GSTexture::Format format); - void CopyFromTexture(const GSVector4i& drc, GSTexture* stex, const GSVector4i& src, u32 src_level, bool use_transfer_pitch) override; + void DoCopyFromTexture(const GSVector4i& drc, GSTexture* stex, const GSVector4i& src, u32 src_level, bool use_transfer_pitch) override; bool Map(const GSVector4i& read_rc) override; void Unmap() override; diff --git a/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp index 0d245324ac..8171cbf89a 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp @@ -329,7 +329,7 @@ void GSTextureVK::UpdateFromBuffer(VkCommandBuffer cmdbuf, int level, u32 x, u32 TransitionSubresourcesToLayout(cmdbuf, level, 1, Layout::TransferDst, old_layout); } -bool GSTextureVK::Update(const GSVector4i& r, const void* data, int pitch, int layer) +bool GSTextureVK::DoUpdate(const GSVector4i& r, const void* data, int pitch, int layer) { if (layer >= m_mipmap_levels) return false; @@ -383,7 +383,7 @@ bool GSTextureVK::Update(const GSVector4i& r, const void* data, int pitch, int l } const VkCommandBuffer cmdbuf = GetCommandBufferForUpdate(); - GL_PUSH("GSTextureVK::Update({%d,%d} %dx%d Lvl:%u", r.x, r.y, r.width(), r.height(), layer); + GL_PUSH("GSTextureVK::DoUpdate({%d,%d} %dx%d Lvl:%u", r.x, r.y, r.width(), r.height(), layer); // first time the texture is used? don't leave it undefined if (m_layout == Layout::Undefined) @@ -420,7 +420,7 @@ bool GSTextureVK::Map(GSMap& m, const GSVector4i* r, int layer) m.pitch = Common::AlignUpPow2( CalcUploadPitch(m_map_area.width()), GSDeviceVK::GetInstance()->GetBufferCopyRowPitchAlignment()); - // see note in Update() for the reason why. + // see note in DoUpdate() for the reason why. const u32 required_size = CalcUploadSize(m_map_area.height(), m.pitch); VKStreamBuffer& buffer = GSDeviceVK::GetInstance()->GetTextureUploadBuffer(); if (required_size >= (buffer.GetCurrentSize() / 2)) @@ -464,7 +464,7 @@ void GSTextureVK::Unmap() buffer.CommitMemory(required_size); const VkCommandBuffer cmdbuf = GetCommandBufferForUpdate(); - GL_PUSH("GSTextureVK::Update({%d,%d} %dx%d Lvl:%u", m_map_area.x, m_map_area.y, m_map_area.width(), + GL_PUSH("GSTextureVK::DoUpdate({%d,%d} %dx%d Lvl:%u", m_map_area.x, m_map_area.y, m_map_area.width(), m_map_area.height(), m_map_level); // first time the texture is used? don't leave it undefined @@ -883,7 +883,7 @@ std::unique_ptr GSDownloadTextureVK::Create(u32 width, u32 return tex; } -void GSDownloadTextureVK::CopyFromTexture( +void GSDownloadTextureVK::DoCopyFromTexture( const GSVector4i& drc, GSTexture* stex, const GSVector4i& src, u32 src_level, bool use_transfer_pitch) { GSTextureVK* const vkTex = static_cast(stex); @@ -905,7 +905,7 @@ void GSDownloadTextureVK::CopyFromTexture( vkTex->CommitClear(); const VkCommandBuffer cmdbuf = GSDeviceVK::GetInstance()->GetCurrentCommandBuffer(); - GL_INS("GSDownloadTextureVK::CopyFromTexture: {%d,%d} %ux%u", src.left, src.top, src.width(), src.height()); + GL_INS("GSDownloadTextureVK::DoCopyFromTexture: {%d,%d} %ux%u", src.left, src.top, src.width(), src.height()); GSTextureVK::Layout old_layout = vkTex->GetLayout(); if (old_layout == GSTextureVK::Layout::Undefined) diff --git a/pcsx2/GS/Renderers/Vulkan/GSTextureVK.h b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.h index c652b46802..bf40e45108 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSTextureVK.h +++ b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.h @@ -50,7 +50,7 @@ public: void* GetNativeHandle() const override; - bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0) override; + bool DoUpdate(const GSVector4i& r, const void* data, int pitch, int layer = 0) override; bool Map(GSMap& m, const GSVector4i* r = NULL, int layer = 0) override; void Unmap() override; void GenerateMipmap() override; @@ -117,7 +117,7 @@ public: static std::unique_ptr Create(u32 width, u32 height, GSTexture::Format format); - void CopyFromTexture( + void DoCopyFromTexture( const GSVector4i& drc, GSTexture* stex, const GSVector4i& src, u32 src_level, bool use_transfer_pitch) override; bool Map(const GSVector4i& read_rc) override;