From a8c4d6c242cc5d529045781d5ab045418b531560 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 5 Mar 2016 19:45:03 +1000 Subject: D3D12: Allow large texture uploads (>64MiB) by using temporary buffer This is not optimal, but for those texture packs with extremely large images, it won't crash. Releasing after the frame completes is an option too, however, there is the risk of running out of memory by doing this. --- Source/Core/VideoBackends/D3D12/D3DTexture.cpp | 54 +++++++++++++++++++++----- 1 file changed, 44 insertions(+), 10 deletions(-) (limited to 'Source/Core/VideoBackends/D3D12/D3DTexture.cpp') diff --git a/Source/Core/VideoBackends/D3D12/D3DTexture.cpp b/Source/Core/VideoBackends/D3D12/D3DTexture.cpp index f913715e75..a3fe3b666e 100644 --- a/Source/Core/VideoBackends/D3D12/D3DTexture.cpp +++ b/Source/Core/VideoBackends/D3D12/D3DTexture.cpp @@ -21,6 +21,9 @@ namespace DX12 namespace D3D { +constexpr size_t INITIAL_TEXTURE_UPLOAD_BUFFER_SIZE = 4 * 1024 * 1024; +constexpr size_t MAXIMUM_TEXTURE_UPLOAD_BUFFER_SIZE = 64 * 1024 * 1024; + static std::unique_ptr s_texture_upload_stream_buffer; void CleanupPersistentD3DTextureResources() @@ -32,16 +35,39 @@ void ReplaceRGBATexture2D(ID3D12Resource* texture12, const u8* buffer, unsigned { const unsigned int upload_size = AlignValue(src_pitch, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) * height; - if (!s_texture_upload_stream_buffer) + ID3D12Resource* upload_buffer = nullptr; + size_t upload_buffer_offset = 0; + u8* dest_data = nullptr; + + if (upload_size > MAXIMUM_TEXTURE_UPLOAD_BUFFER_SIZE) { - s_texture_upload_stream_buffer = std::make_unique(4 * 1024 * 1024, 64 * 1024 * 1024, nullptr); - } + // If the texture is too large to fit in the upload buffer, create a temporary buffer instead. + // This will only be the case for large (e.g. 8192x8192) textures from custom texture packs. + CheckHR(D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), + D3D12_HEAP_FLAG_NONE, + &CD3DX12_RESOURCE_DESC::Buffer(upload_size), + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + IID_PPV_ARGS(&upload_buffer))); - bool current_command_list_executed = s_texture_upload_stream_buffer->AllocateSpaceInBuffer(upload_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT); - if (current_command_list_executed) + CheckHR(upload_buffer->Map(0, nullptr, reinterpret_cast(&dest_data))); + } + else { - g_renderer->SetViewport(); - D3D::current_command_list->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE, &FramebufferManager::GetEFBDepthTexture()->GetDSV12()); + if (!s_texture_upload_stream_buffer) + s_texture_upload_stream_buffer = std::make_unique(INITIAL_TEXTURE_UPLOAD_BUFFER_SIZE, MAXIMUM_TEXTURE_UPLOAD_BUFFER_SIZE, nullptr); + + bool current_command_list_executed = s_texture_upload_stream_buffer->AllocateSpaceInBuffer(upload_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT); + if (current_command_list_executed) + { + g_renderer->SetViewport(); + D3D::current_command_list->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE, &FramebufferManager::GetEFBDepthTexture()->GetDSV12()); + } + + upload_buffer = s_texture_upload_stream_buffer->GetBuffer(); + upload_buffer_offset = s_texture_upload_stream_buffer->GetOffsetOfCurrentAllocation(); + dest_data = reinterpret_cast(s_texture_upload_stream_buffer->GetCPUAddressOfCurrentAllocation()); } ResourceBarrier(current_command_list, texture12, current_resource_state, D3D12_RESOURCE_STATE_COPY_DEST, level); @@ -51,9 +77,8 @@ void ReplaceRGBATexture2D(ID3D12Resource* texture12, const u8* buffer, unsigned u64 upload_row_size_in_bytes = 0; u64 upload_total_bytes = 0; - D3D::device12->GetCopyableFootprints(&texture12->GetDesc(), level, 1, s_texture_upload_stream_buffer->GetOffsetOfCurrentAllocation(), &upload_footprint, &upload_rows, &upload_row_size_in_bytes, &upload_total_bytes); + D3D::device12->GetCopyableFootprints(&texture12->GetDesc(), level, 1, upload_buffer_offset, &upload_footprint, &upload_rows, &upload_row_size_in_bytes, &upload_total_bytes); - u8* dest_data = reinterpret_cast(s_texture_upload_stream_buffer->GetCPUAddressOfCurrentAllocation()); const u8* src_data = reinterpret_cast(buffer); for (u32 y = 0; y < upload_rows; ++y) { @@ -64,9 +89,18 @@ void ReplaceRGBATexture2D(ID3D12Resource* texture12, const u8* buffer, unsigned ); } - D3D::current_command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(texture12, level), 0, 0, 0, &CD3DX12_TEXTURE_COPY_LOCATION(s_texture_upload_stream_buffer->GetBuffer(), upload_footprint), nullptr); + D3D::current_command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(texture12, level), 0, 0, 0, &CD3DX12_TEXTURE_COPY_LOCATION(upload_buffer, upload_footprint), nullptr); ResourceBarrier(D3D::current_command_list, texture12, D3D12_RESOURCE_STATE_COPY_DEST, current_resource_state, level); + + // Release temporary buffer after commands complete. + // We block here because otherwise if there was a large number of texture uploads, we may run out of memory. + if (!s_texture_upload_stream_buffer || upload_buffer != s_texture_upload_stream_buffer->GetBuffer()) + { + D3D::command_list_mgr->ExecuteQueuedWork(true); + upload_buffer->Unmap(0, nullptr); + upload_buffer->Release(); + } } } // namespace -- cgit v1.2.3 From 32599559dbdcbebf3f13e7e7dc6a815ff308811c Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 5 Mar 2016 20:22:08 +1000 Subject: D3D12: Use helper method for binding EFB render targets --- Source/Core/VideoBackends/D3D12/D3DTexture.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Source/Core/VideoBackends/D3D12/D3DTexture.cpp') diff --git a/Source/Core/VideoBackends/D3D12/D3DTexture.cpp b/Source/Core/VideoBackends/D3D12/D3DTexture.cpp index a3fe3b666e..26141d2ae3 100644 --- a/Source/Core/VideoBackends/D3D12/D3DTexture.cpp +++ b/Source/Core/VideoBackends/D3D12/D3DTexture.cpp @@ -62,7 +62,7 @@ void ReplaceRGBATexture2D(ID3D12Resource* texture12, const u8* buffer, unsigned if (current_command_list_executed) { g_renderer->SetViewport(); - D3D::current_command_list->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE, &FramebufferManager::GetEFBDepthTexture()->GetDSV12()); + FramebufferManager::RestoreEFBRenderTargets(); } upload_buffer = s_texture_upload_stream_buffer->GetBuffer(); -- cgit v1.2.3 From acfa93372ec58faac05f9ed7c8ac0d6ed5ad403e Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 5 Mar 2016 22:38:14 +1000 Subject: D3D12: Refactoring and cleanups Moves render target restoring to RestoreAPIState, this also means no need to manually restore after allocating in a buffer that caused execution, because the manager restores it for us. Remove a method that wasn't used from D3DUtil.cpp, and fixes a few errors in EFB poke drawing. --- Source/Core/VideoBackends/D3D12/D3DTexture.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'Source/Core/VideoBackends/D3D12/D3DTexture.cpp') diff --git a/Source/Core/VideoBackends/D3D12/D3DTexture.cpp b/Source/Core/VideoBackends/D3D12/D3DTexture.cpp index 26141d2ae3..dd48391467 100644 --- a/Source/Core/VideoBackends/D3D12/D3DTexture.cpp +++ b/Source/Core/VideoBackends/D3D12/D3DTexture.cpp @@ -58,12 +58,7 @@ void ReplaceRGBATexture2D(ID3D12Resource* texture12, const u8* buffer, unsigned if (!s_texture_upload_stream_buffer) s_texture_upload_stream_buffer = std::make_unique(INITIAL_TEXTURE_UPLOAD_BUFFER_SIZE, MAXIMUM_TEXTURE_UPLOAD_BUFFER_SIZE, nullptr); - bool current_command_list_executed = s_texture_upload_stream_buffer->AllocateSpaceInBuffer(upload_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT); - if (current_command_list_executed) - { - g_renderer->SetViewport(); - FramebufferManager::RestoreEFBRenderTargets(); - } + s_texture_upload_stream_buffer->AllocateSpaceInBuffer(upload_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT); upload_buffer = s_texture_upload_stream_buffer->GetBuffer(); upload_buffer_offset = s_texture_upload_stream_buffer->GetOffsetOfCurrentAllocation(); -- cgit v1.2.3 From 25d5da0ea38a405c7fe4d1e3e4207701035c4fd2 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 6 Mar 2016 19:36:40 +1000 Subject: D3D12: Remove D3D11 header references --- Source/Core/VideoBackends/D3D12/D3DTexture.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'Source/Core/VideoBackends/D3D12/D3DTexture.cpp') diff --git a/Source/Core/VideoBackends/D3D12/D3DTexture.cpp b/Source/Core/VideoBackends/D3D12/D3DTexture.cpp index dd48391467..12fed7c4e2 100644 --- a/Source/Core/VideoBackends/D3D12/D3DTexture.cpp +++ b/Source/Core/VideoBackends/D3D12/D3DTexture.cpp @@ -100,7 +100,7 @@ void ReplaceRGBATexture2D(ID3D12Resource* texture12, const u8* buffer, unsigned } // namespace -D3DTexture2D* D3DTexture2D::Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind, D3D11_USAGE usage, DXGI_FORMAT fmt, unsigned int levels, unsigned int slices, D3D12_SUBRESOURCE_DATA* data) +D3DTexture2D* D3DTexture2D::Create(unsigned int width, unsigned int height, u32 bind, DXGI_FORMAT fmt, unsigned int levels, unsigned int slices, D3D12_SUBRESOURCE_DATA* data) { ID3D12Resource* texture12 = nullptr; @@ -115,7 +115,7 @@ D3DTexture2D* D3DTexture2D::Create(unsigned int width, unsigned int height, D3D1 D3D12_CLEAR_VALUE optimized_clear_value = {}; optimized_clear_value.Format = fmt; - if (bind & D3D11_BIND_RENDER_TARGET) + if (bind & TEXTURE_BIND_FLAG_RENDER_TARGET) { texdesc12.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; optimized_clear_value.Color[0] = 0.0f; @@ -124,7 +124,7 @@ D3DTexture2D* D3DTexture2D::Create(unsigned int width, unsigned int height, D3D1 optimized_clear_value.Color[3] = 1.0f; } - if (bind & D3D11_BIND_DEPTH_STENCIL) + if (bind & TEXTURE_BIND_FLAG_DEPTH_STENCIL) { texdesc12.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; optimized_clear_value.DepthStencil.Depth = 0.0f; @@ -210,7 +210,7 @@ D3D12_CPU_DESCRIPTOR_HANDLE D3DTexture2D::GetRTV12() const return m_rtv12; } -D3DTexture2D::D3DTexture2D(ID3D12Resource* texptr, D3D11_BIND_FLAG bind, +D3DTexture2D::D3DTexture2D(ID3D12Resource* texptr, u32 bind, DXGI_FORMAT srv_format, DXGI_FORMAT dsv_format, DXGI_FORMAT rtv_format, bool multisampled, D3D12_RESOURCE_STATES resource_state) : m_tex12(texptr), m_resource_state(resource_state), m_multisampled(multisampled) { @@ -218,7 +218,7 @@ D3DTexture2D::D3DTexture2D(ID3D12Resource* texptr, D3D11_BIND_FLAG bind, D3D12_DSV_DIMENSION dsv_dim12 = multisampled ? D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY : D3D12_DSV_DIMENSION_TEXTURE2DARRAY; D3D12_RTV_DIMENSION rtv_dim12 = multisampled ? D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY : D3D12_RTV_DIMENSION_TEXTURE2DARRAY; - if (bind & D3D11_BIND_SHADER_RESOURCE) + if (bind & TEXTURE_BIND_FLAG_SHADER_RESOURCE) { D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = { srv_format, // DXGI_FORMAT Format @@ -245,7 +245,7 @@ D3DTexture2D::D3DTexture2D(ID3D12Resource* texptr, D3D11_BIND_FLAG bind, D3D::device12->CreateShaderResourceView(m_tex12, &srv_desc, m_srv12_gpu_cpu_shadow); } - if (bind & D3D11_BIND_DEPTH_STENCIL) + if (bind & TEXTURE_BIND_FLAG_DEPTH_STENCIL) { D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc = { dsv_format, // DXGI_FORMAT Format @@ -262,7 +262,7 @@ D3DTexture2D::D3DTexture2D(ID3D12Resource* texptr, D3D11_BIND_FLAG bind, D3D::device12->CreateDepthStencilView(m_tex12, &dsv_desc, m_dsv12); } - if (bind & D3D11_BIND_RENDER_TARGET) + if (bind & TEXTURE_BIND_FLAG_RENDER_TARGET) { D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = { rtv_format, // DXGI_FORMAT Format -- cgit v1.2.3 From ccf9470241309114bdc46d9dc80bb9b99aed4a41 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Tue, 15 Mar 2016 22:26:01 +1000 Subject: D3D12: Specify read/write ranges when calling Map/Unmap --- Source/Core/VideoBackends/D3D12/D3DTexture.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'Source/Core/VideoBackends/D3D12/D3DTexture.cpp') diff --git a/Source/Core/VideoBackends/D3D12/D3DTexture.cpp b/Source/Core/VideoBackends/D3D12/D3DTexture.cpp index 12fed7c4e2..9749a36a76 100644 --- a/Source/Core/VideoBackends/D3D12/D3DTexture.cpp +++ b/Source/Core/VideoBackends/D3D12/D3DTexture.cpp @@ -51,7 +51,8 @@ void ReplaceRGBATexture2D(ID3D12Resource* texture12, const u8* buffer, unsigned nullptr, IID_PPV_ARGS(&upload_buffer))); - CheckHR(upload_buffer->Map(0, nullptr, reinterpret_cast(&dest_data))); + D3D12_RANGE read_range = {}; + CheckHR(upload_buffer->Map(0, &read_range, reinterpret_cast(&dest_data))); } else { @@ -92,8 +93,11 @@ void ReplaceRGBATexture2D(ID3D12Resource* texture12, const u8* buffer, unsigned // We block here because otherwise if there was a large number of texture uploads, we may run out of memory. if (!s_texture_upload_stream_buffer || upload_buffer != s_texture_upload_stream_buffer->GetBuffer()) { + D3D12_RANGE write_range = { 0, upload_size }; + upload_buffer->Unmap(0, &write_range); + D3D::command_list_mgr->ExecuteQueuedWork(true); - upload_buffer->Unmap(0, nullptr); + upload_buffer->Release(); } } -- cgit v1.2.3