From 8341a482103bd733dc8f0ba725ea42b882d52bf9 Mon Sep 17 00:00:00 2001 From: Triang3l Date: Sat, 16 May 2020 19:33:22 +0300 Subject: [PATCH] [D3D12] Fix state of textures bound to both VS and PS --- .../gpu/d3d12/d3d12_command_processor.cc | 4 +- src/xenia/gpu/d3d12/texture_cache.cc | 54 ++++++++++--------- src/xenia/gpu/d3d12/texture_cache.h | 4 +- 3 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.cc b/src/xenia/gpu/d3d12/d3d12_command_processor.cc index be889cea0..ce1d48316 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.cc +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.cc @@ -1409,8 +1409,8 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type, // Update the textures - this may bind pipelines. texture_cache_->RequestTextures( - vertex_shader->GetUsedTextureMask(), - pixel_shader != nullptr ? pixel_shader->GetUsedTextureMask() : 0); + vertex_shader->GetUsedTextureMask() | + (pixel_shader != nullptr ? pixel_shader->GetUsedTextureMask() : 0)); // Check if early depth/stencil can be enabled. bool early_z; diff --git a/src/xenia/gpu/d3d12/texture_cache.cc b/src/xenia/gpu/d3d12/texture_cache.cc index a7bc23641..7740f9ec1 100644 --- a/src/xenia/gpu/d3d12/texture_cache.cc +++ b/src/xenia/gpu/d3d12/texture_cache.cc @@ -1250,8 +1250,7 @@ void TextureCache::EndFrame() { } } -void TextureCache::RequestTextures(uint32_t used_vertex_texture_mask, - uint32_t used_pixel_texture_mask) { +void TextureCache::RequestTextures(uint32_t used_texture_mask) { auto& regs = *register_file_; #if FINE_GRAINED_DRAW_SCOPES @@ -1268,12 +1267,11 @@ void TextureCache::RequestTextures(uint32_t used_vertex_texture_mask, } // Update the texture keys and the textures. - uint32_t used_texture_mask = - used_vertex_texture_mask | used_pixel_texture_mask; + uint32_t textures_remaining = used_texture_mask; uint32_t index = 0; - while (xe::bit_scan_forward(used_texture_mask, &index)) { - uint32_t index_bit = 1u << index; - used_texture_mask &= ~index_bit; + while (xe::bit_scan_forward(textures_remaining, &index)) { + uint32_t index_bit = uint32_t(1) << index; + textures_remaining &= ~index_bit; if (texture_keys_in_sync_ & index_bit) { continue; } @@ -1337,34 +1335,35 @@ void TextureCache::RequestTextures(uint32_t used_vertex_texture_mask, } } - // Transition the textures to the needed usage. - used_texture_mask = used_vertex_texture_mask | used_pixel_texture_mask; - while (xe::bit_scan_forward(used_texture_mask, &index)) { - uint32_t index_bit = 1u << index; - used_texture_mask &= ~index_bit; - - D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATES(0); - if (used_vertex_texture_mask & index_bit) { - state |= D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; - } - if (used_pixel_texture_mask & index_bit) { - state |= D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; - } - + // Transition the textures to the needed usage - always in + // NON_PIXEL_SHADER_RESOURCE | PIXEL_SHADER_RESOURCE states because barriers + // between read-only stages, if needed, are discouraged (also if these were + // tracked separately, checks would be needed to make sure, if the same + // texture is bound through different fetch constants to both VS and PS, it + // would be in both states). + textures_remaining = used_texture_mask; + while (xe::bit_scan_forward(textures_remaining, &index)) { + textures_remaining &= ~(uint32_t(1) << index); TextureBinding& binding = texture_bindings_[index]; if (binding.texture != nullptr) { // Will be referenced by the command list, so mark as used. MarkTextureUsed(binding.texture); - command_processor_->PushTransitionBarrier(binding.texture->resource, - binding.texture->state, state); - binding.texture->state = state; + command_processor_->PushTransitionBarrier( + binding.texture->resource, binding.texture->state, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + binding.texture->state = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; } if (binding.texture_signed != nullptr) { MarkTextureUsed(binding.texture_signed); command_processor_->PushTransitionBarrier( binding.texture_signed->resource, binding.texture_signed->state, - state); - binding.texture_signed->state = state; + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + binding.texture_signed->state = + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; } } } @@ -2028,6 +2027,9 @@ bool TextureCache::RequestSwapTexture(D3D12_CPU_DESCRIPTOR_HANDLE handle, return false; } MarkTextureUsed(texture); + // The swap texture is likely to be used only for the presentation pixel + // shader, and not during emulation, where it'd be NON_PIXEL_SHADER_RESOURCE | + // PIXEL_SHADER_RESOURCE. command_processor_->PushTransitionBarrier( texture->resource, texture->state, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); diff --git a/src/xenia/gpu/d3d12/texture_cache.h b/src/xenia/gpu/d3d12/texture_cache.h index ab1d2d4cc..dbeb0cc2d 100644 --- a/src/xenia/gpu/d3d12/texture_cache.h +++ b/src/xenia/gpu/d3d12/texture_cache.h @@ -109,8 +109,7 @@ class TextureCache { // shaders and puts them in the SRV state. This may bind compute pipelines // (notifying the command processor about that), so this must be called before // binding the actual drawing pipeline. - void RequestTextures(uint32_t used_vertex_texture_mask, - uint32_t used_pixel_texture_mask); + void RequestTextures(uint32_t used_texture_mask); // Returns the hash of the current bindings (must be called after // RequestTextures) for the provided SRV descriptor layout. @@ -160,6 +159,7 @@ class TextureCache { uint32_t first_unscaled_4kb_page, uint32_t unscaled_4kb_page_count); + // Returns a descriptor of the front buffer in PIXEL_SHADER_RESOURCE state. bool RequestSwapTexture(D3D12_CPU_DESCRIPTOR_HANDLE handle, TextureFormat& format_out);