From 212fddd1953d7661599ce8bbcb4453389977c5af Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Mon, 16 Mar 2020 00:03:16 +1000 Subject: [PATCH] D3D11/StagingTexture: Add auto-resizing staging texture --- src/common/d3d11/staging_texture.cpp | 58 ++++++++++++++++++-------- src/common/d3d11/staging_texture.h | 61 ++++++++++++++++++++++++++-- 2 files changed, 99 insertions(+), 20 deletions(-) diff --git a/src/common/d3d11/staging_texture.cpp b/src/common/d3d11/staging_texture.cpp index 79a4d701d..148251308 100644 --- a/src/common/d3d11/staging_texture.cpp +++ b/src/common/d3d11/staging_texture.cpp @@ -1,6 +1,6 @@ #include "staging_texture.h" -#include "../log.h" #include "../assert.h" +#include "../log.h" Log_SetChannel(D3D11); namespace D3D11 { @@ -58,36 +58,60 @@ void StagingTexture::Unmap(ID3D11DeviceContext* context) m_map = {}; } -void StagingTexture::CopyToTexture(ID3D11DeviceContext* context, u32 src_x, u32 src_y, ID3D11Texture2D* dst_texture, +void StagingTexture::CopyToTexture(ID3D11DeviceContext* context, u32 src_x, u32 src_y, ID3D11Resource* dst_texture, u32 dst_subresource, u32 dst_x, u32 dst_y, u32 width, u32 height) { -#ifdef _DEBUG - Assert((src_x + width) <= m_width && (src_y + height) <= m_height); - - D3D11_TEXTURE2D_DESC dst_desc; - dst_texture->GetDesc(&dst_desc); - Assert((dst_x + width) <= dst_desc.Width && (dst_y + height) <= dst_desc.Height); -#endif + DebugAssert((src_x + width) <= m_width && (src_y + height) <= m_height); const CD3D11_BOX box(static_cast(src_x), static_cast(src_y), 0, static_cast(src_x + width), static_cast(src_y + height), 1); context->CopySubresourceRegion(dst_texture, dst_subresource, dst_x, dst_y, 0, m_texture.Get(), 0, &box); } -void StagingTexture::CopyFromTexture(ID3D11DeviceContext* context, ID3D11Texture2D* src_texture, u32 src_subresource, +void StagingTexture::CopyFromTexture(ID3D11DeviceContext* context, ID3D11Resource* src_texture, u32 src_subresource, u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) { -#ifdef _DEBUG - Assert((dst_x + width) <= m_width && (dst_y + height) <= m_height); - - D3D11_TEXTURE2D_DESC src_desc; - src_texture->GetDesc(&src_desc); - Assert((src_x + width) <= src_desc.Width && (src_y + height) <= src_desc.Height); -#endif + DebugAssert((dst_x + width) <= m_width && (dst_y + height) <= m_height); const CD3D11_BOX box(static_cast(src_x), static_cast(src_y), 0, static_cast(src_x + width), static_cast(src_y + height), 1); context->CopySubresourceRegion(m_texture.Get(), 0, dst_x, dst_y, 0, src_texture, src_subresource, &box); } +bool AutoStagingTexture::EnsureSize(ID3D11DeviceContext* context, u32 width, u32 height, DXGI_FORMAT format, + bool for_uploading) +{ + if (m_texture && m_width >= width && m_height >= height && m_format == format) + return true; + + ID3D11Device* device; + context->GetDevice(&device); + + CD3D11_TEXTURE2D_DESC new_desc(format, width, height, 1, 1, 0, + for_uploading ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_STAGING, + for_uploading ? D3D11_CPU_ACCESS_WRITE : D3D11_CPU_ACCESS_READ, 1, 0, 0); + ComPtr new_texture; + HRESULT hr = device->CreateTexture2D(&new_desc, nullptr, new_texture.GetAddressOf()); + if (FAILED(hr)) + { + Log_ErrorPrintf("Create texture failed: 0x%08X", hr); + return false; + } + + m_texture = std::move(new_texture); + m_width = width; + m_height = height; + m_format = format; + return true; +} + +void AutoStagingTexture::CopyFromTexture(ID3D11DeviceContext* context, ID3D11Resource* src_texture, u32 src_subresource, + u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) +{ + if (!EnsureSize(context, width, height, m_format, false)) + return; + + StagingTexture::CopyFromTexture(context, src_texture, src_subresource, src_x, src_y, dst_x, dst_y, width, height); +} + } // namespace D3D11 \ No newline at end of file diff --git a/src/common/d3d11/staging_texture.h b/src/common/d3d11/staging_texture.h index 53456a6c9..668cee2ae 100644 --- a/src/common/d3d11/staging_texture.h +++ b/src/common/d3d11/staging_texture.h @@ -30,9 +30,9 @@ public: bool Map(ID3D11DeviceContext* context, bool writing); void Unmap(ID3D11DeviceContext* context); - void CopyToTexture(ID3D11DeviceContext* context, u32 src_x, u32 src_y, ID3D11Texture2D* dst_texture, + void CopyToTexture(ID3D11DeviceContext* context, u32 src_x, u32 src_y, ID3D11Resource* dst_texture, u32 dst_subresource, u32 dst_x, u32 dst_y, u32 width, u32 height); - void CopyFromTexture(ID3D11DeviceContext* context, ID3D11Texture2D* src_texture, u32 src_subresource, u32 src_x, + void CopyFromTexture(ID3D11DeviceContext* context, ID3D11Resource* src_texture, u32 src_subresource, u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height); template @@ -69,6 +69,20 @@ public: } } + template + bool ReadPixels(ID3D11DeviceContext* context, u32 x, u32 y, u32 width, u32 height, u32 stride, T* data) + { + const bool was_mapped = IsMapped(); + if (!was_mapped && !Map(context, false)) + return false; + + ReadPixels(x, y, width, height, stride, data); + if (!was_mapped) + Unmap(context); + + return true; + } + template void WritePixels(u32 x, u32 y, u32 width, u32 height, u32 stride, const T* data) { @@ -89,7 +103,21 @@ public: } } -private: + template + bool WritePixels(ID3D11DeviceContext* context, u32 x, u32 y, u32 width, u32 height, u32 stride, const T* data) + { + const bool was_mapped = IsMapped(); + if (!was_mapped && !Map(context, true)) + return false; + + WritePixels(context, x, y, width, height, stride, data); + if (!was_mapped) + Unmap(context); + + return true; + } + +protected: ComPtr m_texture; u32 m_width; u32 m_height; @@ -97,4 +125,31 @@ private: D3D11_MAPPED_SUBRESOURCE m_map = {}; }; + +class AutoStagingTexture : public StagingTexture +{ +public: + bool EnsureSize(ID3D11DeviceContext* context, u32 width, u32 height, DXGI_FORMAT format, bool for_uploading); + + void CopyFromTexture(ID3D11DeviceContext* context, ID3D11Resource* src_texture, u32 src_subresource, u32 src_x, + u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height); + + template + bool WritePixels(ID3D11DeviceContext* context, u32 x, u32 y, u32 width, u32 height, u32 stride, const T* data) + { + if (!EnsureSize(context, width, height, m_format, true)) + return false; + + const bool was_mapped = IsMapped(); + if (!was_mapped && !Map(context, true)) + return false; + + WritePixels(context, x, y, width, height, stride, data); + + if (!was_mapped) + Unmap(context); + + return true; + } +}; } // namespace D3D11 \ No newline at end of file