[D3D12] Fix texture binding hashing

This commit is contained in:
Triang3l 2018-10-04 23:57:08 +03:00
parent 131525e44d
commit d827bbeb6c
4 changed files with 57 additions and 56 deletions

View File

@ -1166,11 +1166,9 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type,
} }
// Update the textures - this may bind pipelines. // Update the textures - this may bind pipelines.
uint64_t new_texture_bindings_hash_vertex, new_texture_bindings_hash_pixel;
texture_cache_->RequestTextures( texture_cache_->RequestTextures(
vertex_shader->GetUsedTextureMask(), vertex_shader->GetUsedTextureMask(),
pixel_shader != nullptr ? pixel_shader->GetUsedTextureMask() : 0, pixel_shader != nullptr ? pixel_shader->GetUsedTextureMask() : 0);
new_texture_bindings_hash_vertex, new_texture_bindings_hash_pixel);
// Update viewport, scissor, blend factor and stencil reference. // Update viewport, scissor, blend factor and stencil reference.
UpdateFixedFunctionState(command_list); UpdateFixedFunctionState(command_list);
@ -1187,9 +1185,8 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type,
pipeline_render_targets); pipeline_render_targets);
// Update constant buffers, descriptors and root parameters. // Update constant buffers, descriptors and root parameters.
if (!UpdateBindings(command_list, vertex_shader, pixel_shader, root_signature, if (!UpdateBindings(command_list, vertex_shader, pixel_shader,
new_texture_bindings_hash_vertex, root_signature)) {
new_texture_bindings_hash_pixel)) {
return false; return false;
} }
@ -1338,8 +1335,8 @@ bool D3D12CommandProcessor::BeginFrame() {
cbuffer_bindings_fetch_.up_to_date = false; cbuffer_bindings_fetch_.up_to_date = false;
draw_view_full_update_ = 0; draw_view_full_update_ = 0;
draw_sampler_full_update_ = 0; draw_sampler_full_update_ = 0;
texture_bindings_hash_vertex_ = texture_bindings_hash_pixel_ = texture_bindings_written_vertex_ = false;
texture_cache_->GetEmptyTextureBindingsHash(); texture_bindings_written_pixel_ = false;
primitive_topology_ = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; primitive_topology_ = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
command_lists_[current_queue_frame_]->BeginRecording(); command_lists_[current_queue_frame_]->BeginRecording();
@ -1802,9 +1799,7 @@ void D3D12CommandProcessor::UpdateSystemConstantValues(
bool D3D12CommandProcessor::UpdateBindings( bool D3D12CommandProcessor::UpdateBindings(
ID3D12GraphicsCommandList* command_list, const D3D12Shader* vertex_shader, ID3D12GraphicsCommandList* command_list, const D3D12Shader* vertex_shader,
const D3D12Shader* pixel_shader, ID3D12RootSignature* root_signature, const D3D12Shader* pixel_shader, ID3D12RootSignature* root_signature) {
uint64_t new_texture_bindings_hash_vertex,
uint64_t new_texture_bindings_hash_pixel) {
auto provider = GetD3D12Context()->GetD3D12Provider(); auto provider = GetD3D12Context()->GetD3D12Provider();
auto device = provider->GetDevice(); auto device = provider->GetDevice();
auto& regs = *register_file_; auto& regs = *register_file_;
@ -1836,9 +1831,19 @@ bool D3D12CommandProcessor::UpdateBindings(
pixel_samplers = nullptr; pixel_samplers = nullptr;
pixel_sampler_count = 0; 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; uint32_t vertex_texture_count, vertex_sampler_count;
const D3D12Shader::TextureSRV* vertex_textures = const D3D12Shader::TextureSRV* vertex_textures =
vertex_shader->GetTextureSRVs(vertex_texture_count); 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 = const D3D12Shader::SamplerBinding* vertex_samplers =
vertex_shader->GetSamplerBindings(vertex_sampler_count); vertex_shader->GetSamplerBindings(vertex_sampler_count);
uint32_t sampler_count = pixel_sampler_count + 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_pixel_float_constant_view = false;
bool write_bool_loop_constant_view = false; bool write_bool_loop_constant_view = false;
bool write_fetch_constant_view = false; bool write_fetch_constant_view = false;
// TODO(Triang3l): Update samplers only if shaders or binding // TODO(Triang3l): Update samplers only if shaders or binding hash change.
// hash change.
bool write_vertex_textures = bool write_vertex_textures =
vertex_texture_count != 0 && 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 = bool write_pixel_textures =
pixel_texture_count != 0 && 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; bool write_samplers = sampler_count != 0;
// Check if the float constant layout is still the same and get the counts. // 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_bool_loop_constant_view = true;
write_vertex_textures = vertex_texture_count != 0; write_vertex_textures = vertex_texture_count != 0;
write_pixel_textures = pixel_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). // If updating fully, write the shared memory descriptor (t0).
shared_memory_->CreateSRV(view_cpu_handle); shared_memory_->CreateSRV(view_cpu_handle);
gpu_handle_shared_memory_ = view_gpu_handle; gpu_handle_shared_memory_ = view_gpu_handle;
@ -2153,7 +2161,8 @@ bool D3D12CommandProcessor::UpdateBindings(
view_cpu_handle.ptr += descriptor_size_view; view_cpu_handle.ptr += descriptor_size_view;
view_gpu_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_ &= current_graphics_root_up_to_date_ &=
~(1u << current_graphics_root_extras_.pixel_textures); ~(1u << current_graphics_root_extras_.pixel_textures);
} }
@ -2168,7 +2177,8 @@ bool D3D12CommandProcessor::UpdateBindings(
view_cpu_handle.ptr += descriptor_size_view; view_cpu_handle.ptr += descriptor_size_view;
view_gpu_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_ &= current_graphics_root_up_to_date_ &=
~(1u << current_graphics_root_extras_.vertex_textures); ~(1u << current_graphics_root_extras_.vertex_textures);
} }

View File

@ -193,9 +193,7 @@ class D3D12CommandProcessor : public CommandProcessor {
bool UpdateBindings(ID3D12GraphicsCommandList* command_list, bool UpdateBindings(ID3D12GraphicsCommandList* command_list,
const D3D12Shader* vertex_shader, const D3D12Shader* vertex_shader,
const D3D12Shader* pixel_shader, const D3D12Shader* pixel_shader,
ID3D12RootSignature* root_signature, ID3D12RootSignature* root_signature);
uint64_t new_texture_bindings_hash_vertex,
uint64_t new_texture_bindings_hash_pixel);
bool cache_clear_requested_ = false; bool cache_clear_requested_ = false;
@ -303,7 +301,13 @@ class D3D12CommandProcessor : public CommandProcessor {
uint64_t draw_view_full_update_; uint64_t draw_view_full_update_;
uint64_t draw_sampler_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_vertex_;
uint64_t texture_bindings_hash_pixel_; uint64_t texture_bindings_hash_pixel_;

View File

@ -294,11 +294,7 @@ TextureCache::TextureCache(D3D12CommandProcessor* command_processor,
SharedMemory* shared_memory) SharedMemory* shared_memory)
: command_processor_(command_processor), : command_processor_(command_processor),
register_file_(register_file), register_file_(register_file),
shared_memory_(shared_memory) { shared_memory_(shared_memory) {}
XXH64_state_t hash_state;
XXH64_reset(&hash_state, 0);
texture_bindings_empty_hash_ = XXH64_digest(&hash_state);
}
TextureCache::~TextureCache() { Shutdown(); } TextureCache::~TextureCache() { Shutdown(); }
@ -433,9 +429,7 @@ void TextureCache::EndFrame() {
} }
void TextureCache::RequestTextures(uint32_t used_vertex_texture_mask, void TextureCache::RequestTextures(uint32_t used_vertex_texture_mask,
uint32_t used_pixel_texture_mask, uint32_t used_pixel_texture_mask) {
uint64_t& descriptor_layout_vertex_hash_out,
uint64_t& descriptor_layout_pixel_hash_out) {
auto command_list = command_processor_->GetCurrentCommandList(); auto command_list = command_processor_->GetCurrentCommandList();
if (command_list == nullptr) { if (command_list == nullptr) {
return; return;
@ -506,31 +500,24 @@ void TextureCache::RequestTextures(uint32_t used_vertex_texture_mask,
state); state);
texture->state = state; texture->state = state;
} }
}
// Compute descriptor layout hashes so descriptors don't have to be written uint64_t TextureCache::GetDescriptorHashForActiveTextures(
// again if the bindings are the same. The hash is computed from indices, keys const D3D12Shader::TextureSRV* texture_srvs,
// and swizzles. uint32_t texture_srv_count) const {
XXH64_state_t hash_state; XXH64_state_t hash_state;
XXH64_reset(&hash_state, 0); XXH64_reset(&hash_state, 0);
used_texture_mask = used_vertex_texture_mask; for (uint32_t i = 0; i < texture_srv_count; ++i) {
while (xe::bit_scan_forward(used_texture_mask, &index)) { const D3D12Shader::TextureSRV& texture_srv = texture_srvs[i];
used_texture_mask &= ~(1u << index); // There can be multiple SRVs of the same texture.
XXH64_update(&hash_state, &index, sizeof(index)); XXH64_update(&hash_state, &texture_srv.dimension,
const TextureBinding& binding = texture_bindings_[index]; 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.key, sizeof(binding.key));
XXH64_update(&hash_state, &binding.swizzle, sizeof(binding.swizzle)); XXH64_update(&hash_state, &binding.swizzle, sizeof(binding.swizzle));
} }
descriptor_layout_vertex_hash_out = XXH64_digest(&hash_state); return 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);
} }
void TextureCache::WriteTextureSRV(uint32_t fetch_constant, void TextureCache::WriteTextureSRV(uint32_t fetch_constant,

View File

@ -13,6 +13,7 @@
#include <atomic> #include <atomic>
#include <unordered_map> #include <unordered_map>
#include "xenia/gpu/d3d12/d3d12_shader.h"
#include "xenia/gpu/d3d12/shared_memory.h" #include "xenia/gpu/d3d12/shared_memory.h"
#include "xenia/gpu/register_file.h" #include "xenia/gpu/register_file.h"
#include "xenia/gpu/texture_info.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 // (notifying the command processor about that), so this must be called before
// binding the actual drawing pipeline. // binding the actual drawing pipeline.
void RequestTextures(uint32_t used_vertex_texture_mask, void RequestTextures(uint32_t used_vertex_texture_mask,
uint32_t used_pixel_texture_mask, uint32_t used_pixel_texture_mask);
uint64_t& descriptor_layout_vertex_hash_out,
uint64_t& descriptor_layout_pixel_hash_out); // Returns the hash of the current bindings (must be called after
inline uint64_t GetEmptyTextureBindingsHash() const { // RequestTextures) for the provided SRV descriptor layout.
return texture_bindings_empty_hash_; uint64_t GetDescriptorHashForActiveTextures(
} const D3D12Shader::TextureSRV* texture_srvs,
uint32_t texture_srv_count) const;
void WriteTextureSRV(uint32_t fetch_constant, void WriteTextureSRV(uint32_t fetch_constant,
TextureDimension shader_dimension, TextureDimension shader_dimension,
@ -371,8 +373,6 @@ class TextureCache {
std::unordered_multimap<uint64_t, Texture*> textures_; std::unordered_multimap<uint64_t, Texture*> textures_;
TextureBinding texture_bindings_[32] = {}; 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 // Bit vector with bits reset on fetch constant writes to avoid getting
// texture keys from the fetch constants again and again. // texture keys from the fetch constants again and again.
uint32_t texture_keys_in_sync_ = 0; uint32_t texture_keys_in_sync_ = 0;