[D3D12] SRV and sampler bindings

This commit is contained in:
Triang3l 2018-08-03 16:39:13 +03:00
parent 471ff6f157
commit 35aaa72722
10 changed files with 588 additions and 154 deletions

View File

@ -47,17 +47,19 @@ ID3D12RootSignature* D3D12CommandProcessor::GetRootSignature(
assert_true(vertex_shader->is_translated()); assert_true(vertex_shader->is_translated());
assert_true(pixel_shader == nullptr || pixel_shader->is_translated()); assert_true(pixel_shader == nullptr || pixel_shader->is_translated());
uint32_t pixel_textures = uint32_t pixel_texture_count = 0, pixel_sampler_count = 0;
pixel_shader != nullptr ? pixel_shader->GetTextureSRVCount() : 0; if (pixel_shader != nullptr) {
uint32_t pixel_samplers = pixel_shader->GetTextureSRVs(pixel_texture_count);
pixel_shader != nullptr ? pixel_shader->GetSamplerCount() : 0; pixel_shader->GetSamplerFetchConstants(pixel_sampler_count);
uint32_t vertex_textures = vertex_shader->GetTextureSRVCount(); }
uint32_t vertex_samplers = vertex_shader->GetSamplerCount(); uint32_t vertex_texture_count, vertex_sampler_count;
vertex_shader->GetTextureSRVs(vertex_texture_count);
vertex_shader->GetSamplerFetchConstants(vertex_sampler_count);
// Max 96 textures (if all kinds of tfetch instructions are used for all fetch // Max 96 textures (if all kinds of tfetch instructions are used for all fetch
// registers) and 32 samplers (one sampler per used fetch), but different // registers) and 32 samplers (one sampler per used fetch), but different
// shader stages have different texture sets. // shader stages have different texture sets.
uint32_t index = pixel_textures | (pixel_samplers << 7) | uint32_t index = pixel_texture_count | (pixel_sampler_count << 7) |
(vertex_textures << 12) | (vertex_samplers << 19); (vertex_texture_count << 12) | (vertex_sampler_count << 19);
// Try an existing root signature. // Try an existing root signature.
auto it = root_signatures_.find(index); auto it = root_signatures_.find(index);
@ -67,14 +69,16 @@ ID3D12RootSignature* D3D12CommandProcessor::GetRootSignature(
// Create a new one. // Create a new one.
D3D12_ROOT_SIGNATURE_DESC desc; D3D12_ROOT_SIGNATURE_DESC desc;
D3D12_ROOT_PARAMETER parameters[kRootParameter_Count_TwoStageTextures]; D3D12_ROOT_PARAMETER parameters[kRootParameter_Count_Max];
D3D12_DESCRIPTOR_RANGE ranges[kRootParameter_Count_TwoStageTextures]; D3D12_DESCRIPTOR_RANGE ranges[kRootParameter_Count_Max];
desc.NumParameters = kRootParameter_Count_NoTextures; desc.NumParameters = kRootParameter_Count_Base;
desc.pParameters = parameters; desc.pParameters = parameters;
desc.NumStaticSamplers = 0; desc.NumStaticSamplers = 0;
desc.pStaticSamplers = nullptr; desc.pStaticSamplers = nullptr;
desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE; desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE;
// Base parameters.
// Fetch constants. // Fetch constants.
{ {
auto& parameter = parameters[kRootParameter_FetchConstants]; auto& parameter = parameters[kRootParameter_FetchConstants];
@ -150,86 +154,70 @@ ID3D12RootSignature* D3D12CommandProcessor::GetRootSignature(
range.OffsetInDescriptorsFromTableStart = 0; range.OffsetInDescriptorsFromTableStart = 0;
} }
if (pixel_textures > 0 || vertex_textures > 0) { // Extra parameters.
desc.NumParameters = kRootParameter_Count_OneStageTextures;
// Pixel or vertex textures. // Pixel textures.
{ if (pixel_texture_count > 0) {
auto& parameter = parameters[kRootParameter_PixelOrVertexTextures]; auto& parameter = parameters[desc.NumParameters];
auto& range = ranges[kRootParameter_PixelOrVertexTextures]; auto& range = ranges[desc.NumParameters];
parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
parameter.DescriptorTable.NumDescriptorRanges = 1; parameter.DescriptorTable.NumDescriptorRanges = 1;
parameter.DescriptorTable.pDescriptorRanges = &range; parameter.DescriptorTable.pDescriptorRanges = &range;
parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
range.NumDescriptors = pixel_texture_count;
range.BaseShaderRegister = 0; range.BaseShaderRegister = 0;
range.RegisterSpace = 0; range.RegisterSpace = 0;
range.OffsetInDescriptorsFromTableStart = 0; range.OffsetInDescriptorsFromTableStart = 0;
if (pixel_textures > 0) { ++desc.NumParameters;
assert_true(pixel_samplers > 0);
parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
range.NumDescriptors = pixel_textures;
} else {
assert_true(vertex_samplers > 0);
parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
range.NumDescriptors = vertex_textures;
}
} }
// Pixel or vertex samplers. // Pixel samplers.
{ if (pixel_sampler_count > 0) {
auto& parameter = parameters[kRootParameter_PixelOrVertexSamplers]; auto& parameter = parameters[desc.NumParameters];
auto& range = ranges[kRootParameter_PixelOrVertexSamplers]; auto& range = ranges[desc.NumParameters];
parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
parameter.DescriptorTable.NumDescriptorRanges = 1; parameter.DescriptorTable.NumDescriptorRanges = 1;
parameter.DescriptorTable.pDescriptorRanges = &range; parameter.DescriptorTable.pDescriptorRanges = &range;
parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
range.NumDescriptors = pixel_sampler_count;
range.BaseShaderRegister = 0; range.BaseShaderRegister = 0;
range.RegisterSpace = 0; range.RegisterSpace = 0;
range.OffsetInDescriptorsFromTableStart = 0; range.OffsetInDescriptorsFromTableStart = 0;
if (pixel_samplers > 0) { ++desc.NumParameters;
parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
range.NumDescriptors = pixel_samplers;
} else {
parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
range.NumDescriptors = vertex_samplers;
} }
}
if (pixel_textures > 0 && vertex_textures > 0) {
assert_true(vertex_samplers > 0);
desc.NumParameters = kRootParameter_Count_TwoStageTextures;
// Vertex textures. // Vertex textures.
{ if (vertex_texture_count > 0) {
auto& parameter = parameters[kRootParameter_VertexTextures]; auto& parameter = parameters[desc.NumParameters];
auto& range = ranges[kRootParameter_VertexTextures]; auto& range = ranges[desc.NumParameters];
parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
parameter.DescriptorTable.NumDescriptorRanges = 1; parameter.DescriptorTable.NumDescriptorRanges = 1;
parameter.DescriptorTable.pDescriptorRanges = &range; parameter.DescriptorTable.pDescriptorRanges = &range;
parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
range.NumDescriptors = vertex_textures; range.NumDescriptors = vertex_texture_count;
range.BaseShaderRegister = 0; range.BaseShaderRegister = 0;
range.RegisterSpace = 0; range.RegisterSpace = 0;
range.OffsetInDescriptorsFromTableStart = 0; range.OffsetInDescriptorsFromTableStart = 0;
++desc.NumParameters;
} }
// Vertex samplers. // Vertex samplers.
{ if (vertex_sampler_count > 0) {
auto& parameter = parameters[kRootParameter_VertexSamplers]; auto& parameter = parameters[desc.NumParameters];
auto& range = ranges[kRootParameter_VertexSamplers]; auto& range = ranges[desc.NumParameters];
parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
parameter.DescriptorTable.NumDescriptorRanges = 1; parameter.DescriptorTable.NumDescriptorRanges = 1;
parameter.DescriptorTable.pDescriptorRanges = &range; parameter.DescriptorTable.pDescriptorRanges = &range;
parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
range.NumDescriptors = vertex_samplers; range.NumDescriptors = vertex_sampler_count;
range.BaseShaderRegister = 0; range.BaseShaderRegister = 0;
range.RegisterSpace = 0; range.RegisterSpace = 0;
range.OffsetInDescriptorsFromTableStart = 0; range.OffsetInDescriptorsFromTableStart = 0;
} ++desc.NumParameters;
}
} }
ID3DBlob* blob; ID3DBlob* blob;
@ -239,7 +227,8 @@ ID3D12RootSignature* D3D12CommandProcessor::GetRootSignature(
XELOGE( XELOGE(
"Failed to serialize a root signature with %u pixel textures, %u " "Failed to serialize a root signature with %u pixel textures, %u "
"pixel samplers, %u vertex textures and %u vertex samplers", "pixel samplers, %u vertex textures and %u vertex samplers",
pixel_textures, pixel_samplers, vertex_textures, vertex_samplers); pixel_texture_count, pixel_sampler_count, vertex_texture_count,
vertex_sampler_count);
if (error_blob != nullptr) { if (error_blob != nullptr) {
XELOGE("%s", XELOGE("%s",
reinterpret_cast<const char*>(error_blob->GetBufferPointer())); reinterpret_cast<const char*>(error_blob->GetBufferPointer()));
@ -259,7 +248,8 @@ ID3D12RootSignature* D3D12CommandProcessor::GetRootSignature(
XELOGE( XELOGE(
"Failed to create a root signature with %u pixel textures, %u pixel " "Failed to create a root signature with %u pixel textures, %u pixel "
"samplers, %u vertex textures and %u vertex samplers", "samplers, %u vertex textures and %u vertex samplers",
pixel_textures, pixel_samplers, vertex_textures, vertex_samplers); pixel_texture_count, pixel_sampler_count, vertex_texture_count,
vertex_sampler_count);
blob->Release(); blob->Release();
return nullptr; return nullptr;
} }
@ -269,6 +259,42 @@ ID3D12RootSignature* D3D12CommandProcessor::GetRootSignature(
return root_signature; return root_signature;
} }
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;
if (pixel_shader != nullptr) {
pixel_shader->GetTextureSRVs(pixel_texture_count);
pixel_shader->GetSamplerFetchConstants(pixel_sampler_count);
}
uint32_t vertex_texture_count, vertex_sampler_count;
vertex_shader->GetTextureSRVs(vertex_texture_count);
vertex_shader->GetSamplerFetchConstants(vertex_sampler_count);
uint32_t index = kRootParameter_Count_Base;
if (pixel_texture_count != 0) {
indices_out.pixel_textures = index++;
} else {
indices_out.pixel_textures = RootExtraParameterIndices::kUnavailable;
}
if (pixel_sampler_count != 0) {
indices_out.pixel_samplers = index++;
} else {
indices_out.pixel_samplers = RootExtraParameterIndices::kUnavailable;
}
if (vertex_texture_count != 0) {
indices_out.vertex_textures = index++;
} else {
indices_out.vertex_textures = RootExtraParameterIndices::kUnavailable;
}
if (vertex_sampler_count != 0) {
indices_out.vertex_samplers = index++;
} else {
indices_out.vertex_samplers = RootExtraParameterIndices::kUnavailable;
}
return index;
}
uint64_t D3D12CommandProcessor::RequestViewDescriptors( uint64_t D3D12CommandProcessor::RequestViewDescriptors(
uint64_t previous_full_update, uint32_t count_for_partial_update, uint64_t previous_full_update, uint32_t count_for_partial_update,
uint32_t count_for_full_update, D3D12_CPU_DESCRIPTOR_HANDLE& cpu_handle_out, uint32_t count_for_full_update, D3D12_CPU_DESCRIPTOR_HANDLE& cpu_handle_out,
@ -331,9 +357,9 @@ uint64_t D3D12CommandProcessor::RequestSamplerDescriptors(
descriptor_index * descriptor_index *
GetD3D12Context()->GetD3D12Provider()->GetDescriptorSizeSampler(); GetD3D12Context()->GetD3D12Provider()->GetDescriptorSizeSampler();
cpu_handle_out.ptr = cpu_handle_out.ptr =
view_heap_pool_->GetLastRequestHeapCPUStart().ptr + descriptor_offset; sampler_heap_pool_->GetLastRequestHeapCPUStart().ptr + descriptor_offset;
gpu_handle_out.ptr = gpu_handle_out.ptr =
view_heap_pool_->GetLastRequestHeapGPUStart().ptr + descriptor_offset; sampler_heap_pool_->GetLastRequestHeapGPUStart().ptr + descriptor_offset;
return current_full_update; return current_full_update;
} }
@ -447,6 +473,8 @@ bool D3D12CommandProcessor::SetupContext() {
pipeline_cache_ = std::make_unique<PipelineCache>(this, register_file_); pipeline_cache_ = std::make_unique<PipelineCache>(this, register_file_);
texture_cache_ = std::make_unique<TextureCache>(this, register_file_);
return true; return true;
} }
@ -469,6 +497,8 @@ void D3D12CommandProcessor::ShutdownContext() {
view_heap_pool_.reset(); view_heap_pool_.reset();
constant_buffer_pool_.reset(); constant_buffer_pool_.reset();
texture_cache_.reset();
pipeline_cache_.reset(); pipeline_cache_.reset();
// Root signatured are used by pipelines, thus freed after the pipelines. // Root signatured are used by pipelines, thus freed after the pipelines.
@ -526,6 +556,8 @@ void D3D12CommandProcessor::PerformSwap(uint32_t frontbuffer_ptr,
pipeline_cache_->ClearCache(); pipeline_cache_->ClearCache();
texture_cache_->ClearCache();
for (auto it : root_signatures_) { for (auto it : root_signatures_) {
it.second->Release(); it.second->Release();
} }
@ -1066,19 +1098,46 @@ bool D3D12CommandProcessor::UpdateBindings(
// Bind the new root signature. // Bind the new root signature.
if (current_graphics_root_signature_ != root_signature) { if (current_graphics_root_signature_ != root_signature) {
current_graphics_root_signature_ = root_signature; current_graphics_root_signature_ = root_signature;
GetRootExtraParameterIndices(vertex_shader, pixel_shader,
current_graphics_root_extras_);
// We don't know which root parameters are up to date anymore. // We don't know which root parameters are up to date anymore.
current_graphics_root_up_to_date_ = 0; current_graphics_root_up_to_date_ = 0;
command_list->SetGraphicsRootSignature(root_signature); command_list->SetGraphicsRootSignature(root_signature);
} }
// Get used textures and samplers.
uint32_t pixel_texture_count, pixel_sampler_count;
const D3D12Shader::TextureSRV* pixel_textures;
const uint32_t* pixel_samplers;
if (pixel_shader != nullptr) {
pixel_textures = pixel_shader->GetTextureSRVs(pixel_texture_count);
pixel_samplers =
pixel_shader->GetSamplerFetchConstants(pixel_sampler_count);
} else {
pixel_textures = nullptr;
pixel_texture_count = 0;
pixel_samplers = nullptr;
pixel_sampler_count = 0;
}
uint32_t vertex_texture_count, vertex_sampler_count;
const D3D12Shader::TextureSRV* vertex_textures =
vertex_shader->GetTextureSRVs(vertex_texture_count);
const uint32_t* vertex_samplers =
vertex_shader->GetSamplerFetchConstants(vertex_sampler_count);
uint32_t texture_count = pixel_texture_count + vertex_texture_count;
uint32_t sampler_count = pixel_sampler_count + vertex_sampler_count;
// Begin updating descriptors. // Begin updating descriptors.
bool write_common_constant_views = false; bool write_common_constant_views = false;
bool write_vertex_float_constant_views = false; bool write_vertex_float_constant_views = false;
bool write_pixel_float_constant_views = false; bool write_pixel_float_constant_views = false;
bool write_fetch_constant_view = false; bool write_fetch_constant_view = false;
// TODO(Triang3l): Update textures and samplers only if shaders or binding
// hash change.
bool write_textures = texture_count != 0;
bool write_samplers = sampler_count != 0;
// Update constant buffers. // Update constant buffers.
// TODO(Triang3l): Update the system constant buffer - will crash without it.
if (!cbuffer_bindings_system_.up_to_date) { if (!cbuffer_bindings_system_.up_to_date) {
uint8_t* system_constants = constant_buffer_pool_->RequestFull( uint8_t* system_constants = constant_buffer_pool_->RequestFull(
xe::align(uint32_t(sizeof(system_constants_)), 256u), nullptr, nullptr, xe::align(uint32_t(sizeof(system_constants_)), 256u), nullptr, nullptr,
@ -1145,7 +1204,7 @@ bool D3D12CommandProcessor::UpdateBindings(
write_fetch_constant_view = true; write_fetch_constant_view = true;
} }
// Update the descriptors. // Allocate the descriptors.
uint32_t view_count_partial_update = 0; uint32_t view_count_partial_update = 0;
if (write_common_constant_views) { if (write_common_constant_views) {
// System and bool/loop constants. // System and bool/loop constants.
@ -1163,8 +1222,11 @@ bool D3D12CommandProcessor::UpdateBindings(
// Fetch constants. // Fetch constants.
++view_count_partial_update; ++view_count_partial_update;
} }
// All the constants + shared memory. if (write_textures) {
uint32_t view_count_full_update = 20; view_count_partial_update += texture_count;
}
// All the constants + shared memory + textures and samplers.
uint32_t view_count_full_update = 20 + texture_count;
D3D12_CPU_DESCRIPTOR_HANDLE view_cpu_handle; D3D12_CPU_DESCRIPTOR_HANDLE view_cpu_handle;
D3D12_GPU_DESCRIPTOR_HANDLE view_gpu_handle; D3D12_GPU_DESCRIPTOR_HANDLE view_gpu_handle;
uint32_t view_handle_size = provider->GetDescriptorSizeView(); uint32_t view_handle_size = provider->GetDescriptorSizeView();
@ -1172,16 +1234,30 @@ bool D3D12CommandProcessor::UpdateBindings(
draw_view_full_update_, view_count_partial_update, view_count_full_update, draw_view_full_update_, view_count_partial_update, view_count_full_update,
view_cpu_handle, view_gpu_handle); view_cpu_handle, view_gpu_handle);
if (view_full_update_index == 0) { if (view_full_update_index == 0) {
XELOGE("View full update index is 0!"); XELOGE("Failed to allocate view descriptors!");
return false; return false;
} }
D3D12_CPU_DESCRIPTOR_HANDLE sampler_cpu_handle = {};
D3D12_GPU_DESCRIPTOR_HANDLE sampler_gpu_handle = {};
uint32_t sampler_handle_size = provider->GetDescriptorSizeSampler();
uint64_t sampler_full_update_index = 0;
if (sampler_count != 0) {
sampler_full_update_index = RequestSamplerDescriptors(
draw_sampler_full_update_, write_samplers ? sampler_count : 0,
sampler_count, sampler_cpu_handle, sampler_gpu_handle);
if (sampler_full_update_index == 0) {
XELOGE("Failed to allocate sampler descriptors!");
return false;
}
}
if (draw_view_full_update_ != view_full_update_index) { if (draw_view_full_update_ != view_full_update_index) {
// Need to update all descriptors. // Need to update all view descriptors.
draw_view_full_update_ = view_full_update_index; draw_view_full_update_ = view_full_update_index;
write_common_constant_views = true; write_common_constant_views = true;
write_vertex_float_constant_views = true; write_vertex_float_constant_views = true;
write_pixel_float_constant_views = true; write_pixel_float_constant_views = true;
write_fetch_constant_view = true; write_fetch_constant_view = true;
write_textures = texture_count != 0;
// If updating fully, write the shared memory descriptor (t0, space1). // If updating fully, write the shared memory descriptor (t0, space1).
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;
@ -1189,6 +1265,13 @@ bool D3D12CommandProcessor::UpdateBindings(
view_gpu_handle.ptr += view_handle_size; view_gpu_handle.ptr += view_handle_size;
current_graphics_root_up_to_date_ &= ~(1u << kRootParameter_SharedMemory); current_graphics_root_up_to_date_ &= ~(1u << kRootParameter_SharedMemory);
} }
if (sampler_count != 0 &&
draw_sampler_full_update_ != sampler_full_update_index) {
draw_sampler_full_update_ = sampler_full_update_index;
write_samplers = true;
}
// Write the descriptors.
D3D12_CONSTANT_BUFFER_VIEW_DESC constant_buffer_desc; D3D12_CONSTANT_BUFFER_VIEW_DESC constant_buffer_desc;
if (write_common_constant_views) { if (write_common_constant_views) {
gpu_handle_common_constants_ = view_gpu_handle; gpu_handle_common_constants_ = view_gpu_handle;
@ -1249,6 +1332,62 @@ bool D3D12CommandProcessor::UpdateBindings(
view_gpu_handle.ptr += view_handle_size; view_gpu_handle.ptr += view_handle_size;
current_graphics_root_up_to_date_ &= ~(1u << kRootParameter_FetchConstants); current_graphics_root_up_to_date_ &= ~(1u << kRootParameter_FetchConstants);
} }
if (write_textures) {
if (pixel_texture_count != 0) {
assert_true(current_graphics_root_extras_.pixel_textures !=
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 += view_handle_size;
view_gpu_handle.ptr += view_handle_size;
}
current_graphics_root_up_to_date_ &=
~(1u << current_graphics_root_extras_.pixel_textures);
}
if (vertex_texture_count != 0) {
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];
texture_cache_->WriteTextureSRV(srv.fetch_constant, srv.dimension,
view_cpu_handle);
view_cpu_handle.ptr += view_handle_size;
view_gpu_handle.ptr += view_handle_size;
}
current_graphics_root_up_to_date_ &=
~(1u << current_graphics_root_extras_.vertex_textures);
}
}
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) {
texture_cache_->WriteSampler(pixel_samplers[i], sampler_cpu_handle);
sampler_cpu_handle.ptr += sampler_handle_size;
sampler_gpu_handle.ptr += sampler_handle_size;
}
current_graphics_root_up_to_date_ &=
~(1u << current_graphics_root_extras_.pixel_samplers);
}
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) {
texture_cache_->WriteSampler(vertex_samplers[i], sampler_cpu_handle);
sampler_cpu_handle.ptr += sampler_handle_size;
sampler_gpu_handle.ptr += sampler_handle_size;
}
current_graphics_root_up_to_date_ &=
~(1u << current_graphics_root_extras_.vertex_samplers);
}
}
// Update the root parameters. // Update the root parameters.
if (!(current_graphics_root_up_to_date_ & if (!(current_graphics_root_up_to_date_ &
@ -1284,6 +1423,35 @@ bool D3D12CommandProcessor::UpdateBindings(
gpu_handle_shared_memory_); gpu_handle_shared_memory_);
current_graphics_root_up_to_date_ |= 1u << kRootParameter_SharedMemory; current_graphics_root_up_to_date_ |= 1u << kRootParameter_SharedMemory;
} }
uint32_t extra_index;
extra_index = current_graphics_root_extras_.pixel_textures;
if (extra_index != RootExtraParameterIndices::kUnavailable &&
!(current_graphics_root_up_to_date_ & (1u << extra_index))) {
command_list->SetGraphicsRootDescriptorTable(extra_index,
gpu_handle_pixel_textures_);
current_graphics_root_up_to_date_ |= 1u << extra_index;
}
extra_index = current_graphics_root_extras_.pixel_samplers;
if (extra_index != RootExtraParameterIndices::kUnavailable &&
!(current_graphics_root_up_to_date_ & (1u << extra_index))) {
command_list->SetGraphicsRootDescriptorTable(extra_index,
gpu_handle_pixel_samplers_);
current_graphics_root_up_to_date_ |= 1u << extra_index;
}
extra_index = current_graphics_root_extras_.vertex_textures;
if (extra_index != RootExtraParameterIndices::kUnavailable &&
!(current_graphics_root_up_to_date_ & (1u << extra_index))) {
command_list->SetGraphicsRootDescriptorTable(extra_index,
gpu_handle_vertex_textures_);
current_graphics_root_up_to_date_ |= 1u << extra_index;
}
extra_index = current_graphics_root_extras_.vertex_samplers;
if (extra_index != RootExtraParameterIndices::kUnavailable &&
!(current_graphics_root_up_to_date_ & (1u << extra_index))) {
command_list->SetGraphicsRootDescriptorTable(extra_index,
gpu_handle_vertex_samplers_);
current_graphics_root_up_to_date_ |= 1u << extra_index;
}
return true; return true;
} }

View File

@ -110,32 +110,30 @@ class D3D12CommandProcessor : public CommandProcessor {
// Never changed - shared memory byte address buffer (t0, space1). // Never changed - shared memory byte address buffer (t0, space1).
kRootParameter_SharedMemory, kRootParameter_SharedMemory,
kRootParameter_Count_NoTextures, kRootParameter_Count_Base,
// These are there only if textures are fetched (they are changed pretty // Extra parameter that may or may not exist:
// frequently, but for the ease of maintenance they're in the end). // - Pixel textures.
// If the pixel shader samples textures, these are for pixel textures // - Pixel samplers.
// (changed more frequently), otherwise, if the vertex shader samples // - Vertex textures.
// textures, these are for vertex textures. // - Vertex samplers.
// Used textures of all types (t0+, space0). kRootParameter_Count_Max = kRootParameter_Count_Base + 4,
kRootParameter_PixelOrVertexTextures = kRootParameter_Count_NoTextures,
// Used samplers (s0+).
kRootParameter_PixelOrVertexSamplers,
kRootParameter_Count_OneStageTextures,
// These are only present if both pixel and vertex shaders sample textures
// for vertex textures.
// Used textures of all types (t0+, space0).
kRootParameter_VertexTextures = kRootParameter_Count_OneStageTextures,
// Used samplers (s0+).
kRootParameter_VertexSamplers,
kRootParameter_Count_TwoStageTextures,
}; };
struct RootExtraParameterIndices {
uint32_t pixel_textures;
uint32_t pixel_samplers;
uint32_t vertex_textures;
uint32_t vertex_samplers;
static constexpr uint32_t kUnavailable = UINT32_MAX;
};
// Gets the indices of optional root parameters. Returns the total parameter
// count.
static uint32_t GetRootExtraParameterIndices(
const D3D12Shader* vertex_shader, const D3D12Shader* pixel_shader,
RootExtraParameterIndices& indices_out);
// Returns true if a new frame was started. // Returns true if a new frame was started.
bool BeginFrame(); bool BeginFrame();
// Returns true if an open frame was ended. // Returns true if an open frame was ended.
@ -162,6 +160,8 @@ class D3D12CommandProcessor : public CommandProcessor {
std::unique_ptr<PipelineCache> pipeline_cache_ = nullptr; std::unique_ptr<PipelineCache> pipeline_cache_ = nullptr;
std::unique_ptr<TextureCache> texture_cache_ = nullptr;
std::unique_ptr<ui::d3d12::UploadBufferPool> constant_buffer_pool_ = nullptr; std::unique_ptr<ui::d3d12::UploadBufferPool> constant_buffer_pool_ = nullptr;
std::unique_ptr<ui::d3d12::DescriptorHeapPool> view_heap_pool_ = nullptr; std::unique_ptr<ui::d3d12::DescriptorHeapPool> view_heap_pool_ = nullptr;
std::unique_ptr<ui::d3d12::DescriptorHeapPool> sampler_heap_pool_ = nullptr; std::unique_ptr<ui::d3d12::DescriptorHeapPool> sampler_heap_pool_ = nullptr;
@ -194,6 +194,8 @@ class D3D12CommandProcessor : public CommandProcessor {
ID3D12PipelineState* current_pipeline_; ID3D12PipelineState* current_pipeline_;
// Currently bound graphics root signature. // Currently bound graphics root signature.
ID3D12RootSignature* current_graphics_root_signature_; ID3D12RootSignature* current_graphics_root_signature_;
// Extra parameters which may or may not be present.
RootExtraParameterIndices current_graphics_root_extras_;
// Whether root parameters are up to date - reset if a new signature is bound. // Whether root parameters are up to date - reset if a new signature is bound.
uint32_t current_graphics_root_up_to_date_; uint32_t current_graphics_root_up_to_date_;
@ -225,6 +227,10 @@ class D3D12CommandProcessor : public CommandProcessor {
D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_pixel_float_constants_; D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_pixel_float_constants_;
D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_fetch_constants_; D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_fetch_constants_;
D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_shared_memory_; 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_;
// Current primitive topology. // Current primitive topology.
D3D_PRIMITIVE_TOPOLOGY primitive_topology_; D3D_PRIMITIVE_TOPOLOGY primitive_topology_;

View File

@ -32,6 +32,27 @@ D3D12Shader::~D3D12Shader() {
} }
} }
void D3D12Shader::SetTexturesAndSamplers(
const HlslShaderTranslator::TextureSRV* texture_srvs,
uint32_t texture_srv_count, const uint32_t* sampler_fetch_constants,
uint32_t sampler_count) {
for (uint32_t i = 0; i < texture_srv_count; ++i) {
TextureSRV& srv = texture_srvs_[i];
const HlslShaderTranslator::TextureSRV& translator_srv = texture_srvs[i];
srv.fetch_constant = translator_srv.fetch_constant;
srv.dimension = translator_srv.dimension;
}
texture_srv_count_ = texture_srv_count;
// If there's a texture, there's a sampler for it.
used_texture_mask_ = 0;
for (uint32_t i = 0; i < sampler_count; ++i) {
uint32_t sampler_fetch_constant = sampler_fetch_constants[i];
sampler_fetch_constants_[i] = sampler_fetch_constant;
used_texture_mask_ |= 1u << sampler_fetch_constant;
}
sampler_count_ = sampler_count;
}
bool D3D12Shader::Prepare() { bool D3D12Shader::Prepare() {
assert_null(blob_); assert_null(blob_);
assert_true(is_valid()); assert_true(is_valid());

View File

@ -10,6 +10,7 @@
#ifndef XENIA_GPU_D3D12_D3D12_SHADER_H_ #ifndef XENIA_GPU_D3D12_D3D12_SHADER_H_
#define XENIA_GPU_D3D12_D3D12_SHADER_H_ #define XENIA_GPU_D3D12_D3D12_SHADER_H_
#include "xenia/gpu/hlsl_shader_translator.h"
#include "xenia/gpu/shader.h" #include "xenia/gpu/shader.h"
#include "xenia/ui/d3d12/d3d12_api.h" #include "xenia/ui/d3d12/d3d12_api.h"
@ -23,17 +24,39 @@ class D3D12Shader : public Shader {
const uint32_t* dword_ptr, uint32_t dword_count); const uint32_t* dword_ptr, uint32_t dword_count);
~D3D12Shader() override; ~D3D12Shader() override;
void SetTexturesAndSamplers(
const HlslShaderTranslator::TextureSRV* texture_srvs,
uint32_t texture_srv_count, const uint32_t* sampler_fetch_constants,
uint32_t sampler_count);
bool Prepare(); bool Prepare();
const uint8_t* GetDXBC() const; const uint8_t* GetDXBC() const;
size_t GetDXBCSize() const; size_t GetDXBCSize() const;
// TODO(Triang3l): Real texture counts. struct TextureSRV {
uint32_t GetTextureSRVCount() const { return 0; } uint32_t fetch_constant;
uint32_t GetSamplerCount() const { return 0; } TextureDimension dimension;
};
const TextureSRV* GetTextureSRVs(uint32_t& count_out) const {
count_out = texture_srv_count_;
return texture_srvs_;
}
const uint32_t* GetSamplerFetchConstants(uint32_t& count_out) const {
count_out = sampler_count_;
return sampler_fetch_constants_;
}
const uint32_t GetUsedTextureMask() const { return used_texture_mask_; }
private: private:
ID3DBlob* blob_ = nullptr; ID3DBlob* blob_ = nullptr;
// Up to 32 2D array textures, 32 3D textures and 32 cube textures.
TextureSRV texture_srvs_[96];
uint32_t texture_srv_count_ = 0;
uint32_t sampler_fetch_constants_[32];
uint32_t sampler_count_ = 0;
uint32_t used_texture_mask_ = 0;
}; };
} // namespace d3d12 } // namespace d3d12

View File

@ -27,7 +27,7 @@ namespace d3d12 {
PipelineCache::PipelineCache(D3D12CommandProcessor* command_processor, PipelineCache::PipelineCache(D3D12CommandProcessor* command_processor,
RegisterFile* register_file) RegisterFile* register_file)
: command_processor_(command_processor), register_file_(register_file) { : command_processor_(command_processor), register_file_(register_file) {
shader_translator_.reset(new HlslShaderTranslator()); shader_translator_ = std::make_unique<HlslShaderTranslator>();
// Set pipeline state description values we never change. // Set pipeline state description values we never change.
// Zero out tessellation, stream output, blend state and formats for render // Zero out tessellation, stream output, blend state and formats for render
@ -158,6 +158,14 @@ bool PipelineCache::TranslateShader(D3D12Shader* shader,
return false; return false;
} }
uint32_t texture_srv_count, sampler_count;
const HlslShaderTranslator::TextureSRV* texture_srvs =
shader_translator_->GetTextureSRVs(texture_srv_count);
const uint32_t* sampler_fetch_constants =
shader_translator_->GetSamplerFetchConstants(sampler_count);
shader->SetTexturesAndSamplers(texture_srvs, texture_srv_count,
sampler_fetch_constants, sampler_count);
// Prepare the shader for use (creates the Shader Model bytecode). // Prepare the shader for use (creates the Shader Model bytecode).
// It could still fail at this point. // It could still fail at this point.
if (!shader->Prepare()) { if (!shader->Prepare()) {

View File

@ -15,8 +15,8 @@
#include "third_party/xxhash/xxhash.h" #include "third_party/xxhash/xxhash.h"
#include "xenia/gpu/d3d12/d3d12_shader.h" #include "xenia/gpu/d3d12/d3d12_shader.h"
#include "xenia/gpu/hlsl_shader_translator.h"
#include "xenia/gpu/register_file.h" #include "xenia/gpu/register_file.h"
#include "xenia/gpu/shader_translator.h"
#include "xenia/gpu/xenos.h" #include "xenia/gpu/xenos.h"
namespace xe { namespace xe {
@ -81,7 +81,7 @@ class PipelineCache {
RegisterFile* register_file_; RegisterFile* register_file_;
// Reusable shader translator. // Reusable shader translator.
std::unique_ptr<ShaderTranslator> shader_translator_ = nullptr; std::unique_ptr<HlslShaderTranslator> shader_translator_ = nullptr;
// All loaded shaders mapped by their guest hash key. // All loaded shaders mapped by their guest hash key.
std::unordered_map<uint64_t, D3D12Shader*> shader_map_; std::unordered_map<uint64_t, D3D12Shader*> shader_map_;

View File

@ -0,0 +1,87 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2018 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/gpu/d3d12/texture_cache.h"
#include "xenia/gpu/d3d12/d3d12_command_processor.h"
namespace xe {
namespace gpu {
namespace d3d12 {
TextureCache::TextureCache(D3D12CommandProcessor* command_processor,
RegisterFile* register_file)
: command_processor_(command_processor), register_file_(register_file) {}
TextureCache::~TextureCache() { Shutdown(); }
void TextureCache::Shutdown() { ClearCache(); }
void TextureCache::ClearCache() {}
void TextureCache::WriteTextureSRV(uint32_t fetch_constant,
TextureDimension shader_dimension,
D3D12_CPU_DESCRIPTOR_HANDLE handle) {
// TODO(Triang3l): Real texture descriptors instead of null.
D3D12_SHADER_RESOURCE_VIEW_DESC desc;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
switch (shader_dimension) {
case TextureDimension::k3D:
desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
desc.Texture3D.MostDetailedMip = 0;
desc.Texture3D.MipLevels = UINT32_MAX;
desc.Texture3D.ResourceMinLODClamp = 0.0f;
break;
case TextureDimension::kCube:
desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
desc.TextureCube.MostDetailedMip = 0;
desc.TextureCube.MipLevels = UINT32_MAX;
desc.TextureCube.ResourceMinLODClamp = 0.0f;
break;
default:
desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
desc.Texture2DArray.MostDetailedMip = 0;
desc.Texture2DArray.MipLevels = UINT32_MAX;
desc.Texture2DArray.FirstArraySlice = 0;
desc.Texture2DArray.ArraySize = 1;
desc.Texture2DArray.PlaneSlice = 0;
desc.Texture2DArray.ResourceMinLODClamp = 0.0f;
break;
}
auto device =
command_processor_->GetD3D12Context()->GetD3D12Provider()->GetDevice();
device->CreateShaderResourceView(nullptr, &desc, handle);
}
void TextureCache::WriteSampler(uint32_t fetch_constant,
D3D12_CPU_DESCRIPTOR_HANDLE handle) {
// TODO(Triang3l): Real samplers instead of this dummy.
D3D12_SAMPLER_DESC desc;
desc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
desc.MipLODBias = 0.0f;
desc.MaxAnisotropy = 1;
desc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
desc.BorderColor[0] = 0.0f;
desc.BorderColor[1] = 0.0f;
desc.BorderColor[2] = 0.0f;
desc.BorderColor[3] = 0.0f;
desc.MinLOD = 0.0f;
desc.MaxLOD = 0.0f;
auto device =
command_processor_->GetD3D12Context()->GetD3D12Provider()->GetDevice();
device->CreateSampler(&desc, handle);
}
} // namespace d3d12
} // namespace gpu
} // namespace xe

View File

@ -0,0 +1,72 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2018 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_D3D12_TEXTURE_CACHE_H_
#define XENIA_GPU_D3D12_TEXTURE_CACHE_H_
#include "xenia/gpu/register_file.h"
#include "xenia/gpu/xenos.h"
#include "xenia/ui/d3d12/d3d12_api.h"
namespace xe {
namespace gpu {
namespace d3d12 {
class D3D12CommandProcessor;
// Manages host copies of guest textures, performing untiling, format and endian
// conversion of textures stored in the shared memory, and also handling
// invalidation.
//
// Mipmaps are treated the following way, according to the GPU hang message
// found in game executables explaining the valid usage of BaseAddress when
// streaming the largest LOD (it says games should not use 0 as the base address
// when the largest LOD isn't loaded, but rather, either allocate a valid
// address for it or make it the same as MipAddress):
// - If the texture has a base address, but no mip address, it's not mipmapped -
// the host texture has only the largest level too.
// - If the texture has different non-zero base address and mip address, a host
// texture full mipmap pyramid is created, disregarding min/max LOD and
// treating it purely as sampler state because there are tfetch instructions
// working directly with LOD values - including fetching with an explicit LOD.
// - If the texture has a mip address, but the base address is 0 or the same as
// the mip address, a fully mipmapped texture is created, but min/max LOD is
// clamped to 1 - the game is expected to do that anyway until the largest LOD
// is loaded.
// TODO(Triang3l): Check if there are any games with BaseAddress==MipAddress
// but min or max LOD being 0, especially check Modern Warfare 2/3.
// TODO(Triang3l): Attach the largest LOD to existing textures with a valid
// MipAddress but no BaseAddress to save memory because textures are streamed
// this way anyway.
class TextureCache {
public:
TextureCache(D3D12CommandProcessor* command_processor,
RegisterFile* register_file);
~TextureCache();
void Shutdown();
void ClearCache();
void WriteTextureSRV(uint32_t fetch_constant,
TextureDimension shader_dimension,
D3D12_CPU_DESCRIPTOR_HANDLE handle);
void WriteSampler(uint32_t fetch_constant,
D3D12_CPU_DESCRIPTOR_HANDLE handle);
private:
D3D12CommandProcessor* command_processor_;
RegisterFile* register_file_;
};
} // namespace d3d12
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_D3D12_TEXTURE_CACHE_H_

View File

@ -40,8 +40,7 @@ void HlslShaderTranslator::Reset() {
writes_depth_ = false; writes_depth_ = false;
srv_bindings_.clear(); texture_srv_count_ = 0;
sampler_count_ = 0; sampler_count_ = 0;
cube_used_ = false; cube_used_ = false;
@ -192,6 +191,37 @@ std::vector<uint8_t> HlslShaderTranslator::CompleteTranslation() {
"xe_float_constants[8] : register(b2);\n" "xe_float_constants[8] : register(b2);\n"
"\n"); "\n");
// Textures and samplers.
for (uint32_t i = 0; i < texture_srv_count_; ++i) {
const TextureSRV& srv = texture_srvs_[i];
const char* srv_type_dimension;
const char* srv_name_suffix;
switch (srv.dimension) {
case TextureDimension::k3D:
srv_type_dimension = "3D";
srv_name_suffix = "3d";
break;
case TextureDimension::kCube:
srv_type_dimension = "Cube";
srv_name_suffix = "cube";
break;
default:
srv_type_dimension = "2DArray";
srv_name_suffix = "2d";
break;
}
source.AppendFormat(
"Texture%s<float4> xe_texture%u_%s : register(t%u, space0);\n",
srv_type_dimension, srv.fetch_constant, srv_name_suffix, i);
}
for (uint32_t i = 0; i < sampler_count_; ++i) {
source.AppendFormat("SamplerState xe_sampler%u : register(s%u);\n",
sampler_fetch_constants_[i], i);
}
if (texture_srv_count_ != 0 || sampler_count_ != 0) {
source.Append("\n");
}
if (is_vertex_shader()) { if (is_vertex_shader()) {
// Vertex fetching, output and prologue. // Vertex fetching, output and prologue.
// Endian register (2nd word of the fetch constant) is 00 for no swap, 01 // Endian register (2nd word of the fetch constant) is 00 for no swap, 01
@ -301,6 +331,10 @@ std::vector<uint8_t> HlslShaderTranslator::CompleteTranslation() {
// Loop counter stack, .x is the active loop. // Loop counter stack, .x is the active loop.
// Represents number of times remaining to loop. // Represents number of times remaining to loop.
" uint4 xe_loop_count = uint4(0u, 0u, 0u, 0u);\n" " uint4 xe_loop_count = uint4(0u, 0u, 0u, 0u);\n"
// Coordinates for texture fetches.
" float3 xe_texture_coords = float3(0.0, 0.0, 0.0);\n"
// LOD for UseRegisterLOD texture fetches.
" float xe_texture_lod = 0.0f;\n"
// Master loop and switch for flow control. // Master loop and switch for flow control.
" uint xe_pc = 0u;\n" " uint xe_pc = 0u;\n"
"\n" "\n"
@ -1068,19 +1102,22 @@ void HlslShaderTranslator::ProcessVertexFetchInstruction(
EndPredicatedInstruction(conditional_emitted); EndPredicatedInstruction(conditional_emitted);
} }
uint32_t HlslShaderTranslator::AddSRVBinding(SRVType type, uint32_t HlslShaderTranslator::AddTextureSRV(uint32_t fetch_constant,
uint32_t fetch_constant) { TextureDimension dimension) {
for (uint32_t i = 0; i < srv_bindings_.size(); ++i) { if (dimension == TextureDimension::k1D) {
const SRVBinding& binding = srv_bindings_[i]; // 1D textures are treated as 2D.
if (binding.type == type && binding.fetch_constant == fetch_constant) { dimension = TextureDimension::k2D;
}
for (uint32_t i = 0; i < texture_srv_count_; ++i) {
const TextureSRV& srv = texture_srvs_[i];
if (srv.fetch_constant == fetch_constant && srv.dimension == dimension) {
return i; return i;
} }
} }
SRVBinding new_binding; TextureSRV& new_srv = texture_srvs_[texture_srv_count_];
new_binding.type = type; new_srv.fetch_constant = fetch_constant;
new_binding.fetch_constant = fetch_constant; new_srv.dimension = dimension;
srv_bindings_.push_back(new_binding); return texture_srv_count_++;
return uint32_t(srv_bindings_.size() - 1);
} }
uint32_t HlslShaderTranslator::AddSampler(uint32_t fetch_constant) { uint32_t HlslShaderTranslator::AddSampler(uint32_t fetch_constant) {
@ -1101,6 +1138,19 @@ void HlslShaderTranslator::ProcessTextureFetchInstruction(
bool conditional_emitted = BeginPredicatedInstruction( bool conditional_emitted = BeginPredicatedInstruction(
instr.is_predicated, instr.predicate_condition); instr.is_predicated, instr.predicate_condition);
if (instr.opcode == FetchOpcode::kSetTextureLod) {
// TODO(Triang3l): Set xe_lod to the src1.
} else {
uint32_t tfetch_index = instr.operands[1].storage_index;
AddTextureSRV(tfetch_index, instr.dimension);
if (instr.dimension == TextureDimension::k3D) {
// tfetch3D is used for both 3D textures and 2D texture arrays, this is
// chosen dynamically.
AddTextureSRV(tfetch_index, TextureDimension::k2D);
}
AddSampler(tfetch_index);
}
// TODO(Triang3l): Texture fetch when textures are added. // TODO(Triang3l): Texture fetch when textures are added.
EmitSourceDepth("xe_pv = (1.0).xxxx;\n"); EmitSourceDepth("xe_pv = (1.0).xxxx;\n");

View File

@ -40,21 +40,18 @@ class HlslShaderTranslator : public ShaderTranslator {
uint32_t textures_are_3d; uint32_t textures_are_3d;
}; };
enum class SRVType : uint32_t { struct TextureSRV {
// 1D, 2D or stacked texture bound as a 2D array texture. uint32_t fetch_constant;
Texture2DArray, TextureDimension dimension;
// 3D texture (also has a 2D array view of the same fetch registers because
// tfetch3D is used for both stacked and 3D textures.
Texture3D,
// Cube texture.
TextureCube
};
struct SRVBinding {
SRVType type : 2;
// 0-31 for textures, 0-95 for vertex buffers.
uint32_t fetch_constant : 7;
}; };
const TextureSRV* GetTextureSRVs(uint32_t& count_out) const {
count_out = texture_srv_count_;
return texture_srvs_;
}
const uint32_t* GetSamplerFetchConstants(uint32_t& count_out) const {
count_out = sampler_count_;
return sampler_fetch_constants_;
}
protected: protected:
void Reset() override; void Reset() override;
@ -108,9 +105,11 @@ class HlslShaderTranslator : public ShaderTranslator {
bool writes_depth_ = false; bool writes_depth_ = false;
std::vector<SRVBinding> srv_bindings_; // Up to 32 2D array textures, 32 3D textures and 32 cube textures.
// Finds or adds an SRV binding to the shader's SRV list, returns t# index. TextureSRV texture_srvs_[96];
uint32_t AddSRVBinding(SRVType type, uint32_t fetch_constant); uint32_t texture_srv_count_ = 0;
// Finds or adds a texture binding to the shader's SRV list, returns t# index.
uint32_t AddTextureSRV(uint32_t fetch_constant, TextureDimension dimension);
// Sampler index -> fetch constant index mapping. // Sampler index -> fetch constant index mapping.
// TODO(Triang3l): On binding tier 1 (Nvidia Fermi), there can't be more than // TODO(Triang3l): On binding tier 1 (Nvidia Fermi), there can't be more than