D3D11/StagingTexture: Add auto-resizing staging texture

This commit is contained in:
Connor McLaughlin 2020-03-16 00:03:16 +10:00
parent cfcdc1c336
commit 212fddd195
2 changed files with 99 additions and 20 deletions

View File

@ -1,6 +1,6 @@
#include "staging_texture.h" #include "staging_texture.h"
#include "../log.h"
#include "../assert.h" #include "../assert.h"
#include "../log.h"
Log_SetChannel(D3D11); Log_SetChannel(D3D11);
namespace D3D11 { namespace D3D11 {
@ -58,36 +58,60 @@ void StagingTexture::Unmap(ID3D11DeviceContext* context)
m_map = {}; 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) u32 dst_subresource, u32 dst_x, u32 dst_y, u32 width, u32 height)
{ {
#ifdef _DEBUG DebugAssert((src_x + width) <= m_width && (src_y + height) <= m_height);
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
const CD3D11_BOX box(static_cast<LONG>(src_x), static_cast<LONG>(src_y), 0, static_cast<LONG>(src_x + width), const CD3D11_BOX box(static_cast<LONG>(src_x), static_cast<LONG>(src_y), 0, static_cast<LONG>(src_x + width),
static_cast<LONG>(src_y + height), 1); static_cast<LONG>(src_y + height), 1);
context->CopySubresourceRegion(dst_texture, dst_subresource, dst_x, dst_y, 0, m_texture.Get(), 0, &box); 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) u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height)
{ {
#ifdef _DEBUG DebugAssert((dst_x + width) <= m_width && (dst_y + height) <= m_height);
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
const CD3D11_BOX box(static_cast<LONG>(src_x), static_cast<LONG>(src_y), 0, static_cast<LONG>(src_x + width), const CD3D11_BOX box(static_cast<LONG>(src_x), static_cast<LONG>(src_y), 0, static_cast<LONG>(src_x + width),
static_cast<LONG>(src_y + height), 1); static_cast<LONG>(src_y + height), 1);
context->CopySubresourceRegion(m_texture.Get(), 0, dst_x, dst_y, 0, src_texture, src_subresource, &box); 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<ID3D11Texture2D> 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 } // namespace D3D11

View File

@ -30,9 +30,9 @@ public:
bool Map(ID3D11DeviceContext* context, bool writing); bool Map(ID3D11DeviceContext* context, bool writing);
void Unmap(ID3D11DeviceContext* context); 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); 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); u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height);
template<typename T> template<typename T>
@ -69,6 +69,20 @@ public:
} }
} }
template<typename T>
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<T>(x, y, width, height, stride, data);
if (!was_mapped)
Unmap(context);
return true;
}
template<typename T> template<typename T>
void WritePixels(u32 x, u32 y, u32 width, u32 height, u32 stride, const T* data) void WritePixels(u32 x, u32 y, u32 width, u32 height, u32 stride, const T* data)
{ {
@ -89,7 +103,21 @@ public:
} }
} }
private: template<typename T>
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<T>(context, x, y, width, height, stride, data);
if (!was_mapped)
Unmap(context);
return true;
}
protected:
ComPtr<ID3D11Texture2D> m_texture; ComPtr<ID3D11Texture2D> m_texture;
u32 m_width; u32 m_width;
u32 m_height; u32 m_height;
@ -97,4 +125,31 @@ private:
D3D11_MAPPED_SUBRESOURCE m_map = {}; 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<typename T>
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<T>(context, x, y, width, height, stride, data);
if (!was_mapped)
Unmap(context);
return true;
}
};
} // namespace D3D11 } // namespace D3D11