[D3D12] SRV and sampler bindings
This commit is contained in:
parent
471ff6f157
commit
35aaa72722
|
@ -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 = ⦥
|
parameter.DescriptorTable.pDescriptorRanges = ⦥
|
||||||
|
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 = ⦥
|
parameter.DescriptorTable.pDescriptorRanges = ⦥
|
||||||
|
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 = ⦥
|
parameter.DescriptorTable.pDescriptorRanges = ⦥
|
||||||
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 = ⦥
|
parameter.DescriptorTable.pDescriptorRanges = ⦥
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_;
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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_;
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -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_
|
|
@ -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");
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue