From d827bbeb6cc5bd2120350e9dc0c4998a8c36a1fe Mon Sep 17 00:00:00 2001 From: Triang3l Date: Thu, 4 Oct 2018 23:57:08 +0300 Subject: [PATCH] [D3D12] Fix texture binding hashing --- .../gpu/d3d12/d3d12_command_processor.cc | 44 ++++++++++++------- src/xenia/gpu/d3d12/d3d12_command_processor.h | 12 +++-- src/xenia/gpu/d3d12/texture_cache.cc | 41 ++++++----------- src/xenia/gpu/d3d12/texture_cache.h | 16 +++---- 4 files changed, 57 insertions(+), 56 deletions(-) diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.cc b/src/xenia/gpu/d3d12/d3d12_command_processor.cc index e7fd98c8a..1a0625b4a 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.cc +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.cc @@ -1166,11 +1166,9 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type, } // Update the textures - this may bind pipelines. - uint64_t new_texture_bindings_hash_vertex, new_texture_bindings_hash_pixel; texture_cache_->RequestTextures( vertex_shader->GetUsedTextureMask(), - pixel_shader != nullptr ? pixel_shader->GetUsedTextureMask() : 0, - new_texture_bindings_hash_vertex, new_texture_bindings_hash_pixel); + pixel_shader != nullptr ? pixel_shader->GetUsedTextureMask() : 0); // Update viewport, scissor, blend factor and stencil reference. UpdateFixedFunctionState(command_list); @@ -1187,9 +1185,8 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type, pipeline_render_targets); // Update constant buffers, descriptors and root parameters. - if (!UpdateBindings(command_list, vertex_shader, pixel_shader, root_signature, - new_texture_bindings_hash_vertex, - new_texture_bindings_hash_pixel)) { + if (!UpdateBindings(command_list, vertex_shader, pixel_shader, + root_signature)) { return false; } @@ -1338,8 +1335,8 @@ bool D3D12CommandProcessor::BeginFrame() { cbuffer_bindings_fetch_.up_to_date = false; draw_view_full_update_ = 0; draw_sampler_full_update_ = 0; - texture_bindings_hash_vertex_ = texture_bindings_hash_pixel_ = - texture_cache_->GetEmptyTextureBindingsHash(); + texture_bindings_written_vertex_ = false; + texture_bindings_written_pixel_ = false; primitive_topology_ = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; command_lists_[current_queue_frame_]->BeginRecording(); @@ -1802,9 +1799,7 @@ void D3D12CommandProcessor::UpdateSystemConstantValues( bool D3D12CommandProcessor::UpdateBindings( ID3D12GraphicsCommandList* command_list, const D3D12Shader* vertex_shader, - const D3D12Shader* pixel_shader, ID3D12RootSignature* root_signature, - uint64_t new_texture_bindings_hash_vertex, - uint64_t new_texture_bindings_hash_pixel) { + const D3D12Shader* pixel_shader, ID3D12RootSignature* root_signature) { auto provider = GetD3D12Context()->GetD3D12Provider(); auto device = provider->GetDevice(); auto& regs = *register_file_; @@ -1836,9 +1831,19 @@ bool D3D12CommandProcessor::UpdateBindings( pixel_samplers = nullptr; pixel_sampler_count = 0; } + uint64_t new_pixel_texture_bindings_hash = + pixel_texture_count != 0 + ? texture_cache_->GetDescriptorHashForActiveTextures( + pixel_textures, pixel_texture_count) + : 0; uint32_t vertex_texture_count, vertex_sampler_count; const D3D12Shader::TextureSRV* vertex_textures = vertex_shader->GetTextureSRVs(vertex_texture_count); + uint64_t new_vertex_texture_bindings_hash = + vertex_texture_count != 0 + ? texture_cache_->GetDescriptorHashForActiveTextures( + vertex_textures, vertex_texture_count) + : 0; const D3D12Shader::SamplerBinding* vertex_samplers = vertex_shader->GetSamplerBindings(vertex_sampler_count); uint32_t sampler_count = pixel_sampler_count + vertex_sampler_count; @@ -1849,14 +1854,15 @@ bool D3D12CommandProcessor::UpdateBindings( bool write_pixel_float_constant_view = false; bool write_bool_loop_constant_view = false; bool write_fetch_constant_view = false; - // TODO(Triang3l): Update samplers only if shaders or binding - // hash change. + // TODO(Triang3l): Update samplers only if shaders or binding hash change. bool write_vertex_textures = vertex_texture_count != 0 && - (texture_bindings_hash_vertex_ != new_texture_bindings_hash_vertex); + (!texture_bindings_written_vertex_ || + texture_bindings_hash_vertex_ != new_vertex_texture_bindings_hash); bool write_pixel_textures = pixel_texture_count != 0 && - (texture_bindings_hash_pixel_ != new_texture_bindings_hash_pixel); + (!texture_bindings_written_pixel_ || + texture_bindings_hash_pixel_ != new_pixel_texture_bindings_hash); bool write_samplers = sampler_count != 0; // Check if the float constant layout is still the same and get the counts. @@ -2068,6 +2074,8 @@ bool D3D12CommandProcessor::UpdateBindings( write_bool_loop_constant_view = true; write_vertex_textures = vertex_texture_count != 0; write_pixel_textures = pixel_texture_count != 0; + texture_bindings_written_vertex_ = false; + texture_bindings_written_pixel_ = false; // If updating fully, write the shared memory descriptor (t0). shared_memory_->CreateSRV(view_cpu_handle); gpu_handle_shared_memory_ = view_gpu_handle; @@ -2153,7 +2161,8 @@ bool D3D12CommandProcessor::UpdateBindings( view_cpu_handle.ptr += descriptor_size_view; view_gpu_handle.ptr += descriptor_size_view; } - texture_bindings_hash_pixel_ = new_texture_bindings_hash_pixel; + texture_bindings_written_pixel_ = true; + texture_bindings_hash_pixel_ = new_pixel_texture_bindings_hash; current_graphics_root_up_to_date_ &= ~(1u << current_graphics_root_extras_.pixel_textures); } @@ -2168,7 +2177,8 @@ bool D3D12CommandProcessor::UpdateBindings( view_cpu_handle.ptr += descriptor_size_view; view_gpu_handle.ptr += descriptor_size_view; } - texture_bindings_hash_vertex_ = new_texture_bindings_hash_vertex; + texture_bindings_written_vertex_ = true; + texture_bindings_hash_vertex_ = new_vertex_texture_bindings_hash; current_graphics_root_up_to_date_ &= ~(1u << current_graphics_root_extras_.vertex_textures); } diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.h b/src/xenia/gpu/d3d12/d3d12_command_processor.h index 287b2ea83..f9b2b04e6 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.h +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.h @@ -193,9 +193,7 @@ class D3D12CommandProcessor : public CommandProcessor { bool UpdateBindings(ID3D12GraphicsCommandList* command_list, const D3D12Shader* vertex_shader, const D3D12Shader* pixel_shader, - ID3D12RootSignature* root_signature, - uint64_t new_texture_bindings_hash_vertex, - uint64_t new_texture_bindings_hash_pixel); + ID3D12RootSignature* root_signature); bool cache_clear_requested_ = false; @@ -303,7 +301,13 @@ class D3D12CommandProcessor : public CommandProcessor { uint64_t draw_view_full_update_; uint64_t draw_sampler_full_update_; - // Hashes of the current texture descriptor layout. + // Whether the last used texture bindings have been written to the current + // view descriptor heap. + bool texture_bindings_written_vertex_; + bool texture_bindings_written_pixel_; + // Hashes of the last texture bindings written to the current view descriptor + // heap with the last used descriptor layout. Valid only when the + // corresponding "written" variables are true. uint64_t texture_bindings_hash_vertex_; uint64_t texture_bindings_hash_pixel_; diff --git a/src/xenia/gpu/d3d12/texture_cache.cc b/src/xenia/gpu/d3d12/texture_cache.cc index ddcf51d82..8caa2f48f 100644 --- a/src/xenia/gpu/d3d12/texture_cache.cc +++ b/src/xenia/gpu/d3d12/texture_cache.cc @@ -294,11 +294,7 @@ TextureCache::TextureCache(D3D12CommandProcessor* command_processor, SharedMemory* shared_memory) : command_processor_(command_processor), register_file_(register_file), - shared_memory_(shared_memory) { - XXH64_state_t hash_state; - XXH64_reset(&hash_state, 0); - texture_bindings_empty_hash_ = XXH64_digest(&hash_state); -} + shared_memory_(shared_memory) {} TextureCache::~TextureCache() { Shutdown(); } @@ -433,9 +429,7 @@ void TextureCache::EndFrame() { } void TextureCache::RequestTextures(uint32_t used_vertex_texture_mask, - uint32_t used_pixel_texture_mask, - uint64_t& descriptor_layout_vertex_hash_out, - uint64_t& descriptor_layout_pixel_hash_out) { + uint32_t used_pixel_texture_mask) { auto command_list = command_processor_->GetCurrentCommandList(); if (command_list == nullptr) { return; @@ -506,31 +500,24 @@ void TextureCache::RequestTextures(uint32_t used_vertex_texture_mask, state); texture->state = state; } +} - // Compute descriptor layout hashes so descriptors don't have to be written - // again if the bindings are the same. The hash is computed from indices, keys - // and swizzles. +uint64_t TextureCache::GetDescriptorHashForActiveTextures( + const D3D12Shader::TextureSRV* texture_srvs, + uint32_t texture_srv_count) const { XXH64_state_t hash_state; XXH64_reset(&hash_state, 0); - used_texture_mask = used_vertex_texture_mask; - while (xe::bit_scan_forward(used_texture_mask, &index)) { - used_texture_mask &= ~(1u << index); - XXH64_update(&hash_state, &index, sizeof(index)); - const TextureBinding& binding = texture_bindings_[index]; + for (uint32_t i = 0; i < texture_srv_count; ++i) { + const D3D12Shader::TextureSRV& texture_srv = texture_srvs[i]; + // There can be multiple SRVs of the same texture. + XXH64_update(&hash_state, &texture_srv.dimension, + sizeof(texture_srv.dimension)); + const TextureBinding& binding = + texture_bindings_[texture_srv.fetch_constant]; XXH64_update(&hash_state, &binding.key, sizeof(binding.key)); XXH64_update(&hash_state, &binding.swizzle, sizeof(binding.swizzle)); } - descriptor_layout_vertex_hash_out = XXH64_digest(&hash_state); - XXH64_reset(&hash_state, 0); - used_texture_mask = used_pixel_texture_mask; - while (xe::bit_scan_forward(used_texture_mask, &index)) { - used_texture_mask &= ~(1u << index); - XXH64_update(&hash_state, &index, sizeof(index)); - const TextureBinding& binding = texture_bindings_[index]; - XXH64_update(&hash_state, &binding.key, sizeof(binding.key)); - XXH64_update(&hash_state, &binding.swizzle, sizeof(binding.swizzle)); - } - descriptor_layout_pixel_hash_out = XXH64_digest(&hash_state); + return XXH64_digest(&hash_state); } void TextureCache::WriteTextureSRV(uint32_t fetch_constant, diff --git a/src/xenia/gpu/d3d12/texture_cache.h b/src/xenia/gpu/d3d12/texture_cache.h index d383db412..11da4ae1a 100644 --- a/src/xenia/gpu/d3d12/texture_cache.h +++ b/src/xenia/gpu/d3d12/texture_cache.h @@ -13,6 +13,7 @@ #include #include +#include "xenia/gpu/d3d12/d3d12_shader.h" #include "xenia/gpu/d3d12/shared_memory.h" #include "xenia/gpu/register_file.h" #include "xenia/gpu/texture_info.h" @@ -72,12 +73,13 @@ class TextureCache { // (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, - uint64_t& descriptor_layout_vertex_hash_out, - uint64_t& descriptor_layout_pixel_hash_out); - inline uint64_t GetEmptyTextureBindingsHash() const { - return texture_bindings_empty_hash_; - } + uint32_t used_pixel_texture_mask); + + // Returns the hash of the current bindings (must be called after + // RequestTextures) for the provided SRV descriptor layout. + uint64_t GetDescriptorHashForActiveTextures( + const D3D12Shader::TextureSRV* texture_srvs, + uint32_t texture_srv_count) const; void WriteTextureSRV(uint32_t fetch_constant, TextureDimension shader_dimension, @@ -371,8 +373,6 @@ class TextureCache { std::unordered_multimap textures_; TextureBinding texture_bindings_[32] = {}; - // Hash for no textures bound. - uint64_t texture_bindings_empty_hash_; // Bit vector with bits reset on fetch constant writes to avoid getting // texture keys from the fetch constants again and again. uint32_t texture_keys_in_sync_ = 0;