From c4d79d6db3192ec3b163c31a611a4f20c03ed8b0 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Tue, 23 Feb 2016 22:18:41 +1000 Subject: D3D12: Add helper method for setting both viewport and scissor rect Simplfies making changes, as well as keeping the two in sync. --- Source/Core/VideoBackends/D3D12/TextureCache.cpp | 32 ++++++------------------ 1 file changed, 7 insertions(+), 25 deletions(-) (limited to 'Source/Core/VideoBackends/D3D12/TextureCache.cpp') diff --git a/Source/Core/VideoBackends/D3D12/TextureCache.cpp b/Source/Core/VideoBackends/D3D12/TextureCache.cpp index d88fce86c7..37660b9136 100644 --- a/Source/Core/VideoBackends/D3D12/TextureCache.cpp +++ b/Source/Core/VideoBackends/D3D12/TextureCache.cpp @@ -164,15 +164,7 @@ void TextureCache::TCacheEntry::CopyRectangleFromTexture( return; } - const D3D12_VIEWPORT vp = { - float(dst_rect.left), - float(dst_rect.top), - float(dst_rect.GetWidth()), - float(dst_rect.GetHeight()), - D3D12_MIN_DEPTH, - D3D12_MAX_DEPTH - }; - D3D::current_command_list->RSSetViewports(1, &vp); + D3D::SetViewportAndScissor(dst_rect.left, dst_rect.top, dst_rect.GetWidth(), dst_rect.GetHeight()); m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); D3D::current_command_list->OMSetRenderTargets(1, &m_texture->GetRTV12(), FALSE, nullptr); @@ -289,18 +281,6 @@ void TextureCache::TCacheEntry::FromRenderTarget(u8* dst, PEControl::PixelFormat FramebufferManager::GetResolvedEFBColorTexture(); } - // stretch picture with increased internal resolution - const D3D12_VIEWPORT vp = { - 0.f, - 0.f, - static_cast(config.width), - static_cast(config.height), - D3D12_MIN_DEPTH, - D3D12_MAX_DEPTH - }; - - D3D::current_command_list->RSSetViewports(1, &vp); - // set transformation if (cbuf_id != old_cbuf_id) { @@ -311,6 +291,9 @@ void TextureCache::TCacheEntry::FromRenderTarget(u8* dst, PEControl::PixelFormat old_cbuf_id = cbuf_id; } + // stretch picture with increased internal resolution + D3D::SetViewportAndScissor(0, 0, config.width, config.height); + D3D::current_command_list->SetGraphicsRootConstantBufferView(DESCRIPTOR_TABLE_PS_CBVONE, s_efb_copy_stream_buffer->GetGPUAddressOfCurrentAllocation()); D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PS_CBV, true); @@ -441,14 +424,13 @@ void main( void TextureCache::ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, TlutFormat format) { - // stretch picture with increased internal resolution - const D3D12_VIEWPORT vp = { 0.f, 0.f, static_cast(unconverted->config.width), static_cast(unconverted->config.height), D3D12_MIN_DEPTH, D3D12_MAX_DEPTH }; - D3D::current_command_list->RSSetViewports(1, &vp); - const unsigned int palette_buffer_allocation_size = 512; m_palette_stream_buffer->AllocateSpaceInBuffer(palette_buffer_allocation_size, 256); memcpy(m_palette_stream_buffer->GetCPUAddressOfCurrentAllocation(), palette, palette_buffer_allocation_size); + // stretch picture with increased internal resolution + D3D::SetViewportAndScissor(0, 0, unconverted->config.width, unconverted->config.height); + // D3D12: Because the second SRV slot is occupied by this buffer, and an arbitrary texture occupies the first SRV slot, // we need to allocate temporary space out of our descriptor heap, place the palette SRV in the second slot, then copy the // existing texture's descriptor into the first slot. -- cgit v1.2.3 From c793459b88651513b4f2f5ed5795f1561f67cb1d Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 24 Feb 2016 00:31:14 +1000 Subject: D3D12: Fixed issue where EFB copies could end up corrupted after reset Also prevents previously-released textures from ending up in a descriptor table. --- Source/Core/VideoBackends/D3D12/TextureCache.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'Source/Core/VideoBackends/D3D12/TextureCache.cpp') diff --git a/Source/Core/VideoBackends/D3D12/TextureCache.cpp b/Source/Core/VideoBackends/D3D12/TextureCache.cpp index 37660b9136..9ecc7e6123 100644 --- a/Source/Core/VideoBackends/D3D12/TextureCache.cpp +++ b/Source/Core/VideoBackends/D3D12/TextureCache.cpp @@ -25,6 +25,7 @@ namespace DX12 static std::unique_ptr s_encoder = nullptr; static std::unique_ptr s_efb_copy_stream_buffer = nullptr; +static u32 s_efb_copy_last_cbuf_id = UINT_MAX; static ID3D12Resource* s_texture_cache_entry_readback_buffer = nullptr; static void* s_texture_cache_entry_readback_buffer_data = nullptr; @@ -264,8 +265,6 @@ TextureCacheBase::TCacheEntryBase* TextureCache::CreateTexture(const TCacheEntry void TextureCache::TCacheEntry::FromRenderTarget(u8* dst, PEControl::PixelFormat src_format, const EFBRectangle& srcRect, bool scale_by_half, unsigned int cbuf_id, const float* colmat) { - static unsigned int old_cbuf_id = UINT_MAX; - // When copying at half size, in multisampled mode, resolve the color/depth buffer first. // This is because multisampled texture reads go through Load, not Sample, and the linear // filter is ignored. @@ -282,13 +281,13 @@ void TextureCache::TCacheEntry::FromRenderTarget(u8* dst, PEControl::PixelFormat } // set transformation - if (cbuf_id != old_cbuf_id) + if (s_efb_copy_last_cbuf_id != cbuf_id) { s_efb_copy_stream_buffer->AllocateSpaceInBuffer(28 * sizeof(float), 256); memcpy(s_efb_copy_stream_buffer->GetCPUAddressOfCurrentAllocation(), colmat, 28 * sizeof(float)); - old_cbuf_id = cbuf_id; + s_efb_copy_last_cbuf_id = cbuf_id; } // stretch picture with increased internal resolution @@ -536,6 +535,7 @@ TextureCache::TextureCache() s_encoder->Init(); s_efb_copy_stream_buffer = std::make_unique(1024 * 1024, 1024 * 1024, nullptr); + s_efb_copy_last_cbuf_id = UINT_MAX; s_texture_cache_entry_readback_buffer = nullptr; s_texture_cache_entry_readback_buffer_data = nullptr; @@ -617,7 +617,7 @@ void TextureCache::BindTextures() D3D12_GPU_DESCRIPTOR_HANDLE s_group_base_texture_gpu_handle; DX12::D3D::gpu_descriptor_heap_mgr->AllocateGroup(&s_group_base_texture_cpu_handle, 8, &s_group_base_texture_gpu_handle, nullptr, true); - for (unsigned int stage = 0; stage <= last_texture; stage++) + for (unsigned int stage = 0; stage < 8; stage++) { if (bound_textures[stage] != nullptr) { -- cgit v1.2.3 From 0a96e2f53117aaa3e094b1ea4282c5aea08e8fd8 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 24 Feb 2016 22:53:24 +1000 Subject: D3D11: Fix texture dumping, for both single and multi-mip textures --- Source/Core/VideoBackends/D3D12/TextureCache.cpp | 81 ++++++++++-------------- 1 file changed, 33 insertions(+), 48 deletions(-) (limited to 'Source/Core/VideoBackends/D3D12/TextureCache.cpp') diff --git a/Source/Core/VideoBackends/D3D12/TextureCache.cpp b/Source/Core/VideoBackends/D3D12/TextureCache.cpp index 9ecc7e6123..309e62c6fc 100644 --- a/Source/Core/VideoBackends/D3D12/TextureCache.cpp +++ b/Source/Core/VideoBackends/D3D12/TextureCache.cpp @@ -28,8 +28,7 @@ static std::unique_ptr s_efb_copy_stream_buffer = nullptr; static u32 s_efb_copy_last_cbuf_id = UINT_MAX; static ID3D12Resource* s_texture_cache_entry_readback_buffer = nullptr; -static void* s_texture_cache_entry_readback_buffer_data = nullptr; -static UINT s_texture_cache_entry_readback_buffer_size = 0; +static size_t s_texture_cache_entry_readback_buffer_size = 0; TextureCache::TCacheEntry::~TCacheEntry() { @@ -43,47 +42,27 @@ void TextureCache::TCacheEntry::Bind(unsigned int stage) bool TextureCache::TCacheEntry::Save(const std::string& filename, unsigned int level) { - // EXISTINGD3D11TODO: Somehow implement this (D3DX11 doesn't support dumping individual LODs) - static bool warn_once = true; - if (level && warn_once) - { - WARN_LOG(VIDEO, "Dumping individual LOD not supported by D3D12 backend!"); - warn_once = false; - return false; - } - - D3D12_RESOURCE_DESC texture_desc = m_texture->GetTex12()->GetDesc(); - - const unsigned int required_readback_buffer_size = D3D::AlignValue(static_cast(texture_desc.Width) * 4, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); - - if (s_texture_cache_entry_readback_buffer_size < required_readback_buffer_size) - { - s_texture_cache_entry_readback_buffer_size = required_readback_buffer_size; - - // We know the readback buffer won't be in use right now, since we wait on this thread - // for the GPU to finish execution right after copying to it. + u32 level_width = std::max(config.width >> level, 1u); + u32 level_height = std::max(config.height >> level, 1u); + size_t level_pitch = D3D::AlignValue(level_width * sizeof(u32), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); + size_t required_readback_buffer_size = level_pitch * level_height; - SAFE_RELEASE(s_texture_cache_entry_readback_buffer); - } - - if (!s_texture_cache_entry_readback_buffer_size) + // Check if the current readback buffer is large enough + if (required_readback_buffer_size > s_texture_cache_entry_readback_buffer_size) { - CheckHR( - D3D::device12->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), - D3D12_HEAP_FLAG_NONE, - &CD3DX12_RESOURCE_DESC::Buffer(s_texture_cache_entry_readback_buffer_size), - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr, - IID_PPV_ARGS(&s_texture_cache_entry_readback_buffer) - ) - ); + // Reallocate the buffer with the new size. Safe to immediately release because we're the only user and we block until completion. + if (s_texture_cache_entry_readback_buffer) + s_texture_cache_entry_readback_buffer->Release(); - CheckHR(s_texture_cache_entry_readback_buffer->Map(0, nullptr, &s_texture_cache_entry_readback_buffer_data)); + s_texture_cache_entry_readback_buffer_size = required_readback_buffer_size; + CheckHR(D3D::device12->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), + D3D12_HEAP_FLAG_NONE, + &CD3DX12_RESOURCE_DESC::Buffer(s_texture_cache_entry_readback_buffer_size), + D3D12_RESOURCE_STATE_COPY_DEST, + nullptr, + IID_PPV_ARGS(&s_texture_cache_entry_readback_buffer))); } - bool saved_png = false; - m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_SOURCE); D3D12_TEXTURE_COPY_LOCATION dst_location = {}; @@ -91,26 +70,31 @@ bool TextureCache::TCacheEntry::Save(const std::string& filename, unsigned int l dst_location.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; dst_location.PlacedFootprint.Offset = 0; dst_location.PlacedFootprint.Footprint.Depth = 1; - dst_location.PlacedFootprint.Footprint.Format = texture_desc.Format; - dst_location.PlacedFootprint.Footprint.Width = static_cast(texture_desc.Width); - dst_location.PlacedFootprint.Footprint.Height = texture_desc.Height; - dst_location.PlacedFootprint.Footprint.RowPitch = D3D::AlignValue(dst_location.PlacedFootprint.Footprint.Width * 4, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); + dst_location.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + dst_location.PlacedFootprint.Footprint.Width = level_width; + dst_location.PlacedFootprint.Footprint.Height = level_height; + dst_location.PlacedFootprint.Footprint.RowPitch = static_cast(level_pitch); - D3D12_TEXTURE_COPY_LOCATION src_location = CD3DX12_TEXTURE_COPY_LOCATION(m_texture->GetTex12(), 0); + D3D12_TEXTURE_COPY_LOCATION src_location = CD3DX12_TEXTURE_COPY_LOCATION(m_texture->GetTex12(), level); D3D::current_command_list->CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, nullptr); D3D::command_list_mgr->ExecuteQueuedWork(true); - saved_png = TextureToPng( - static_cast(s_texture_cache_entry_readback_buffer_data), + // Map readback buffer and save to file. + void* readback_texture_map; + CheckHR(s_texture_cache_entry_readback_buffer->Map(0, nullptr, &readback_texture_map)); + + bool saved = TextureToPng( + static_cast(readback_texture_map), dst_location.PlacedFootprint.Footprint.RowPitch, filename, dst_location.PlacedFootprint.Footprint.Width, dst_location.PlacedFootprint.Footprint.Height ); - return saved_png; + s_texture_cache_entry_readback_buffer->Unmap(0, nullptr); + return saved; } void TextureCache::TCacheEntry::CopyRectangleFromTexture( @@ -538,7 +522,6 @@ TextureCache::TextureCache() s_efb_copy_last_cbuf_id = UINT_MAX; s_texture_cache_entry_readback_buffer = nullptr; - s_texture_cache_entry_readback_buffer_data = nullptr; s_texture_cache_entry_readback_buffer_size = 0; m_palette_pixel_shaders[GX_TL_IA8] = GetConvertShader12(std::string("IA8")); @@ -588,8 +571,10 @@ TextureCache::~TextureCache() if (s_texture_cache_entry_readback_buffer) { - D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(s_texture_cache_entry_readback_buffer); + // Safe to destroy the readback buffer immediately, as the only time it's used is blocked until completion. + s_texture_cache_entry_readback_buffer->Release(); s_texture_cache_entry_readback_buffer = nullptr; + s_texture_cache_entry_readback_buffer_size = 0; } D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_palette_uniform_buffer); -- cgit v1.2.3