diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.cc b/src/xenia/gpu/d3d12/d3d12_command_processor.cc index 52d0588a8..31b77ef39 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.cc +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.cc @@ -10,6 +10,7 @@ #include "xenia/gpu/d3d12/d3d12_command_processor.h" #include +#include "third_party/xxhash/xxhash.h" #include #include @@ -126,24 +127,26 @@ ID3D12RootSignature* D3D12CommandProcessor::GetRootSignature( assert_true(vertex_shader->is_translated()); assert_true(pixel_shader == nullptr || pixel_shader->is_translated()); - uint32_t pixel_texture_count = 0, pixel_sampler_count = 0; + uint32_t texture_count_vertex, sampler_count_vertex; + vertex_shader->GetTextureSRVs(texture_count_vertex); + vertex_shader->GetSamplerBindings(sampler_count_vertex); + uint32_t texture_count_pixel = 0, sampler_count_pixel = 0; if (pixel_shader != nullptr) { - pixel_shader->GetTextureSRVs(pixel_texture_count); - pixel_shader->GetSamplerBindings(pixel_sampler_count); + pixel_shader->GetTextureSRVs(texture_count_pixel); + pixel_shader->GetSamplerBindings(sampler_count_pixel); } - uint32_t vertex_texture_count, vertex_sampler_count; - vertex_shader->GetTextureSRVs(vertex_texture_count); - vertex_shader->GetSamplerBindings(vertex_sampler_count); + // Better put the pixel texture/sampler in the lower bits probably because it + // changes often. uint32_t index = 0; uint32_t index_offset = 0; - index |= pixel_texture_count << index_offset; + index |= texture_count_pixel << index_offset; index_offset += D3D12Shader::kMaxTextureSRVIndexBits; - index |= pixel_sampler_count << index_offset; + index |= sampler_count_pixel << index_offset; index_offset += D3D12Shader::kMaxSamplerBindingIndexBits; - index |= vertex_texture_count << index_offset; + index |= texture_count_vertex << index_offset; index_offset += D3D12Shader::kMaxTextureSRVIndexBits; - index |= vertex_sampler_count << index_offset; + index |= sampler_count_vertex << index_offset; index_offset += D3D12Shader::kMaxSamplerBindingIndexBits; assert_true(index_offset <= 32); @@ -183,8 +186,8 @@ ID3D12RootSignature* D3D12CommandProcessor::GetRootSignature( // Vertex float constants. { - auto& parameter = parameters[kRootParameter_VertexFloatConstants]; - auto& range = ranges[kRootParameter_VertexFloatConstants]; + auto& parameter = parameters[kRootParameter_FloatConstantsVertex]; + auto& range = ranges[kRootParameter_FloatConstantsVertex]; parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; parameter.DescriptorTable.NumDescriptorRanges = 1; parameter.DescriptorTable.pDescriptorRanges = ⦥ @@ -199,8 +202,8 @@ ID3D12RootSignature* D3D12CommandProcessor::GetRootSignature( // Pixel float constants. { - auto& parameter = parameters[kRootParameter_PixelFloatConstants]; - auto& range = ranges[kRootParameter_PixelFloatConstants]; + auto& parameter = parameters[kRootParameter_FloatConstantsPixel]; + auto& range = ranges[kRootParameter_FloatConstantsPixel]; parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; parameter.DescriptorTable.NumDescriptorRanges = 1; parameter.DescriptorTable.pDescriptorRanges = ⦥ @@ -263,7 +266,7 @@ ID3D12RootSignature* D3D12CommandProcessor::GetRootSignature( // Extra parameters. // Pixel textures. - if (pixel_texture_count > 0) { + if (texture_count_pixel > 0) { auto& parameter = parameters[desc.NumParameters]; auto& range = ranges[desc.NumParameters]; parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; @@ -271,7 +274,7 @@ ID3D12RootSignature* D3D12CommandProcessor::GetRootSignature( parameter.DescriptorTable.pDescriptorRanges = ⦥ parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; - range.NumDescriptors = pixel_texture_count; + range.NumDescriptors = texture_count_pixel; range.BaseShaderRegister = 1; range.RegisterSpace = 0; range.OffsetInDescriptorsFromTableStart = 0; @@ -279,7 +282,7 @@ ID3D12RootSignature* D3D12CommandProcessor::GetRootSignature( } // Pixel samplers. - if (pixel_sampler_count > 0) { + if (sampler_count_pixel > 0) { auto& parameter = parameters[desc.NumParameters]; auto& range = ranges[desc.NumParameters]; parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; @@ -287,7 +290,7 @@ ID3D12RootSignature* D3D12CommandProcessor::GetRootSignature( parameter.DescriptorTable.pDescriptorRanges = ⦥ parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; - range.NumDescriptors = pixel_sampler_count; + range.NumDescriptors = sampler_count_pixel; range.BaseShaderRegister = 0; range.RegisterSpace = 0; range.OffsetInDescriptorsFromTableStart = 0; @@ -295,7 +298,7 @@ ID3D12RootSignature* D3D12CommandProcessor::GetRootSignature( } // Vertex textures. - if (vertex_texture_count > 0) { + if (texture_count_vertex > 0) { auto& parameter = parameters[desc.NumParameters]; auto& range = ranges[desc.NumParameters]; parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; @@ -303,7 +306,7 @@ ID3D12RootSignature* D3D12CommandProcessor::GetRootSignature( parameter.DescriptorTable.pDescriptorRanges = ⦥ parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; - range.NumDescriptors = vertex_texture_count; + range.NumDescriptors = texture_count_vertex; range.BaseShaderRegister = 1; range.RegisterSpace = 0; range.OffsetInDescriptorsFromTableStart = 0; @@ -311,7 +314,7 @@ ID3D12RootSignature* D3D12CommandProcessor::GetRootSignature( } // Vertex samplers. - if (vertex_sampler_count > 0) { + if (sampler_count_vertex > 0) { auto& parameter = parameters[desc.NumParameters]; auto& range = ranges[desc.NumParameters]; parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; @@ -319,7 +322,7 @@ ID3D12RootSignature* D3D12CommandProcessor::GetRootSignature( parameter.DescriptorTable.pDescriptorRanges = ⦥ parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; - range.NumDescriptors = vertex_sampler_count; + range.NumDescriptors = sampler_count_vertex; range.BaseShaderRegister = 0; range.RegisterSpace = 0; range.OffsetInDescriptorsFromTableStart = 0; @@ -332,8 +335,8 @@ ID3D12RootSignature* D3D12CommandProcessor::GetRootSignature( XELOGE( "Failed to create a root signature with %u pixel textures, %u pixel " "samplers, %u vertex textures and %u vertex samplers", - pixel_texture_count, pixel_sampler_count, vertex_texture_count, - vertex_sampler_count); + texture_count_pixel, sampler_count_pixel, texture_count_vertex, + sampler_count_vertex); return nullptr; } root_signatures_.insert({index, root_signature}); @@ -343,35 +346,35 @@ ID3D12RootSignature* D3D12CommandProcessor::GetRootSignature( uint32_t D3D12CommandProcessor::GetRootExtraParameterIndices( const D3D12Shader* vertex_shader, const D3D12Shader* pixel_shader, RootExtraParameterIndices& indices_out) { - uint32_t pixel_texture_count = 0, pixel_sampler_count = 0; + uint32_t texture_count_pixel = 0, sampler_count_pixel = 0; if (pixel_shader != nullptr) { - pixel_shader->GetTextureSRVs(pixel_texture_count); - pixel_shader->GetSamplerBindings(pixel_sampler_count); + pixel_shader->GetTextureSRVs(texture_count_pixel); + pixel_shader->GetSamplerBindings(sampler_count_pixel); } - uint32_t vertex_texture_count, vertex_sampler_count; - vertex_shader->GetTextureSRVs(vertex_texture_count); - vertex_shader->GetSamplerBindings(vertex_sampler_count); + uint32_t texture_count_vertex, sampler_count_vertex; + vertex_shader->GetTextureSRVs(texture_count_vertex); + vertex_shader->GetSamplerBindings(sampler_count_vertex); uint32_t index = kRootParameter_Count_Base; - if (pixel_texture_count != 0) { - indices_out.pixel_textures = index++; + if (texture_count_pixel != 0) { + indices_out.textures_pixel = index++; } else { - indices_out.pixel_textures = RootExtraParameterIndices::kUnavailable; + indices_out.textures_pixel = RootExtraParameterIndices::kUnavailable; } - if (pixel_sampler_count != 0) { - indices_out.pixel_samplers = index++; + if (sampler_count_pixel != 0) { + indices_out.samplers_pixel = index++; } else { - indices_out.pixel_samplers = RootExtraParameterIndices::kUnavailable; + indices_out.samplers_pixel = RootExtraParameterIndices::kUnavailable; } - if (vertex_texture_count != 0) { - indices_out.vertex_textures = index++; + if (texture_count_vertex != 0) { + indices_out.textures_vertex = index++; } else { - indices_out.vertex_textures = RootExtraParameterIndices::kUnavailable; + indices_out.textures_vertex = RootExtraParameterIndices::kUnavailable; } - if (vertex_sampler_count != 0) { - indices_out.vertex_samplers = index++; + if (sampler_count_vertex != 0) { + indices_out.samplers_vertex = index++; } else { - indices_out.vertex_samplers = RootExtraParameterIndices::kUnavailable; + indices_out.samplers_vertex = RootExtraParameterIndices::kUnavailable; } return index; } @@ -826,14 +829,14 @@ void D3D12CommandProcessor::WriteRegister(uint32_t index, uint32_t value) { (index - XE_GPU_REG_SHADER_CONSTANT_000_X) >> 2; if (float_constant_index >= 256) { float_constant_index -= 256; - if (float_constant_map_pixel_[float_constant_index >> 6] & + if (current_float_constant_map_pixel_[float_constant_index >> 6] & (1ull << (float_constant_index & 63))) { - cbuffer_bindings_pixel_float_.up_to_date = false; + cbuffer_bindings_float_pixel_.up_to_date = false; } } else { - if (float_constant_map_vertex_[float_constant_index >> 6] & + if (current_float_constant_map_vertex_[float_constant_index >> 6] & (1ull << (float_constant_index & 63))) { - cbuffer_bindings_vertex_float_.up_to_date = false; + cbuffer_bindings_float_vertex_.up_to_date = false; } } } @@ -1303,18 +1306,21 @@ bool D3D12CommandProcessor::BeginFrame() { current_graphics_root_up_to_date_ = 0; current_view_heap_ = nullptr; current_sampler_heap_ = nullptr; - std::memset(float_constant_map_vertex_, 0, - sizeof(float_constant_map_vertex_)); - std::memset(float_constant_map_pixel_, 0, sizeof(float_constant_map_pixel_)); + std::memset(current_float_constant_map_vertex_, 0, + sizeof(current_float_constant_map_vertex_)); + std::memset(current_float_constant_map_pixel_, 0, + sizeof(current_float_constant_map_pixel_)); cbuffer_bindings_system_.up_to_date = false; - cbuffer_bindings_vertex_float_.up_to_date = false; - cbuffer_bindings_pixel_float_.up_to_date = false; + cbuffer_bindings_float_vertex_.up_to_date = false; + cbuffer_bindings_float_pixel_.up_to_date = false; cbuffer_bindings_bool_loop_.up_to_date = false; cbuffer_bindings_fetch_.up_to_date = false; draw_view_full_update_ = 0; draw_sampler_full_update_ = 0; texture_bindings_written_vertex_ = false; texture_bindings_written_pixel_ = false; + samplers_written_vertex_ = false; + samplers_written_pixel_ = false; primitive_topology_ = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; command_lists_[current_queue_frame_]->BeginRecording(); @@ -1796,102 +1802,121 @@ bool D3D12CommandProcessor::UpdateBindings( command_list->SetGraphicsRootSignature(root_signature); } - // Get used textures and samplers. - uint32_t pixel_texture_count, pixel_sampler_count; - const D3D12Shader::TextureSRV* pixel_textures; - const D3D12Shader::SamplerBinding* pixel_samplers; - if (pixel_shader != nullptr) { - pixel_textures = pixel_shader->GetTextureSRVs(pixel_texture_count); - pixel_samplers = pixel_shader->GetSamplerBindings(pixel_sampler_count); - } else { - pixel_textures = nullptr; - pixel_texture_count = 0; - pixel_samplers = nullptr; - pixel_sampler_count = 0; + XXH64_state_t hash_state; + + // Get textures and samplers used by the vertex shader. + uint32_t texture_count_vertex, sampler_count_vertex; + const D3D12Shader::TextureSRV* textures_vertex = + vertex_shader->GetTextureSRVs(texture_count_vertex); + uint64_t texture_bindings_hash_vertex = + texture_count_vertex != 0 + ? texture_cache_->GetDescriptorHashForActiveTextures( + textures_vertex, texture_count_vertex) + : 0; + const D3D12Shader::SamplerBinding* samplers_vertex = + vertex_shader->GetSamplerBindings(sampler_count_vertex); + XXH64_reset(&hash_state, 0); + for (uint32_t i = 0; i < sampler_count_vertex; ++i) { + TextureCache::SamplerParameters sampler_parameters = + texture_cache_->GetSamplerParameters(samplers_vertex[i]); + XXH64_update(&hash_state, &sampler_parameters, sizeof(sampler_parameters)); } - uint64_t new_pixel_texture_bindings_hash = - pixel_texture_count != 0 + uint64_t samplers_hash_vertex = XXH64_digest(&hash_state); + + // Get textures and samplers used by the pixel shader. + uint32_t texture_count_pixel, sampler_count_pixel; + const D3D12Shader::TextureSRV* textures_pixel; + const D3D12Shader::SamplerBinding* samplers_pixel; + if (pixel_shader != nullptr) { + textures_pixel = pixel_shader->GetTextureSRVs(texture_count_pixel); + samplers_pixel = pixel_shader->GetSamplerBindings(sampler_count_pixel); + } else { + textures_pixel = nullptr; + texture_count_pixel = 0; + samplers_pixel = nullptr; + sampler_count_pixel = 0; + } + uint64_t texture_bindings_hash_pixel = + texture_count_pixel != 0 ? texture_cache_->GetDescriptorHashForActiveTextures( - pixel_textures, pixel_texture_count) + textures_pixel, texture_count_pixel) : 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; + XXH64_reset(&hash_state, 0); + for (uint32_t i = 0; i < sampler_count_pixel; ++i) { + TextureCache::SamplerParameters sampler_parameters = + texture_cache_->GetSamplerParameters(samplers_pixel[i]); + XXH64_update(&hash_state, &sampler_parameters, sizeof(sampler_parameters)); + } + uint64_t samplers_hash_pixel = XXH64_digest(&hash_state); // Begin updating descriptors. bool write_system_constant_view = false; - bool write_vertex_float_constant_view = false; - bool write_pixel_float_constant_view = false; + bool write_float_constant_view_vertex = false; + bool write_float_constant_view_pixel = 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. - bool write_vertex_textures = - vertex_texture_count != 0 && + bool write_textures_vertex = + texture_count_vertex != 0 && (!texture_bindings_written_vertex_ || - texture_bindings_hash_vertex_ != new_vertex_texture_bindings_hash); - bool write_pixel_textures = - pixel_texture_count != 0 && + current_texture_bindings_hash_vertex_ != texture_bindings_hash_vertex); + bool write_textures_pixel = + texture_count_pixel != 0 && (!texture_bindings_written_pixel_ || - texture_bindings_hash_pixel_ != new_pixel_texture_bindings_hash); - bool write_samplers = sampler_count != 0; + current_texture_bindings_hash_pixel_ != texture_bindings_hash_pixel); + bool write_samplers_vertex = + sampler_count_vertex != 0 && + (!samplers_written_vertex_ || + current_samplers_hash_vertex_ != samplers_hash_vertex); + bool write_samplers_pixel = + sampler_count_pixel != 0 && + (!samplers_written_pixel_ || + current_samplers_hash_pixel_ != samplers_hash_pixel); // Check if the float constant layout is still the same and get the counts. - const Shader::ConstantRegisterMap& vertex_shader_float_constant_map = + const Shader::ConstantRegisterMap& float_constant_map_vertex = vertex_shader->constant_register_map(); - uint32_t vertex_shader_float_constant_count = - vertex_shader_float_constant_map.float_count; + uint32_t float_constant_count_vertex = float_constant_map_vertex.float_count; // Even if the shader doesn't need any float constants, a valid binding must // still be provided, so if the first draw in the frame with the current root // signature doesn't have float constants at all, still allocate an empty // buffer. - uint32_t vertex_shader_float_constant_size = - xe::align(uint32_t(std::max(vertex_shader_float_constant_count, 1u) * 4 * - sizeof(float)), - 256u); + uint32_t float_constant_size_vertex = xe::align( + uint32_t(std::max(float_constant_count_vertex, 1u) * 4 * sizeof(float)), + 256u); for (uint32_t i = 0; i < 4; ++i) { - if (float_constant_map_vertex_[i] != - vertex_shader_float_constant_map.float_bitmap[i]) { - float_constant_map_vertex_[i] = - vertex_shader_float_constant_map.float_bitmap[i]; + if (current_float_constant_map_vertex_[i] != + float_constant_map_vertex.float_bitmap[i]) { + current_float_constant_map_vertex_[i] = + float_constant_map_vertex.float_bitmap[i]; // If no float constants at all, we can reuse any buffer for them, so not // invalidating. - if (vertex_shader_float_constant_map.float_count != 0) { - cbuffer_bindings_vertex_float_.up_to_date = false; + if (float_constant_map_vertex.float_count != 0) { + cbuffer_bindings_float_vertex_.up_to_date = false; } } } - uint32_t pixel_shader_float_constant_count = 0; + uint32_t float_constant_count_pixel = 0; if (pixel_shader != nullptr) { - const Shader::ConstantRegisterMap& pixel_shader_float_constant_map = + const Shader::ConstantRegisterMap& float_constant_map_pixel = pixel_shader->constant_register_map(); - pixel_shader_float_constant_count = - pixel_shader_float_constant_map.float_count; + float_constant_count_pixel = float_constant_map_pixel.float_count; for (uint32_t i = 0; i < 4; ++i) { - if (float_constant_map_pixel_[i] != - pixel_shader_float_constant_map.float_bitmap[i]) { - float_constant_map_pixel_[i] = - pixel_shader_float_constant_map.float_bitmap[i]; - if (pixel_shader_float_constant_map.float_count != 0) { - cbuffer_bindings_pixel_float_.up_to_date = false; + if (current_float_constant_map_pixel_[i] != + float_constant_map_pixel.float_bitmap[i]) { + current_float_constant_map_pixel_[i] = + float_constant_map_pixel.float_bitmap[i]; + if (float_constant_map_pixel.float_count != 0) { + cbuffer_bindings_float_pixel_.up_to_date = false; } } } } else { - std::memset(float_constant_map_pixel_, 0, - sizeof(float_constant_map_pixel_)); + std::memset(current_float_constant_map_pixel_, 0, + sizeof(current_float_constant_map_pixel_)); } - uint32_t pixel_shader_float_constant_size = - xe::align(uint32_t(std::max(pixel_shader_float_constant_count, 1u) * 4 * - sizeof(float)), - 256u); + uint32_t float_constant_size_pixel = xe::align( + uint32_t(std::max(float_constant_count_pixel, 1u) * 4 * sizeof(float)), + 256u); // Update constant buffers. if (!cbuffer_bindings_system_.up_to_date) { @@ -1906,16 +1931,16 @@ bool D3D12CommandProcessor::UpdateBindings( cbuffer_bindings_system_.up_to_date = true; write_system_constant_view = true; } - if (!cbuffer_bindings_vertex_float_.up_to_date) { + if (!cbuffer_bindings_float_vertex_.up_to_date) { uint8_t* float_constants = constant_buffer_pool_->RequestFull( - vertex_shader_float_constant_size, nullptr, nullptr, - &cbuffer_bindings_vertex_float_.buffer_address); + float_constant_size_vertex, nullptr, nullptr, + &cbuffer_bindings_float_vertex_.buffer_address); if (float_constants == nullptr) { return false; } for (uint32_t i = 0; i < 4; ++i) { uint64_t float_constant_map_entry = - vertex_shader_float_constant_map.float_bitmap[i]; + float_constant_map_vertex.float_bitmap[i]; uint32_t float_constant_index; while (xe::bit_scan_forward(float_constant_map_entry, &float_constant_index)) { @@ -1928,22 +1953,22 @@ bool D3D12CommandProcessor::UpdateBindings( float_constants += 4 * sizeof(float); } } - cbuffer_bindings_vertex_float_.up_to_date = true; - write_vertex_float_constant_view = true; + cbuffer_bindings_float_vertex_.up_to_date = true; + write_float_constant_view_vertex = true; } - if (!cbuffer_bindings_pixel_float_.up_to_date) { + if (!cbuffer_bindings_float_pixel_.up_to_date) { uint8_t* float_constants = constant_buffer_pool_->RequestFull( - pixel_shader_float_constant_size, nullptr, nullptr, - &cbuffer_bindings_pixel_float_.buffer_address); + float_constant_size_pixel, nullptr, nullptr, + &cbuffer_bindings_float_pixel_.buffer_address); if (float_constants == nullptr) { return false; } if (pixel_shader != nullptr) { - const Shader::ConstantRegisterMap& pixel_shader_float_constant_map = + const Shader::ConstantRegisterMap& float_constant_map_pixel = pixel_shader->constant_register_map(); for (uint32_t i = 0; i < 4; ++i) { uint64_t float_constant_map_entry = - pixel_shader_float_constant_map.float_bitmap[i]; + float_constant_map_pixel.float_bitmap[i]; uint32_t float_constant_index; while (xe::bit_scan_forward(float_constant_map_entry, &float_constant_index)) { @@ -1957,8 +1982,8 @@ bool D3D12CommandProcessor::UpdateBindings( } } } - cbuffer_bindings_pixel_float_.up_to_date = true; - write_pixel_float_constant_view = true; + cbuffer_bindings_float_pixel_.up_to_date = true; + write_float_constant_view_pixel = true; } if (!cbuffer_bindings_bool_loop_.up_to_date) { uint32_t* bool_loop_constants = @@ -1999,10 +2024,10 @@ bool D3D12CommandProcessor::UpdateBindings( if (write_system_constant_view) { ++view_count_partial_update; } - if (write_vertex_float_constant_view) { + if (write_float_constant_view_vertex) { ++view_count_partial_update; } - if (write_pixel_float_constant_view) { + if (write_float_constant_view_pixel) { ++view_count_partial_update; } if (write_bool_loop_constant_view) { @@ -2011,15 +2036,15 @@ bool D3D12CommandProcessor::UpdateBindings( if (write_fetch_constant_view) { ++view_count_partial_update; } - if (write_vertex_textures) { - view_count_partial_update += vertex_texture_count; + if (write_textures_vertex) { + view_count_partial_update += texture_count_vertex; } - if (write_pixel_textures) { - view_count_partial_update += pixel_texture_count; + if (write_textures_pixel) { + view_count_partial_update += texture_count_pixel; } // All the constants + shared memory + textures. uint32_t view_count_full_update = - 6 + vertex_texture_count + pixel_texture_count; + 6 + texture_count_vertex + texture_count_pixel; D3D12_CPU_DESCRIPTOR_HANDLE view_cpu_handle; D3D12_GPU_DESCRIPTOR_HANDLE view_gpu_handle; uint32_t descriptor_size_view = provider->GetViewDescriptorSize(); @@ -2030,14 +2055,22 @@ bool D3D12CommandProcessor::UpdateBindings( XELOGE("Failed to allocate view descriptors!"); return false; } + uint32_t sampler_count_partial_update = 0; + if (write_samplers_vertex) { + sampler_count_partial_update += sampler_count_vertex; + } + if (write_samplers_pixel) { + sampler_count_partial_update += sampler_count_pixel; + } D3D12_CPU_DESCRIPTOR_HANDLE sampler_cpu_handle = {}; D3D12_GPU_DESCRIPTOR_HANDLE sampler_gpu_handle = {}; uint32_t descriptor_size_sampler = provider->GetSamplerDescriptorSize(); uint64_t sampler_full_update_index = 0; - if (sampler_count != 0) { + if (sampler_count_vertex != 0 || sampler_count_pixel != 0) { sampler_full_update_index = RequestSamplerDescriptors( - draw_sampler_full_update_, write_samplers ? sampler_count : 0, - sampler_count, sampler_cpu_handle, sampler_gpu_handle); + draw_sampler_full_update_, sampler_count_partial_update, + sampler_count_vertex + sampler_count_pixel, sampler_cpu_handle, + sampler_gpu_handle); if (sampler_full_update_index == 0) { XELOGE("Failed to allocate sampler descriptors!"); return false; @@ -2047,11 +2080,11 @@ bool D3D12CommandProcessor::UpdateBindings( // Need to update all view descriptors. write_system_constant_view = true; write_fetch_constant_view = true; - write_vertex_float_constant_view = true; - write_pixel_float_constant_view = true; + write_float_constant_view_vertex = true; + write_float_constant_view_pixel = true; write_bool_loop_constant_view = true; - write_vertex_textures = vertex_texture_count != 0; - write_pixel_textures = pixel_texture_count != 0; + write_textures_vertex = texture_count_vertex != 0; + write_textures_pixel = texture_count_pixel != 0; texture_bindings_written_vertex_ = false; texture_bindings_written_pixel_ = false; // If updating fully, write the shared memory descriptor (t0). @@ -2061,16 +2094,17 @@ bool D3D12CommandProcessor::UpdateBindings( view_gpu_handle.ptr += descriptor_size_view; current_graphics_root_up_to_date_ &= ~(1u << kRootParameter_SharedMemory); } - if (sampler_count != 0 && - draw_sampler_full_update_ != sampler_full_update_index) { - write_samplers = true; + if (draw_sampler_full_update_ != sampler_full_update_index) { + write_samplers_vertex = sampler_count_vertex != 0; + write_samplers_pixel = sampler_count_pixel != 0; + samplers_written_vertex_ = false; + samplers_written_pixel_ = false; } // Write the descriptors. D3D12_CONSTANT_BUFFER_VIEW_DESC constant_buffer_desc; if (write_system_constant_view) { gpu_handle_system_constants_ = view_gpu_handle; - // System constants. constant_buffer_desc.BufferLocation = cbuffer_bindings_system_.buffer_address; constant_buffer_desc.SizeInBytes = @@ -2081,33 +2115,30 @@ bool D3D12CommandProcessor::UpdateBindings( current_graphics_root_up_to_date_ &= ~(1u << kRootParameter_SystemConstants); } - if (write_vertex_float_constant_view) { - gpu_handle_vertex_float_constants_ = view_gpu_handle; - // Vertex float constants. + if (write_float_constant_view_vertex) { + gpu_handle_float_constants_vertex_ = view_gpu_handle; constant_buffer_desc.BufferLocation = - cbuffer_bindings_vertex_float_.buffer_address; - constant_buffer_desc.SizeInBytes = vertex_shader_float_constant_size; + cbuffer_bindings_float_vertex_.buffer_address; + constant_buffer_desc.SizeInBytes = float_constant_size_vertex; device->CreateConstantBufferView(&constant_buffer_desc, view_cpu_handle); view_cpu_handle.ptr += descriptor_size_view; view_gpu_handle.ptr += descriptor_size_view; current_graphics_root_up_to_date_ &= - ~(1u << kRootParameter_VertexFloatConstants); + ~(1u << kRootParameter_FloatConstantsVertex); } - if (write_pixel_float_constant_view) { - gpu_handle_pixel_float_constants_ = view_gpu_handle; - // Pixel float constants. + if (write_float_constant_view_pixel) { + gpu_handle_float_constants_pixel_ = view_gpu_handle; constant_buffer_desc.BufferLocation = - cbuffer_bindings_pixel_float_.buffer_address; - constant_buffer_desc.SizeInBytes = pixel_shader_float_constant_size; + cbuffer_bindings_float_pixel_.buffer_address; + constant_buffer_desc.SizeInBytes = float_constant_size_pixel; device->CreateConstantBufferView(&constant_buffer_desc, view_cpu_handle); view_cpu_handle.ptr += descriptor_size_view; view_gpu_handle.ptr += descriptor_size_view; current_graphics_root_up_to_date_ &= - ~(1u << kRootParameter_PixelFloatConstants); + ~(1u << kRootParameter_FloatConstantsPixel); } if (write_bool_loop_constant_view) { gpu_handle_bool_loop_constants_ = view_gpu_handle; - // Bool/loop constants. constant_buffer_desc.BufferLocation = cbuffer_bindings_bool_loop_.buffer_address; constant_buffer_desc.SizeInBytes = 768; @@ -2119,7 +2150,6 @@ bool D3D12CommandProcessor::UpdateBindings( } if (write_fetch_constant_view) { gpu_handle_fetch_constants_ = view_gpu_handle; - // Fetch constants. constant_buffer_desc.BufferLocation = cbuffer_bindings_fetch_.buffer_address; constant_buffer_desc.SizeInBytes = 768; @@ -2128,69 +2158,69 @@ bool D3D12CommandProcessor::UpdateBindings( view_gpu_handle.ptr += descriptor_size_view; current_graphics_root_up_to_date_ &= ~(1u << kRootParameter_FetchConstants); } - if (write_pixel_textures) { - assert_true(current_graphics_root_extras_.pixel_textures != + if (write_textures_vertex) { + assert_true(current_graphics_root_extras_.textures_vertex != RootExtraParameterIndices::kUnavailable); - gpu_handle_pixel_textures_ = view_gpu_handle; - for (uint32_t i = 0; i < pixel_texture_count; ++i) { - const D3D12Shader::TextureSRV& srv = pixel_textures[i]; - texture_cache_->WriteTextureSRV(srv.fetch_constant, srv.dimension, - view_cpu_handle); - view_cpu_handle.ptr += descriptor_size_view; - view_gpu_handle.ptr += descriptor_size_view; - } - 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); - } - if (write_vertex_textures) { - assert_true(current_graphics_root_extras_.vertex_textures != - RootExtraParameterIndices::kUnavailable); - gpu_handle_vertex_textures_ = view_gpu_handle; - for (uint32_t i = 0; i < vertex_texture_count; ++i) { - const D3D12Shader::TextureSRV& srv = vertex_textures[i]; + gpu_handle_textures_vertex_ = view_gpu_handle; + for (uint32_t i = 0; i < texture_count_vertex; ++i) { + const D3D12Shader::TextureSRV& srv = textures_vertex[i]; texture_cache_->WriteTextureSRV(srv.fetch_constant, srv.dimension, view_cpu_handle); view_cpu_handle.ptr += descriptor_size_view; view_gpu_handle.ptr += descriptor_size_view; } texture_bindings_written_vertex_ = true; - texture_bindings_hash_vertex_ = new_vertex_texture_bindings_hash; + current_texture_bindings_hash_vertex_ = texture_bindings_hash_vertex; current_graphics_root_up_to_date_ &= - ~(1u << current_graphics_root_extras_.vertex_textures); + ~(1u << current_graphics_root_extras_.textures_vertex); } - if (write_samplers) { - if (pixel_sampler_count != 0) { - assert_true(current_graphics_root_extras_.pixel_samplers != - RootExtraParameterIndices::kUnavailable); - gpu_handle_pixel_samplers_ = sampler_gpu_handle; - for (uint32_t i = 0; i < pixel_sampler_count; ++i) { - const D3D12Shader::SamplerBinding& sampler = pixel_samplers[i]; - texture_cache_->WriteSampler(sampler.fetch_constant, sampler.mag_filter, - sampler.min_filter, sampler.mip_filter, - sampler.aniso_filter, sampler_cpu_handle); - sampler_cpu_handle.ptr += descriptor_size_sampler; - sampler_gpu_handle.ptr += descriptor_size_sampler; - } - current_graphics_root_up_to_date_ &= - ~(1u << current_graphics_root_extras_.pixel_samplers); + if (write_textures_pixel) { + assert_true(current_graphics_root_extras_.textures_pixel != + RootExtraParameterIndices::kUnavailable); + gpu_handle_textures_pixel_ = view_gpu_handle; + for (uint32_t i = 0; i < texture_count_pixel; ++i) { + const D3D12Shader::TextureSRV& srv = textures_pixel[i]; + texture_cache_->WriteTextureSRV(srv.fetch_constant, srv.dimension, + view_cpu_handle); + view_cpu_handle.ptr += descriptor_size_view; + view_gpu_handle.ptr += descriptor_size_view; } - if (vertex_sampler_count != 0) { - assert_true(current_graphics_root_extras_.vertex_samplers != - RootExtraParameterIndices::kUnavailable); - gpu_handle_vertex_samplers_ = sampler_gpu_handle; - for (uint32_t i = 0; i < vertex_sampler_count; ++i) { - const D3D12Shader::SamplerBinding& sampler = vertex_samplers[i]; - texture_cache_->WriteSampler(sampler.fetch_constant, sampler.mag_filter, - sampler.min_filter, sampler.mip_filter, - sampler.aniso_filter, sampler_cpu_handle); - sampler_cpu_handle.ptr += descriptor_size_sampler; - sampler_gpu_handle.ptr += descriptor_size_sampler; - } - current_graphics_root_up_to_date_ &= - ~(1u << current_graphics_root_extras_.vertex_samplers); + texture_bindings_written_pixel_ = true; + current_texture_bindings_hash_pixel_ = texture_bindings_hash_pixel; + current_graphics_root_up_to_date_ &= + ~(1u << current_graphics_root_extras_.textures_pixel); + } + if (write_samplers_vertex) { + assert_true(current_graphics_root_extras_.samplers_vertex != + RootExtraParameterIndices::kUnavailable); + gpu_handle_samplers_vertex_ = sampler_gpu_handle; + for (uint32_t i = 0; i < sampler_count_vertex; ++i) { + texture_cache_->WriteSampler( + texture_cache_->GetSamplerParameters(samplers_vertex[i]), + sampler_cpu_handle); + sampler_cpu_handle.ptr += descriptor_size_sampler; + sampler_gpu_handle.ptr += descriptor_size_sampler; } + samplers_written_vertex_ = true; + current_samplers_hash_vertex_ = samplers_hash_vertex; + current_graphics_root_up_to_date_ &= + ~(1u << current_graphics_root_extras_.samplers_vertex); + } + if (write_samplers_pixel) { + assert_true(current_graphics_root_extras_.samplers_pixel != + RootExtraParameterIndices::kUnavailable); + gpu_handle_samplers_pixel_ = sampler_gpu_handle; + for (uint32_t i = 0; i < sampler_count_pixel; ++i) { + texture_cache_->WriteSampler( + texture_cache_->GetSamplerParameters(samplers_pixel[i]), + sampler_cpu_handle); + sampler_cpu_handle.ptr += descriptor_size_sampler; + sampler_gpu_handle.ptr += descriptor_size_sampler; + } + samplers_written_pixel_ = true; + current_samplers_hash_pixel_ = samplers_hash_pixel; + current_graphics_root_up_to_date_ &= + ~(1u << current_graphics_root_extras_.samplers_pixel); } // Wrote new descriptors on the current page. @@ -2205,19 +2235,19 @@ bool D3D12CommandProcessor::UpdateBindings( current_graphics_root_up_to_date_ |= 1u << kRootParameter_FetchConstants; } if (!(current_graphics_root_up_to_date_ & - (1u << kRootParameter_VertexFloatConstants))) { + (1u << kRootParameter_FloatConstantsVertex))) { command_list->SetGraphicsRootDescriptorTable( - kRootParameter_VertexFloatConstants, - gpu_handle_vertex_float_constants_); + kRootParameter_FloatConstantsVertex, + gpu_handle_float_constants_vertex_); current_graphics_root_up_to_date_ |= 1u - << kRootParameter_VertexFloatConstants; + << kRootParameter_FloatConstantsVertex; } if (!(current_graphics_root_up_to_date_ & - (1u << kRootParameter_PixelFloatConstants))) { + (1u << kRootParameter_FloatConstantsPixel))) { command_list->SetGraphicsRootDescriptorTable( - kRootParameter_PixelFloatConstants, gpu_handle_pixel_float_constants_); + kRootParameter_FloatConstantsPixel, gpu_handle_float_constants_pixel_); current_graphics_root_up_to_date_ |= 1u - << kRootParameter_PixelFloatConstants; + << kRootParameter_FloatConstantsPixel; } if (!(current_graphics_root_up_to_date_ & (1u << kRootParameter_SystemConstants))) { @@ -2238,32 +2268,32 @@ bool D3D12CommandProcessor::UpdateBindings( current_graphics_root_up_to_date_ |= 1u << kRootParameter_SharedMemory; } uint32_t extra_index; - extra_index = current_graphics_root_extras_.pixel_textures; + extra_index = current_graphics_root_extras_.textures_pixel; if (extra_index != RootExtraParameterIndices::kUnavailable && !(current_graphics_root_up_to_date_ & (1u << extra_index))) { command_list->SetGraphicsRootDescriptorTable(extra_index, - gpu_handle_pixel_textures_); + gpu_handle_textures_pixel_); current_graphics_root_up_to_date_ |= 1u << extra_index; } - extra_index = current_graphics_root_extras_.pixel_samplers; + extra_index = current_graphics_root_extras_.samplers_pixel; if (extra_index != RootExtraParameterIndices::kUnavailable && !(current_graphics_root_up_to_date_ & (1u << extra_index))) { command_list->SetGraphicsRootDescriptorTable(extra_index, - gpu_handle_pixel_samplers_); + gpu_handle_samplers_pixel_); current_graphics_root_up_to_date_ |= 1u << extra_index; } - extra_index = current_graphics_root_extras_.vertex_textures; + extra_index = current_graphics_root_extras_.textures_vertex; if (extra_index != RootExtraParameterIndices::kUnavailable && !(current_graphics_root_up_to_date_ & (1u << extra_index))) { command_list->SetGraphicsRootDescriptorTable(extra_index, - gpu_handle_vertex_textures_); + gpu_handle_textures_vertex_); current_graphics_root_up_to_date_ |= 1u << extra_index; } - extra_index = current_graphics_root_extras_.vertex_samplers; + extra_index = current_graphics_root_extras_.samplers_vertex; if (extra_index != RootExtraParameterIndices::kUnavailable && !(current_graphics_root_up_to_date_ & (1u << extra_index))) { command_list->SetGraphicsRootDescriptorTable(extra_index, - gpu_handle_vertex_samplers_); + gpu_handle_samplers_vertex_); current_graphics_root_up_to_date_ |= 1u << extra_index; } diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.h b/src/xenia/gpu/d3d12/d3d12_command_processor.h index f9b2b04e6..18163b370 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.h +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.h @@ -146,9 +146,9 @@ class D3D12CommandProcessor : public CommandProcessor { kRootParameter_FetchConstants, // Quite frequently changed (for one object drawn multiple times, for // instance - may contain projection matrices). - kRootParameter_VertexFloatConstants, + kRootParameter_FloatConstantsVertex, // Less frequently changed (per-material). - kRootParameter_PixelFloatConstants, + kRootParameter_FloatConstantsPixel, // Rarely changed - system constants like viewport and alpha testing. kRootParameter_SystemConstants, // Pretty rarely used and rarely changed - flow control constants. @@ -169,10 +169,10 @@ class D3D12CommandProcessor : public CommandProcessor { }; struct RootExtraParameterIndices { - uint32_t pixel_textures; - uint32_t pixel_samplers; - uint32_t vertex_textures; - uint32_t vertex_samplers; + uint32_t textures_pixel; + uint32_t samplers_pixel; + uint32_t textures_vertex; + uint32_t samplers_vertex; static constexpr uint32_t kUnavailable = UINT32_MAX; }; // Gets the indices of optional root parameters. Returns the total parameter @@ -283,8 +283,8 @@ class D3D12CommandProcessor : public CommandProcessor { DxbcShaderTranslator::SystemConstants system_constants_; // Float constant usage masks of the last draw call. - uint64_t float_constant_map_vertex_[4]; - uint64_t float_constant_map_pixel_[4]; + uint64_t current_float_constant_map_vertex_[4]; + uint64_t current_float_constant_map_pixel_[4]; // Constant buffer bindings. struct ConstantBufferBinding { @@ -292,8 +292,8 @@ class D3D12CommandProcessor : public CommandProcessor { bool up_to_date; }; ConstantBufferBinding cbuffer_bindings_system_; - ConstantBufferBinding cbuffer_bindings_vertex_float_; - ConstantBufferBinding cbuffer_bindings_pixel_float_; + ConstantBufferBinding cbuffer_bindings_float_vertex_; + ConstantBufferBinding cbuffer_bindings_float_pixel_; ConstantBufferBinding cbuffer_bindings_bool_loop_; ConstantBufferBinding cbuffer_bindings_fetch_; @@ -308,20 +308,30 @@ class D3D12CommandProcessor : public CommandProcessor { // 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_; + uint64_t current_texture_bindings_hash_vertex_; + uint64_t current_texture_bindings_hash_pixel_; + + // Whether the last used samplers have been written to the current sampler + // descriptor heap. + bool samplers_written_vertex_; + bool samplers_written_pixel_; + // Hashes of the last sampler parameters written to the current sampler + // descriptor heap with the last used descriptor layout. Valid only when the + // corresponding "written" variables are true. + uint64_t current_samplers_hash_vertex_; + uint64_t current_samplers_hash_pixel_; // Latest descriptor handles used for handling Xenos draw calls. D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_system_constants_; - D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_vertex_float_constants_; - D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_pixel_float_constants_; + D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_float_constants_vertex_; + D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_float_constants_pixel_; D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_bool_loop_constants_; D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_fetch_constants_; D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_shared_memory_; - D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_pixel_textures_; - D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_pixel_samplers_; - D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_vertex_textures_; - D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_vertex_samplers_; + D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_textures_vertex_; + D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_textures_pixel_; + D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_samplers_vertex_; + D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_samplers_pixel_; // Current primitive topology. D3D_PRIMITIVE_TOPOLOGY primitive_topology_; diff --git a/src/xenia/gpu/d3d12/texture_cache.cc b/src/xenia/gpu/d3d12/texture_cache.cc index 3f783a826..58bec4edd 100644 --- a/src/xenia/gpu/d3d12/texture_cache.cc +++ b/src/xenia/gpu/d3d12/texture_cache.cc @@ -576,41 +576,82 @@ void TextureCache::WriteTextureSRV(uint32_t fetch_constant, device->CreateShaderResourceView(resource, &desc, handle); } -void TextureCache::WriteSampler(uint32_t fetch_constant, - TextureFilter mag_filter, - TextureFilter min_filter, - TextureFilter mip_filter, - AnisoFilter aniso_filter, - D3D12_CPU_DESCRIPTOR_HANDLE handle) { +TextureCache::SamplerParameters TextureCache::GetSamplerParameters( + const D3D12Shader::SamplerBinding& binding) const { auto& regs = *register_file_; - uint32_t r = XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 + fetch_constant * 6; + uint32_t r = + XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 + binding.fetch_constant * 6; auto group = reinterpret_cast(®s.values[r]); auto& fetch = group->texture_fetch; - if (mag_filter == TextureFilter::kUseFetchConst) { - mag_filter = TextureFilter(fetch.mag_filter); + + SamplerParameters parameters; + + parameters.clamp_x = ClampMode(fetch.clamp_x); + parameters.clamp_y = ClampMode(fetch.clamp_y); + parameters.clamp_z = ClampMode(fetch.clamp_z); + parameters.border_color = BorderColor(fetch.border_color); + + uint32_t mip_min_level = fetch.mip_min_level; + uint32_t mip_max_level = fetch.mip_max_level; + uint32_t base_page = fetch.base_address & 0x1FFFF; + uint32_t mip_page = fetch.mip_address & 0x1FFFF; + if (base_page == 0 || base_page == mip_page) { + // Games should clamp mip level in this case anyway, but just for safety. + mip_min_level = std::max(mip_min_level, 1u); } - if (min_filter == TextureFilter::kUseFetchConst) { - min_filter = TextureFilter(fetch.min_filter); + if (mip_page == 0) { + mip_max_level = 0; } - if (mip_filter == TextureFilter::kUseFetchConst) { - mip_filter = TextureFilter(fetch.mip_filter); - } - if (aniso_filter == AnisoFilter::kUseFetchConst) { - aniso_filter = AnisoFilter(fetch.aniso_filter); - } - D3D12_SAMPLER_DESC desc; + parameters.mip_min_level = mip_min_level; + parameters.mip_max_level = std::max(mip_max_level, mip_min_level); + parameters.lod_bias = fetch.lod_bias; + + AnisoFilter aniso_filter = binding.aniso_filter == AnisoFilter::kUseFetchConst + ? AnisoFilter(fetch.aniso_filter) + : binding.aniso_filter; + aniso_filter = std::min(aniso_filter, AnisoFilter::kMax_16_1); + parameters.aniso_filter = aniso_filter; if (aniso_filter != AnisoFilter::kDisabled) { - desc.Filter = D3D12_FILTER_ANISOTROPIC; - desc.MaxAnisotropy = std::min(1u << (uint32_t(aniso_filter) - 1), 16u); + parameters.mag_linear = 1; + parameters.min_linear = 1; + parameters.mip_linear = 1; } else { - D3D12_FILTER_TYPE d3d_filter_min = min_filter == TextureFilter::kLinear + TextureFilter mag_filter = + binding.mag_filter == TextureFilter::kUseFetchConst + ? TextureFilter(fetch.mag_filter) + : binding.mag_filter; + parameters.mag_linear = mag_filter == TextureFilter::kLinear; + TextureFilter min_filter = + binding.min_filter == TextureFilter::kUseFetchConst + ? TextureFilter(fetch.min_filter) + : binding.min_filter; + parameters.min_linear = min_filter == TextureFilter::kLinear; + TextureFilter mip_filter = + binding.mip_filter == TextureFilter::kUseFetchConst + ? TextureFilter(fetch.mip_filter) + : binding.mip_filter; + parameters.mip_linear = mip_filter == TextureFilter::kLinear; + // TODO(Triang3l): Investigate mip_filter TextureFilter::kBaseMap. + } + + return parameters; +} + +void TextureCache::WriteSampler(SamplerParameters parameters, + D3D12_CPU_DESCRIPTOR_HANDLE handle) const { + D3D12_SAMPLER_DESC desc; + if (parameters.aniso_filter != AnisoFilter::kDisabled) { + desc.Filter = D3D12_FILTER_ANISOTROPIC; + desc.MaxAnisotropy = 1u << (uint32_t(parameters.aniso_filter) - 1); + } else { + D3D12_FILTER_TYPE d3d_filter_min = parameters.min_linear ? D3D12_FILTER_TYPE_LINEAR : D3D12_FILTER_TYPE_POINT; - D3D12_FILTER_TYPE d3d_filter_mag = mag_filter == TextureFilter::kLinear + D3D12_FILTER_TYPE d3d_filter_mag = parameters.mag_linear ? D3D12_FILTER_TYPE_LINEAR : D3D12_FILTER_TYPE_POINT; - D3D12_FILTER_TYPE d3d_filter_mip = mip_filter == TextureFilter::kLinear + D3D12_FILTER_TYPE d3d_filter_mip = parameters.mip_linear ? D3D12_FILTER_TYPE_LINEAR : D3D12_FILTER_TYPE_POINT; // TODO(Triang3l): Investigate mip_filter TextureFilter::kBaseMap. @@ -630,13 +671,13 @@ void TextureCache::WriteSampler(uint32_t fetch_constant, /* kClampToBorder */ D3D12_TEXTURE_ADDRESS_MODE_BORDER, /* kMirrorClampToBorder */ D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE, }; - desc.AddressU = kAddressModeMap[fetch.clamp_x]; - desc.AddressV = kAddressModeMap[fetch.clamp_y]; - desc.AddressW = kAddressModeMap[fetch.clamp_z]; - desc.MipLODBias = fetch.lod_bias * (1.0f / 32.0f); + desc.AddressU = kAddressModeMap[uint32_t(parameters.clamp_x)]; + desc.AddressV = kAddressModeMap[uint32_t(parameters.clamp_y)]; + desc.AddressW = kAddressModeMap[uint32_t(parameters.clamp_z)]; + desc.MipLODBias = parameters.lod_bias * (1.0f / 32.0f); desc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; // TODO(Triang3l): Border colors k_ACBYCR_BLACK and k_ACBCRY_BLACK. - if (BorderColor(fetch.border_color) == BorderColor::k_AGBR_White) { + if (parameters.border_color == BorderColor::k_AGBR_White) { desc.BorderColor[0] = 1.0f; desc.BorderColor[1] = 1.0f; desc.BorderColor[2] = 1.0f; @@ -647,18 +688,8 @@ void TextureCache::WriteSampler(uint32_t fetch_constant, desc.BorderColor[2] = 0.0f; desc.BorderColor[3] = 0.0f; } - desc.MinLOD = float(fetch.mip_min_level); - desc.MaxLOD = float(fetch.mip_max_level); - uint32_t base_page = fetch.base_address & 0x1FFFF; - uint32_t mip_page = fetch.mip_address & 0x1FFFF; - if (base_page == 0 || base_page == mip_page) { - // Games should clamp mip level in this case anyway, but just for safety. - desc.MinLOD = std::max(desc.MinLOD, 1.0f); - } - if (mip_page == 0) { - desc.MaxLOD = 0.0f; - } - desc.MaxLOD = std::max(desc.MaxLOD, desc.MinLOD); + desc.MinLOD = float(parameters.mip_min_level); + desc.MaxLOD = float(parameters.mip_max_level); auto device = command_processor_->GetD3D12Context()->GetD3D12Provider()->GetDevice(); device->CreateSampler(&desc, handle); diff --git a/src/xenia/gpu/d3d12/texture_cache.h b/src/xenia/gpu/d3d12/texture_cache.h index 8a4a095af..9e0e0d991 100644 --- a/src/xenia/gpu/d3d12/texture_cache.h +++ b/src/xenia/gpu/d3d12/texture_cache.h @@ -55,6 +55,42 @@ class D3D12CommandProcessor; // this way anyway. class TextureCache { public: + // Sampler parameters that can be directly converted to a host sampler or used + // for binding hashing. + union SamplerParameters { + struct { + ClampMode clamp_x : 3; // 3 + ClampMode clamp_y : 3; // 6 + ClampMode clamp_z : 3; // 9 + BorderColor border_color : 2; // 11 + // For anisotropic, these are true. + uint32_t mag_linear : 1; // 12 + uint32_t min_linear : 1; // 13 + uint32_t mip_linear : 1; // 14 + AnisoFilter aniso_filter : 3; // 17 + uint32_t mip_min_level : 4; // 21 + uint32_t mip_max_level : 4; // 25 + + int32_t lod_bias : 10; // 42 + }; + uint64_t value; + + // Clearing the unused bits. + SamplerParameters() : value(0) {} + SamplerParameters(const SamplerParameters& parameters) + : value(parameters.value) {} + SamplerParameters& operator=(const SamplerParameters& parameters) { + value = parameters.value; + return *this; + } + bool operator==(const SamplerParameters& parameters) const { + return value == parameters.value; + } + bool operator!=(const SamplerParameters& parameters) const { + return value != parameters.value; + } + }; + TextureCache(D3D12CommandProcessor* command_processor, RegisterFile* register_file, SharedMemory* shared_memory); ~TextureCache(); @@ -84,10 +120,11 @@ class TextureCache { void WriteTextureSRV(uint32_t fetch_constant, TextureDimension shader_dimension, D3D12_CPU_DESCRIPTOR_HANDLE handle); - void WriteSampler(uint32_t fetch_constant, TextureFilter mag_filter, - TextureFilter min_filter, TextureFilter mip_filter, - AnisoFilter aniso_filter, - D3D12_CPU_DESCRIPTOR_HANDLE handle); + + SamplerParameters GetSamplerParameters( + const D3D12Shader::SamplerBinding& binding) const; + void WriteSampler(SamplerParameters parameters, + D3D12_CPU_DESCRIPTOR_HANDLE handle) const; static inline DXGI_FORMAT GetResolveDXGIFormat(TextureFormat format) { return host_formats_[uint32_t(format)].dxgi_format_resolve_tile;