[GPU] Dynamic r# count via shader modifications + refactoring
This commit is contained in:
@@ -99,14 +99,11 @@ void D3D12CommandProcessor::RestoreEdramSnapshot(const void* snapshot) {
|
||||
}
|
||||
|
||||
uint32_t D3D12CommandProcessor::GetCurrentColorMask(
|
||||
const Shader* pixel_shader) const {
|
||||
if (pixel_shader == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
uint32_t shader_writes_color_targets) const {
|
||||
auto& regs = *register_file_;
|
||||
uint32_t color_mask = regs[XE_GPU_REG_RB_COLOR_MASK].u32 & 0xFFFF;
|
||||
for (uint32_t i = 0; i < 4; ++i) {
|
||||
if (!pixel_shader->writes_color_target(i)) {
|
||||
if (!(shader_writes_color_targets & (1 << i))) {
|
||||
color_mask &= ~(0xF << (i * 4));
|
||||
}
|
||||
}
|
||||
@@ -167,14 +164,18 @@ ID3D12RootSignature* D3D12CommandProcessor::GetRootSignature(
|
||||
tessellated ? D3D12_SHADER_VISIBILITY_DOMAIN
|
||||
: D3D12_SHADER_VISIBILITY_VERTEX;
|
||||
|
||||
uint32_t texture_count_vertex, sampler_count_vertex;
|
||||
vertex_shader->GetTextureBindings(texture_count_vertex);
|
||||
vertex_shader->GetSamplerBindings(sampler_count_vertex);
|
||||
uint32_t texture_count_pixel = 0, sampler_count_pixel = 0;
|
||||
if (pixel_shader != nullptr) {
|
||||
pixel_shader->GetTextureBindings(texture_count_pixel);
|
||||
pixel_shader->GetSamplerBindings(sampler_count_pixel);
|
||||
}
|
||||
uint32_t texture_count_vertex =
|
||||
uint32_t(vertex_shader->GetTextureBindingsAfterTranslation().size());
|
||||
uint32_t sampler_count_vertex =
|
||||
uint32_t(vertex_shader->GetSamplerBindingsAfterTranslation().size());
|
||||
uint32_t texture_count_pixel =
|
||||
pixel_shader
|
||||
? uint32_t(pixel_shader->GetTextureBindingsAfterTranslation().size())
|
||||
: 0;
|
||||
uint32_t sampler_count_pixel =
|
||||
pixel_shader
|
||||
? uint32_t(pixel_shader->GetSamplerBindingsAfterTranslation().size())
|
||||
: 0;
|
||||
|
||||
// Better put the pixel texture/sampler in the lower bits probably because it
|
||||
// changes often.
|
||||
@@ -383,33 +384,26 @@ ID3D12RootSignature* D3D12CommandProcessor::GetRootSignature(
|
||||
uint32_t D3D12CommandProcessor::GetRootBindfulExtraParameterIndices(
|
||||
const DxbcShader* vertex_shader, const DxbcShader* pixel_shader,
|
||||
RootBindfulExtraParameterIndices& indices_out) {
|
||||
uint32_t texture_count_pixel = 0, sampler_count_pixel = 0;
|
||||
if (pixel_shader != nullptr) {
|
||||
pixel_shader->GetTextureBindings(texture_count_pixel);
|
||||
pixel_shader->GetSamplerBindings(sampler_count_pixel);
|
||||
}
|
||||
uint32_t texture_count_vertex, sampler_count_vertex;
|
||||
vertex_shader->GetTextureBindings(texture_count_vertex);
|
||||
vertex_shader->GetSamplerBindings(sampler_count_vertex);
|
||||
|
||||
uint32_t index = kRootParameter_Bindful_Count_Base;
|
||||
if (texture_count_pixel != 0) {
|
||||
if (pixel_shader &&
|
||||
!pixel_shader->GetTextureBindingsAfterTranslation().empty()) {
|
||||
indices_out.textures_pixel = index++;
|
||||
} else {
|
||||
indices_out.textures_pixel = RootBindfulExtraParameterIndices::kUnavailable;
|
||||
}
|
||||
if (sampler_count_pixel != 0) {
|
||||
if (pixel_shader &&
|
||||
!pixel_shader->GetSamplerBindingsAfterTranslation().empty()) {
|
||||
indices_out.samplers_pixel = index++;
|
||||
} else {
|
||||
indices_out.samplers_pixel = RootBindfulExtraParameterIndices::kUnavailable;
|
||||
}
|
||||
if (texture_count_vertex != 0) {
|
||||
if (!vertex_shader->GetTextureBindingsAfterTranslation().empty()) {
|
||||
indices_out.textures_vertex = index++;
|
||||
} else {
|
||||
indices_out.textures_vertex =
|
||||
RootBindfulExtraParameterIndices::kUnavailable;
|
||||
}
|
||||
if (sampler_count_vertex != 0) {
|
||||
if (!vertex_shader->GetSamplerBindingsAfterTranslation().empty()) {
|
||||
indices_out.samplers_vertex = index++;
|
||||
} else {
|
||||
indices_out.samplers_vertex =
|
||||
@@ -1839,10 +1833,14 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type,
|
||||
// Need a pixel shader in normal color mode.
|
||||
return false;
|
||||
}
|
||||
// Gather shader ucode information to get the color mask, which is needed by
|
||||
// the render target cache, and memexport configuration, and also get the
|
||||
// current shader modification bits.
|
||||
DxbcShaderTranslator::Modification vertex_shader_modification;
|
||||
DxbcShaderTranslator::Modification pixel_shader_modification;
|
||||
if (!pipeline_cache_->GetCurrentShaderModifications(
|
||||
vertex_shader_modification, pixel_shader_modification)) {
|
||||
if (!pipeline_cache_->AnalyzeShaderUcodeAndGetCurrentModifications(
|
||||
vertex_shader, pixel_shader, vertex_shader_modification,
|
||||
pixel_shader_modification)) {
|
||||
return false;
|
||||
}
|
||||
D3D12Shader::D3D12Translation* vertex_shader_translation =
|
||||
@@ -1854,13 +1852,6 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type,
|
||||
pixel_shader->GetOrCreateTranslation(
|
||||
pixel_shader_modification.value))
|
||||
: nullptr;
|
||||
// Translate the shaders now to get memexport configuration and color mask,
|
||||
// which is needed by the render target cache, and also to get used textures
|
||||
// and samplers.
|
||||
if (!pipeline_cache_->EnsureShadersTranslated(vertex_shader_translation,
|
||||
pixel_shader_translation)) {
|
||||
return false;
|
||||
}
|
||||
bool tessellated = vertex_shader_modification.host_vertex_shader_type !=
|
||||
Shader::HostVertexShaderType::kVertex;
|
||||
|
||||
@@ -1889,7 +1880,10 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type,
|
||||
BeginSubmission(true);
|
||||
|
||||
// Set up the render targets - this may bind pipelines.
|
||||
if (!render_target_cache_->UpdateRenderTargets(pixel_shader)) {
|
||||
uint32_t pixel_shader_writes_color_targets =
|
||||
pixel_shader ? pixel_shader->writes_color_targets() : 0;
|
||||
if (!render_target_cache_->UpdateRenderTargets(
|
||||
pixel_shader_writes_color_targets)) {
|
||||
return false;
|
||||
}
|
||||
const RenderTargetCache::PipelineRenderTarget* pipeline_render_targets =
|
||||
@@ -1958,13 +1952,7 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type,
|
||||
line_loop_closing_index = 0;
|
||||
}
|
||||
|
||||
// Update the textures - this may bind pipelines.
|
||||
uint32_t used_texture_mask =
|
||||
vertex_shader->GetUsedTextureMask() |
|
||||
(pixel_shader != nullptr ? pixel_shader->GetUsedTextureMask() : 0);
|
||||
texture_cache_->RequestTextures(used_texture_mask);
|
||||
|
||||
// Create the pipeline if needed and bind it.
|
||||
// Translate the shaders and create the pipeline if needed.
|
||||
void* pipeline_handle;
|
||||
ID3D12RootSignature* root_signature;
|
||||
if (!pipeline_cache_->ConfigurePipeline(
|
||||
@@ -1974,6 +1962,17 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type,
|
||||
pipeline_render_targets, &pipeline_handle, &root_signature)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update the textures - this may bind pipelines.
|
||||
uint32_t used_texture_mask =
|
||||
vertex_shader->GetUsedTextureMaskAfterTranslation() |
|
||||
(pixel_shader != nullptr
|
||||
? pixel_shader->GetUsedTextureMaskAfterTranslation()
|
||||
: 0);
|
||||
texture_cache_->RequestTextures(used_texture_mask);
|
||||
|
||||
// Bind the pipeline after configuring it and doing everything that may bind
|
||||
// other pipelines.
|
||||
if (current_cached_pipeline_ != pipeline_handle) {
|
||||
deferred_command_list_.SetPipelineStateHandle(
|
||||
reinterpret_cast<void*>(pipeline_handle));
|
||||
@@ -2026,7 +2025,9 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type,
|
||||
memexport_used, primitive_polygonal, line_loop_closing_index,
|
||||
indexed ? index_buffer_info->endianness : xenos::Endian::kNone,
|
||||
viewport_info, pixel_size_x, pixel_size_y, used_texture_mask,
|
||||
GetCurrentColorMask(pixel_shader), pipeline_render_targets);
|
||||
pixel_shader ? GetCurrentColorMask(pixel_shader->writes_color_targets())
|
||||
: 0,
|
||||
pipeline_render_targets);
|
||||
|
||||
// Update constant buffers, descriptors and root parameters.
|
||||
if (!UpdateBindings(vertex_shader, pixel_shader, root_signature)) {
|
||||
@@ -2089,9 +2090,8 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type,
|
||||
MemExportRange memexport_ranges[512];
|
||||
uint32_t memexport_range_count = 0;
|
||||
if (memexport_used_vertex) {
|
||||
const std::vector<uint32_t>& memexport_stream_constants_vertex =
|
||||
vertex_shader->memexport_stream_constants();
|
||||
for (uint32_t constant_index : memexport_stream_constants_vertex) {
|
||||
for (uint32_t constant_index :
|
||||
vertex_shader->memexport_stream_constants()) {
|
||||
const auto& memexport_stream = regs.Get<xenos::xe_gpu_memexport_stream_t>(
|
||||
XE_GPU_REG_SHADER_CONSTANT_000_X + constant_index * 4);
|
||||
if (memexport_stream.index_count == 0) {
|
||||
@@ -2132,9 +2132,7 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type,
|
||||
}
|
||||
}
|
||||
if (memexport_used_pixel) {
|
||||
const std::vector<uint32_t>& memexport_stream_constants_pixel =
|
||||
pixel_shader->memexport_stream_constants();
|
||||
for (uint32_t constant_index : memexport_stream_constants_pixel) {
|
||||
for (uint32_t constant_index : pixel_shader->memexport_stream_constants()) {
|
||||
const auto& memexport_stream = regs.Get<xenos::xe_gpu_memexport_stream_t>(
|
||||
XE_GPU_REG_SHADER_CONSTANT_256_X + constant_index * 4);
|
||||
if (memexport_stream.index_count == 0) {
|
||||
@@ -3588,20 +3586,21 @@ bool D3D12CommandProcessor::UpdateBindings(
|
||||
vertex_shader->GetTextureBindingLayoutUserUID();
|
||||
size_t sampler_layout_uid_vertex =
|
||||
vertex_shader->GetSamplerBindingLayoutUserUID();
|
||||
uint32_t texture_count_vertex, sampler_count_vertex;
|
||||
const D3D12Shader::TextureBinding* textures_vertex =
|
||||
vertex_shader->GetTextureBindings(texture_count_vertex);
|
||||
const D3D12Shader::SamplerBinding* samplers_vertex =
|
||||
vertex_shader->GetSamplerBindings(sampler_count_vertex);
|
||||
const std::vector<D3D12Shader::TextureBinding>& textures_vertex =
|
||||
vertex_shader->GetTextureBindingsAfterTranslation();
|
||||
const std::vector<D3D12Shader::SamplerBinding>& samplers_vertex =
|
||||
vertex_shader->GetSamplerBindingsAfterTranslation();
|
||||
size_t texture_count_vertex = textures_vertex.size();
|
||||
size_t sampler_count_vertex = samplers_vertex.size();
|
||||
if (sampler_count_vertex) {
|
||||
if (current_sampler_layout_uid_vertex_ != sampler_layout_uid_vertex) {
|
||||
current_sampler_layout_uid_vertex_ = sampler_layout_uid_vertex;
|
||||
cbuffer_binding_descriptor_indices_vertex_.up_to_date = false;
|
||||
bindful_samplers_written_vertex_ = false;
|
||||
}
|
||||
current_samplers_vertex_.resize(std::max(current_samplers_vertex_.size(),
|
||||
size_t(sampler_count_vertex)));
|
||||
for (uint32_t i = 0; i < sampler_count_vertex; ++i) {
|
||||
current_samplers_vertex_.resize(
|
||||
std::max(current_samplers_vertex_.size(), sampler_count_vertex));
|
||||
for (size_t i = 0; i < sampler_count_vertex; ++i) {
|
||||
TextureCache::SamplerParameters parameters =
|
||||
texture_cache_->GetSamplerParameters(samplers_vertex[i]);
|
||||
if (current_samplers_vertex_[i] != parameters) {
|
||||
@@ -3615,14 +3614,16 @@ bool D3D12CommandProcessor::UpdateBindings(
|
||||
// Get textures and samplers used by the pixel shader, check if the last used
|
||||
// samplers are compatible and update them.
|
||||
size_t texture_layout_uid_pixel, sampler_layout_uid_pixel;
|
||||
uint32_t texture_count_pixel, sampler_count_pixel;
|
||||
const D3D12Shader::TextureBinding* textures_pixel;
|
||||
const D3D12Shader::SamplerBinding* samplers_pixel;
|
||||
const std::vector<D3D12Shader::TextureBinding>* textures_pixel;
|
||||
const std::vector<D3D12Shader::SamplerBinding>* samplers_pixel;
|
||||
size_t texture_count_pixel, sampler_count_pixel;
|
||||
if (pixel_shader != nullptr) {
|
||||
texture_layout_uid_pixel = pixel_shader->GetTextureBindingLayoutUserUID();
|
||||
sampler_layout_uid_pixel = pixel_shader->GetSamplerBindingLayoutUserUID();
|
||||
textures_pixel = pixel_shader->GetTextureBindings(texture_count_pixel);
|
||||
samplers_pixel = pixel_shader->GetSamplerBindings(sampler_count_pixel);
|
||||
textures_pixel = &pixel_shader->GetTextureBindingsAfterTranslation();
|
||||
texture_count_pixel = textures_pixel->size();
|
||||
samplers_pixel = &pixel_shader->GetSamplerBindingsAfterTranslation();
|
||||
sampler_count_pixel = samplers_pixel->size();
|
||||
if (sampler_count_pixel) {
|
||||
if (current_sampler_layout_uid_pixel_ != sampler_layout_uid_pixel) {
|
||||
current_sampler_layout_uid_pixel_ = sampler_layout_uid_pixel;
|
||||
@@ -3633,7 +3634,7 @@ bool D3D12CommandProcessor::UpdateBindings(
|
||||
size_t(sampler_count_pixel)));
|
||||
for (uint32_t i = 0; i < sampler_count_pixel; ++i) {
|
||||
TextureCache::SamplerParameters parameters =
|
||||
texture_cache_->GetSamplerParameters(samplers_pixel[i]);
|
||||
texture_cache_->GetSamplerParameters((*samplers_pixel)[i]);
|
||||
if (current_samplers_pixel_[i] != parameters) {
|
||||
current_samplers_pixel_[i] = parameters;
|
||||
cbuffer_binding_descriptor_indices_pixel_.up_to_date = false;
|
||||
@@ -3663,7 +3664,7 @@ bool D3D12CommandProcessor::UpdateBindings(
|
||||
cbuffer_binding_descriptor_indices_vertex_.up_to_date &&
|
||||
(current_texture_layout_uid_vertex_ != texture_layout_uid_vertex ||
|
||||
!texture_cache_->AreActiveTextureSRVKeysUpToDate(
|
||||
current_texture_srv_keys_vertex_.data(), textures_vertex,
|
||||
current_texture_srv_keys_vertex_.data(), textures_vertex.data(),
|
||||
texture_count_vertex))) {
|
||||
cbuffer_binding_descriptor_indices_vertex_.up_to_date = false;
|
||||
}
|
||||
@@ -3671,7 +3672,7 @@ bool D3D12CommandProcessor::UpdateBindings(
|
||||
cbuffer_binding_descriptor_indices_pixel_.up_to_date &&
|
||||
(current_texture_layout_uid_pixel_ != texture_layout_uid_pixel ||
|
||||
!texture_cache_->AreActiveTextureSRVKeysUpToDate(
|
||||
current_texture_srv_keys_pixel_.data(), textures_pixel,
|
||||
current_texture_srv_keys_pixel_.data(), textures_pixel->data(),
|
||||
texture_count_pixel))) {
|
||||
cbuffer_binding_descriptor_indices_pixel_.up_to_date = false;
|
||||
}
|
||||
@@ -3804,15 +3805,14 @@ bool D3D12CommandProcessor::UpdateBindings(
|
||||
uint32_t* descriptor_indices =
|
||||
reinterpret_cast<uint32_t*>(constant_buffer_pool_->Request(
|
||||
frame_current_,
|
||||
std::max(texture_count_vertex + sampler_count_vertex,
|
||||
uint32_t(1)) *
|
||||
std::max(texture_count_vertex + sampler_count_vertex, size_t(1)) *
|
||||
sizeof(uint32_t),
|
||||
D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT, nullptr, nullptr,
|
||||
&cbuffer_binding_descriptor_indices_vertex_.address));
|
||||
if (!descriptor_indices) {
|
||||
return false;
|
||||
}
|
||||
for (uint32_t i = 0; i < texture_count_vertex; ++i) {
|
||||
for (size_t i = 0; i < texture_count_vertex; ++i) {
|
||||
const D3D12Shader::TextureBinding& texture = textures_vertex[i];
|
||||
descriptor_indices[texture.bindless_descriptor_index] =
|
||||
texture_cache_->GetActiveTextureBindlessSRVIndex(texture) -
|
||||
@@ -3824,11 +3824,11 @@ bool D3D12CommandProcessor::UpdateBindings(
|
||||
std::max(current_texture_srv_keys_vertex_.size(),
|
||||
size_t(texture_count_vertex)));
|
||||
texture_cache_->WriteActiveTextureSRVKeys(
|
||||
current_texture_srv_keys_vertex_.data(), textures_vertex,
|
||||
current_texture_srv_keys_vertex_.data(), textures_vertex.data(),
|
||||
texture_count_vertex);
|
||||
}
|
||||
// Current samplers have already been updated.
|
||||
for (uint32_t i = 0; i < sampler_count_vertex; ++i) {
|
||||
for (size_t i = 0; i < sampler_count_vertex; ++i) {
|
||||
descriptor_indices[samplers_vertex[i].bindless_descriptor_index] =
|
||||
current_sampler_bindless_indices_vertex_[i];
|
||||
}
|
||||
@@ -3841,15 +3841,15 @@ bool D3D12CommandProcessor::UpdateBindings(
|
||||
uint32_t* descriptor_indices =
|
||||
reinterpret_cast<uint32_t*>(constant_buffer_pool_->Request(
|
||||
frame_current_,
|
||||
std::max(texture_count_pixel + sampler_count_pixel, uint32_t(1)) *
|
||||
std::max(texture_count_pixel + sampler_count_pixel, size_t(1)) *
|
||||
sizeof(uint32_t),
|
||||
D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT, nullptr, nullptr,
|
||||
&cbuffer_binding_descriptor_indices_pixel_.address));
|
||||
if (!descriptor_indices) {
|
||||
return false;
|
||||
}
|
||||
for (uint32_t i = 0; i < texture_count_pixel; ++i) {
|
||||
const D3D12Shader::TextureBinding& texture = textures_pixel[i];
|
||||
for (size_t i = 0; i < texture_count_pixel; ++i) {
|
||||
const D3D12Shader::TextureBinding& texture = (*textures_pixel)[i];
|
||||
descriptor_indices[texture.bindless_descriptor_index] =
|
||||
texture_cache_->GetActiveTextureBindlessSRVIndex(texture) -
|
||||
uint32_t(SystemBindlessView::kUnboundedSRVsStart);
|
||||
@@ -3860,12 +3860,12 @@ bool D3D12CommandProcessor::UpdateBindings(
|
||||
std::max(current_texture_srv_keys_pixel_.size(),
|
||||
size_t(texture_count_pixel)));
|
||||
texture_cache_->WriteActiveTextureSRVKeys(
|
||||
current_texture_srv_keys_pixel_.data(), textures_pixel,
|
||||
current_texture_srv_keys_pixel_.data(), textures_pixel->data(),
|
||||
texture_count_pixel);
|
||||
}
|
||||
// Current samplers have already been updated.
|
||||
for (uint32_t i = 0; i < sampler_count_pixel; ++i) {
|
||||
descriptor_indices[samplers_pixel[i].bindless_descriptor_index] =
|
||||
for (size_t i = 0; i < sampler_count_pixel; ++i) {
|
||||
descriptor_indices[(*samplers_pixel)[i].bindless_descriptor_index] =
|
||||
current_sampler_bindless_indices_pixel_[i];
|
||||
}
|
||||
cbuffer_binding_descriptor_indices_pixel_.up_to_date = true;
|
||||
@@ -3884,14 +3884,14 @@ bool D3D12CommandProcessor::UpdateBindings(
|
||||
(!bindful_textures_written_vertex_ ||
|
||||
current_texture_layout_uid_vertex_ != texture_layout_uid_vertex ||
|
||||
!texture_cache_->AreActiveTextureSRVKeysUpToDate(
|
||||
current_texture_srv_keys_vertex_.data(), textures_vertex,
|
||||
current_texture_srv_keys_vertex_.data(), textures_vertex.data(),
|
||||
texture_count_vertex));
|
||||
bool write_textures_pixel =
|
||||
texture_count_pixel &&
|
||||
(!bindful_textures_written_pixel_ ||
|
||||
current_texture_layout_uid_pixel_ != texture_layout_uid_pixel ||
|
||||
!texture_cache_->AreActiveTextureSRVKeysUpToDate(
|
||||
current_texture_srv_keys_pixel_.data(), textures_pixel,
|
||||
current_texture_srv_keys_pixel_.data(), textures_pixel->data(),
|
||||
texture_count_pixel));
|
||||
bool write_samplers_vertex =
|
||||
sampler_count_vertex && !bindful_samplers_written_vertex_;
|
||||
@@ -3899,7 +3899,7 @@ bool D3D12CommandProcessor::UpdateBindings(
|
||||
sampler_count_pixel && !bindful_samplers_written_pixel_;
|
||||
|
||||
// Allocate the descriptors.
|
||||
uint32_t view_count_partial_update = 0;
|
||||
size_t view_count_partial_update = 0;
|
||||
if (write_textures_vertex) {
|
||||
view_count_partial_update += texture_count_vertex;
|
||||
}
|
||||
@@ -3907,7 +3907,7 @@ bool D3D12CommandProcessor::UpdateBindings(
|
||||
view_count_partial_update += texture_count_pixel;
|
||||
}
|
||||
// All the constants + shared memory SRV and UAV + textures.
|
||||
uint32_t view_count_full_update =
|
||||
size_t view_count_full_update =
|
||||
2 + texture_count_vertex + texture_count_pixel;
|
||||
if (edram_rov_used_) {
|
||||
// + EDRAM UAV.
|
||||
@@ -3917,14 +3917,14 @@ bool D3D12CommandProcessor::UpdateBindings(
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE view_gpu_handle;
|
||||
uint32_t descriptor_size_view = provider.GetViewDescriptorSize();
|
||||
uint64_t view_heap_index = RequestViewBindfulDescriptors(
|
||||
draw_view_bindful_heap_index_, view_count_partial_update,
|
||||
view_count_full_update, view_cpu_handle, view_gpu_handle);
|
||||
draw_view_bindful_heap_index_, uint32_t(view_count_partial_update),
|
||||
uint32_t(view_count_full_update), view_cpu_handle, view_gpu_handle);
|
||||
if (view_heap_index ==
|
||||
ui::d3d12::D3D12DescriptorHeapPool::kHeapIndexInvalid) {
|
||||
XELOGE("Failed to allocate view descriptors");
|
||||
return false;
|
||||
}
|
||||
uint32_t sampler_count_partial_update = 0;
|
||||
size_t sampler_count_partial_update = 0;
|
||||
if (write_samplers_vertex) {
|
||||
sampler_count_partial_update += sampler_count_vertex;
|
||||
}
|
||||
@@ -3938,9 +3938,10 @@ bool D3D12CommandProcessor::UpdateBindings(
|
||||
ui::d3d12::D3D12DescriptorHeapPool::kHeapIndexInvalid;
|
||||
if (sampler_count_vertex != 0 || sampler_count_pixel != 0) {
|
||||
sampler_heap_index = RequestSamplerBindfulDescriptors(
|
||||
draw_sampler_bindful_heap_index_, sampler_count_partial_update,
|
||||
sampler_count_vertex + sampler_count_pixel, sampler_cpu_handle,
|
||||
sampler_gpu_handle);
|
||||
draw_sampler_bindful_heap_index_,
|
||||
uint32_t(sampler_count_partial_update),
|
||||
uint32_t(sampler_count_vertex + sampler_count_pixel),
|
||||
sampler_cpu_handle, sampler_gpu_handle);
|
||||
if (sampler_heap_index ==
|
||||
ui::d3d12::D3D12DescriptorHeapPool::kHeapIndexInvalid) {
|
||||
XELOGE("Failed to allocate sampler descriptors");
|
||||
@@ -3985,7 +3986,7 @@ bool D3D12CommandProcessor::UpdateBindings(
|
||||
assert_true(current_graphics_root_bindful_extras_.textures_vertex !=
|
||||
RootBindfulExtraParameterIndices::kUnavailable);
|
||||
gpu_handle_textures_vertex_ = view_gpu_handle;
|
||||
for (uint32_t i = 0; i < texture_count_vertex; ++i) {
|
||||
for (size_t i = 0; i < texture_count_vertex; ++i) {
|
||||
texture_cache_->WriteActiveTextureBindfulSRV(textures_vertex[i],
|
||||
view_cpu_handle);
|
||||
view_cpu_handle.ptr += descriptor_size_view;
|
||||
@@ -3996,7 +3997,7 @@ bool D3D12CommandProcessor::UpdateBindings(
|
||||
std::max(current_texture_srv_keys_vertex_.size(),
|
||||
size_t(texture_count_vertex)));
|
||||
texture_cache_->WriteActiveTextureSRVKeys(
|
||||
current_texture_srv_keys_vertex_.data(), textures_vertex,
|
||||
current_texture_srv_keys_vertex_.data(), textures_vertex.data(),
|
||||
texture_count_vertex);
|
||||
bindful_textures_written_vertex_ = true;
|
||||
current_graphics_root_up_to_date_ &=
|
||||
@@ -4006,8 +4007,8 @@ bool D3D12CommandProcessor::UpdateBindings(
|
||||
assert_true(current_graphics_root_bindful_extras_.textures_pixel !=
|
||||
RootBindfulExtraParameterIndices::kUnavailable);
|
||||
gpu_handle_textures_pixel_ = view_gpu_handle;
|
||||
for (uint32_t i = 0; i < texture_count_pixel; ++i) {
|
||||
texture_cache_->WriteActiveTextureBindfulSRV(textures_pixel[i],
|
||||
for (size_t i = 0; i < texture_count_pixel; ++i) {
|
||||
texture_cache_->WriteActiveTextureBindfulSRV((*textures_pixel)[i],
|
||||
view_cpu_handle);
|
||||
view_cpu_handle.ptr += descriptor_size_view;
|
||||
view_gpu_handle.ptr += descriptor_size_view;
|
||||
@@ -4016,7 +4017,7 @@ bool D3D12CommandProcessor::UpdateBindings(
|
||||
current_texture_srv_keys_pixel_.resize(std::max(
|
||||
current_texture_srv_keys_pixel_.size(), size_t(texture_count_pixel)));
|
||||
texture_cache_->WriteActiveTextureSRVKeys(
|
||||
current_texture_srv_keys_pixel_.data(), textures_pixel,
|
||||
current_texture_srv_keys_pixel_.data(), textures_pixel->data(),
|
||||
texture_count_pixel);
|
||||
bindful_textures_written_pixel_ = true;
|
||||
current_graphics_root_up_to_date_ &=
|
||||
@@ -4026,7 +4027,7 @@ bool D3D12CommandProcessor::UpdateBindings(
|
||||
assert_true(current_graphics_root_bindful_extras_.samplers_vertex !=
|
||||
RootBindfulExtraParameterIndices::kUnavailable);
|
||||
gpu_handle_samplers_vertex_ = sampler_gpu_handle;
|
||||
for (uint32_t i = 0; i < sampler_count_vertex; ++i) {
|
||||
for (size_t i = 0; i < sampler_count_vertex; ++i) {
|
||||
texture_cache_->WriteSampler(current_samplers_vertex_[i],
|
||||
sampler_cpu_handle);
|
||||
sampler_cpu_handle.ptr += descriptor_size_sampler;
|
||||
@@ -4041,7 +4042,7 @@ bool D3D12CommandProcessor::UpdateBindings(
|
||||
assert_true(current_graphics_root_bindful_extras_.samplers_pixel !=
|
||||
RootBindfulExtraParameterIndices::kUnavailable);
|
||||
gpu_handle_samplers_pixel_ = sampler_gpu_handle;
|
||||
for (uint32_t i = 0; i < sampler_count_pixel; ++i) {
|
||||
for (size_t i = 0; i < sampler_count_pixel; ++i) {
|
||||
texture_cache_->WriteSampler(current_samplers_pixel_[i],
|
||||
sampler_cpu_handle);
|
||||
sampler_cpu_handle.ptr += descriptor_size_sampler;
|
||||
|
||||
@@ -89,7 +89,7 @@ class D3D12CommandProcessor : public CommandProcessor {
|
||||
// there are 4 render targets bound with the same EDRAM base (clearly not
|
||||
// correct usage), but the shader only clears 1, and then EDRAM buffer stores
|
||||
// conflict with each other.
|
||||
uint32_t GetCurrentColorMask(const Shader* pixel_shader) const;
|
||||
uint32_t GetCurrentColorMask(uint32_t shader_writes_color_targets) const;
|
||||
|
||||
void PushTransitionBarrier(
|
||||
ID3D12Resource* resource, D3D12_RESOURCE_STATES old_state,
|
||||
|
||||
@@ -99,7 +99,7 @@ void D3D12Shader::D3D12Translation::DisassembleDxbcAndDxil(
|
||||
}
|
||||
|
||||
Shader::Translation* D3D12Shader::CreateTranslationInstance(
|
||||
uint32_t modification) {
|
||||
uint64_t modification) {
|
||||
return new D3D12Translation(*this, modification);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ class D3D12Shader : public DxbcShader {
|
||||
public:
|
||||
class D3D12Translation : public DxbcTranslation {
|
||||
public:
|
||||
D3D12Translation(D3D12Shader& shader, uint32_t modification)
|
||||
D3D12Translation(D3D12Shader& shader, uint64_t modification)
|
||||
: DxbcTranslation(shader, modification) {}
|
||||
|
||||
void DisassembleDxbcAndDxil(const ui::d3d12::D3D12Provider& provider,
|
||||
@@ -60,7 +60,7 @@ class D3D12Shader : public DxbcShader {
|
||||
}
|
||||
|
||||
protected:
|
||||
Translation* CreateTranslationInstance(uint32_t modification) override;
|
||||
Translation* CreateTranslationInstance(uint64_t modification) override;
|
||||
|
||||
private:
|
||||
std::atomic_flag binding_layout_user_uids_set_up_ = ATOMIC_FLAG_INIT;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "third_party/fmt/include/fmt/format.h"
|
||||
#include "xenia/base/assert.h"
|
||||
@@ -29,6 +30,7 @@
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/base/profiling.h"
|
||||
#include "xenia/base/string.h"
|
||||
#include "xenia/base/string_buffer.h"
|
||||
#include "xenia/base/xxhash.h"
|
||||
#include "xenia/gpu/d3d12/d3d12_command_processor.h"
|
||||
#include "xenia/gpu/gpu_flags.h"
|
||||
@@ -265,7 +267,7 @@ void PipelineCache::InitializeShaderStorage(
|
||||
// collect used shader modifications to translate.
|
||||
std::vector<PipelineStoredDescription> pipeline_stored_descriptions;
|
||||
// <Shader hash, modification bits>.
|
||||
std::set<std::pair<uint64_t, uint32_t>> shader_translations_needed;
|
||||
std::set<std::pair<uint64_t, uint64_t>> shader_translations_needed;
|
||||
auto pipeline_storage_file_path =
|
||||
shader_storage_shareable_root /
|
||||
fmt::format("{:08X}.{}.d3d12.xpso", title_id,
|
||||
@@ -292,7 +294,6 @@ void PipelineCache::InitializeShaderStorage(
|
||||
uint32_t magic;
|
||||
uint32_t magic_api;
|
||||
uint32_t version_swapped;
|
||||
uint32_t device_features;
|
||||
} pipeline_storage_file_header;
|
||||
if (fread(&pipeline_storage_file_header, sizeof(pipeline_storage_file_header),
|
||||
1, pipeline_storage_file_) &&
|
||||
@@ -331,6 +332,9 @@ void PipelineCache::InitializeShaderStorage(
|
||||
pipeline_stored_descriptions.resize(i);
|
||||
break;
|
||||
}
|
||||
// TODO(Triang3l): On Vulkan, skip pipelines requiring unsupported
|
||||
// device features (to keep the cache files mostly shareable across
|
||||
// devices).
|
||||
// Mark the shader modifications as needed for translation.
|
||||
shader_translations_needed.emplace(
|
||||
pipeline_stored_description.description.vertex_shader_hash,
|
||||
@@ -391,14 +395,14 @@ void PipelineCache::InitializeShaderStorage(
|
||||
// Threads overlapping file reading.
|
||||
std::mutex shaders_translation_thread_mutex;
|
||||
std::condition_variable shaders_translation_thread_cond;
|
||||
std::deque<std::pair<ShaderStoredHeader, D3D12Shader::D3D12Translation*>>
|
||||
shaders_to_translate;
|
||||
std::deque<D3D12Shader*> shaders_to_translate;
|
||||
size_t shader_translation_threads_busy = 0;
|
||||
bool shader_translation_threads_shutdown = false;
|
||||
std::mutex shaders_failed_to_translate_mutex;
|
||||
std::vector<D3D12Shader::D3D12Translation*> shaders_failed_to_translate;
|
||||
auto shader_translation_thread_function = [&]() {
|
||||
auto& provider = command_processor_.GetD3D12Context().GetD3D12Provider();
|
||||
StringBuffer ucode_disasm_buffer;
|
||||
DxbcShaderTranslator translator(
|
||||
provider.GetAdapterVendorID(), bindless_resources_used_,
|
||||
edram_rov_used_, provider.GetGraphicsAnalysis() != nullptr);
|
||||
@@ -416,8 +420,7 @@ void PipelineCache::InitializeShaderStorage(
|
||||
IID_PPV_ARGS(&dxc_compiler));
|
||||
}
|
||||
for (;;) {
|
||||
std::pair<ShaderStoredHeader, D3D12Shader::D3D12Translation*>
|
||||
shader_to_translate;
|
||||
D3D12Shader* shader_to_translate;
|
||||
for (;;) {
|
||||
std::unique_lock<std::mutex> lock(shaders_translation_thread_mutex);
|
||||
if (shaders_to_translate.empty()) {
|
||||
@@ -432,12 +435,29 @@ void PipelineCache::InitializeShaderStorage(
|
||||
++shader_translation_threads_busy;
|
||||
break;
|
||||
}
|
||||
assert_not_null(shader_to_translate.second);
|
||||
if (!TranslateShader(translator, *shader_to_translate.second,
|
||||
shader_to_translate.first.sq_program_cntl,
|
||||
dxbc_converter, dxc_utils, dxc_compiler)) {
|
||||
std::lock_guard<std::mutex> lock(shaders_failed_to_translate_mutex);
|
||||
shaders_failed_to_translate.push_back(shader_to_translate.second);
|
||||
shader_to_translate->AnalyzeUcode(ucode_disasm_buffer);
|
||||
// Translate each needed modification on this thread after performing
|
||||
// modification-independent analysis of the whole shader.
|
||||
uint64_t ucode_data_hash = shader_to_translate->ucode_data_hash();
|
||||
for (auto modification_it = shader_translations_needed.lower_bound(
|
||||
std::make_pair(ucode_data_hash, uint64_t(0)));
|
||||
modification_it != shader_translations_needed.end() &&
|
||||
modification_it->first == ucode_data_hash;
|
||||
++modification_it) {
|
||||
D3D12Shader::D3D12Translation* translation =
|
||||
static_cast<D3D12Shader::D3D12Translation*>(
|
||||
shader_to_translate->GetOrCreateTranslation(
|
||||
modification_it->second));
|
||||
// Only try (and delete in case of failure) if it's a new translation.
|
||||
// If it's a shader previously encountered in the game, translation of
|
||||
// which has failed, and the shader storage is loaded later, keep it
|
||||
// this way not to try to translate it again.
|
||||
if (!translation->is_translated() &&
|
||||
!TranslateAnalyzedShader(translator, *translation, dxbc_converter,
|
||||
dxc_utils, dxc_compiler)) {
|
||||
std::lock_guard<std::mutex> lock(shaders_failed_to_translate_mutex);
|
||||
shaders_failed_to_translate.push_back(translation);
|
||||
}
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(shaders_translation_thread_mutex);
|
||||
@@ -477,59 +497,41 @@ void PipelineCache::InitializeShaderStorage(
|
||||
break;
|
||||
}
|
||||
shader_storage_valid_bytes += sizeof(shader_header) + ucode_byte_count;
|
||||
// Only add the shader if needed.
|
||||
auto modification_it = shader_translations_needed.lower_bound(
|
||||
std::make_pair(ucode_data_hash, uint32_t(0)));
|
||||
if (modification_it == shader_translations_needed.end() ||
|
||||
modification_it->first != ucode_data_hash) {
|
||||
continue;
|
||||
}
|
||||
D3D12Shader* shader =
|
||||
LoadShader(shader_header.type, ucode_dwords.data(),
|
||||
shader_header.ucode_dword_count, ucode_data_hash);
|
||||
if (shader->ucode_storage_index() == shader_storage_index_) {
|
||||
// Appeared twice in this file for some reason - skip, otherwise race
|
||||
// condition will be caused by translating twice in parallel.
|
||||
continue;
|
||||
}
|
||||
// Loaded from the current storage - don't write again.
|
||||
shader->set_ucode_storage_index(shader_storage_index_);
|
||||
// Translate all the needed modifications.
|
||||
for (; modification_it != shader_translations_needed.end() &&
|
||||
modification_it->first == ucode_data_hash;
|
||||
++modification_it) {
|
||||
bool translation_is_new;
|
||||
D3D12Shader::D3D12Translation* translation =
|
||||
static_cast<D3D12Shader::D3D12Translation*>(
|
||||
shader->GetOrCreateTranslation(modification_it->second,
|
||||
&translation_is_new));
|
||||
if (!translation_is_new) {
|
||||
// Already added - usually shaders aren't added without the intention
|
||||
// of translating them imminently, so don't do additional checks to
|
||||
// actually ensure that translation happens right now (they would
|
||||
// cause a race condition with shaders currently queued for
|
||||
// translation).
|
||||
continue;
|
||||
}
|
||||
// Create new threads if the currently existing threads can't keep up
|
||||
// with file reading, but not more than the number of logical processors
|
||||
// minus one.
|
||||
size_t shader_translation_threads_needed;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(shaders_translation_thread_mutex);
|
||||
shader_translation_threads_needed =
|
||||
std::min(shader_translation_threads_busy +
|
||||
shaders_to_translate.size() + size_t(1),
|
||||
logical_processor_count - size_t(1));
|
||||
}
|
||||
while (shader_translation_threads.size() <
|
||||
shader_translation_threads_needed) {
|
||||
shader_translation_threads.push_back(xe::threading::Thread::Create(
|
||||
{}, shader_translation_thread_function));
|
||||
shader_translation_threads.back()->set_name("Shader Translation");
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(shaders_translation_thread_mutex);
|
||||
shaders_to_translate.emplace_back(shader_header, translation);
|
||||
}
|
||||
shaders_translation_thread_cond.notify_one();
|
||||
++shaders_translated;
|
||||
// Create new threads if the currently existing threads can't keep up
|
||||
// with file reading, but not more than the number of logical processors
|
||||
// minus one.
|
||||
size_t shader_translation_threads_needed;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(shaders_translation_thread_mutex);
|
||||
shader_translation_threads_needed =
|
||||
std::min(shader_translation_threads_busy +
|
||||
shaders_to_translate.size() + size_t(1),
|
||||
logical_processor_count - size_t(1));
|
||||
}
|
||||
while (shader_translation_threads.size() <
|
||||
shader_translation_threads_needed) {
|
||||
shader_translation_threads.push_back(xe::threading::Thread::Create(
|
||||
{}, shader_translation_thread_function));
|
||||
shader_translation_threads.back()->set_name("Shader Translation");
|
||||
}
|
||||
// Request ucode information gathering and translation of all the needed
|
||||
// shaders.
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(shaders_translation_thread_mutex);
|
||||
shaders_to_translate.push_back(shader);
|
||||
}
|
||||
shaders_translation_thread_cond.notify_one();
|
||||
++shaders_translated;
|
||||
}
|
||||
if (!shader_translation_threads.empty()) {
|
||||
{
|
||||
@@ -593,6 +595,8 @@ void PipelineCache::InitializeShaderStorage(
|
||||
pipeline_stored_descriptions) {
|
||||
const PipelineDescription& pipeline_description =
|
||||
pipeline_stored_description.description;
|
||||
// TODO(Triang3l): On Vulkan, skip pipelines requiring unsupported device
|
||||
// features (to keep the cache files mostly shareable across devices).
|
||||
// Skip already known pipelines - those have already been enqueued.
|
||||
auto found_range =
|
||||
pipelines_.equal_range(pipeline_stored_description.description_hash);
|
||||
@@ -621,6 +625,7 @@ void PipelineCache::InitializeShaderStorage(
|
||||
vertex_shader->GetTranslation(
|
||||
pipeline_description.vertex_shader_modification));
|
||||
if (!pipeline_runtime_description.vertex_shader ||
|
||||
!pipeline_runtime_description.vertex_shader->is_translated() ||
|
||||
!pipeline_runtime_description.vertex_shader->is_valid()) {
|
||||
continue;
|
||||
}
|
||||
@@ -637,6 +642,7 @@ void PipelineCache::InitializeShaderStorage(
|
||||
pixel_shader->GetTranslation(
|
||||
pipeline_description.pixel_shader_modification));
|
||||
if (!pipeline_runtime_description.pixel_shader ||
|
||||
!pipeline_runtime_description.pixel_shader->is_translated() ||
|
||||
!pipeline_runtime_description.pixel_shader->is_valid()) {
|
||||
continue;
|
||||
}
|
||||
@@ -730,9 +736,6 @@ void PipelineCache::InitializeShaderStorage(
|
||||
pipeline_storage_file_header.magic_api = pipeline_storage_magic_api;
|
||||
pipeline_storage_file_header.version_swapped =
|
||||
pipeline_storage_version_swapped;
|
||||
// Reserved for future (for Vulkan) - host device features affecting legal
|
||||
// pipeline descriptions.
|
||||
pipeline_storage_file_header.device_features = 0;
|
||||
fwrite(&pipeline_storage_file_header, sizeof(pipeline_storage_file_header),
|
||||
1, pipeline_storage_file_);
|
||||
}
|
||||
@@ -854,52 +857,68 @@ D3D12Shader* PipelineCache::LoadShader(xenos::ShaderType shader_type,
|
||||
return shader;
|
||||
}
|
||||
|
||||
bool PipelineCache::GetCurrentShaderModifications(
|
||||
bool PipelineCache::AnalyzeShaderUcodeAndGetCurrentModifications(
|
||||
D3D12Shader* vertex_shader, D3D12Shader* pixel_shader,
|
||||
DxbcShaderTranslator::Modification& vertex_shader_modification_out,
|
||||
DxbcShaderTranslator::Modification& pixel_shader_modification_out) const {
|
||||
DxbcShaderTranslator::Modification& pixel_shader_modification_out) {
|
||||
Shader::HostVertexShaderType host_vertex_shader_type =
|
||||
GetCurrentHostVertexShaderTypeIfValid();
|
||||
if (host_vertex_shader_type == Shader::HostVertexShaderType(-1)) {
|
||||
return false;
|
||||
}
|
||||
const auto& regs = register_file_;
|
||||
auto sq_program_cntl = regs.Get<reg::SQ_PROGRAM_CNTL>();
|
||||
|
||||
vertex_shader->AnalyzeUcode(ucode_disasm_buffer_);
|
||||
vertex_shader_modification_out = DxbcShaderTranslator::Modification(
|
||||
shader_translator_->GetDefaultModification(xenos::ShaderType::kVertex,
|
||||
host_vertex_shader_type));
|
||||
DxbcShaderTranslator::Modification pixel_shader_modification(
|
||||
shader_translator_->GetDefaultModification(xenos::ShaderType::kPixel));
|
||||
if (!edram_rov_used_) {
|
||||
const auto& regs = register_file_;
|
||||
using DepthStencilMode =
|
||||
DxbcShaderTranslator::Modification::DepthStencilMode;
|
||||
if ((depth_float24_conversion_ ==
|
||||
flags::DepthFloat24Conversion::kOnOutputTruncating ||
|
||||
depth_float24_conversion_ ==
|
||||
flags::DepthFloat24Conversion::kOnOutputRounding) &&
|
||||
regs.Get<reg::RB_DEPTHCONTROL>().z_enable &&
|
||||
regs.Get<reg::RB_DEPTH_INFO>().depth_format ==
|
||||
xenos::DepthRenderTargetFormat::kD24FS8) {
|
||||
pixel_shader_modification.depth_stencil_mode =
|
||||
depth_float24_conversion_ ==
|
||||
flags::DepthFloat24Conversion::kOnOutputTruncating
|
||||
? DepthStencilMode::kFloat24Truncating
|
||||
: DepthStencilMode::kFloat24Rounding;
|
||||
} else {
|
||||
// Hint to enable early depth/stencil writing if possible - whether it
|
||||
// will actually take effect depends on the shader itself, it's not known
|
||||
// before translation.
|
||||
auto rb_colorcontrol = regs.Get<reg::RB_COLORCONTROL>();
|
||||
if ((!rb_colorcontrol.alpha_test_enable ||
|
||||
rb_colorcontrol.alpha_func == xenos::CompareFunction::kAlways) &&
|
||||
!rb_colorcontrol.alpha_to_mask_enable) {
|
||||
shader_translator_->GetDefaultModification(
|
||||
xenos::ShaderType::kVertex,
|
||||
vertex_shader->GetDynamicAddressableRegisterCount(
|
||||
sq_program_cntl.vs_num_reg),
|
||||
host_vertex_shader_type));
|
||||
|
||||
if (pixel_shader) {
|
||||
pixel_shader->AnalyzeUcode(ucode_disasm_buffer_);
|
||||
DxbcShaderTranslator::Modification pixel_shader_modification(
|
||||
shader_translator_->GetDefaultModification(
|
||||
xenos::ShaderType::kPixel,
|
||||
pixel_shader->GetDynamicAddressableRegisterCount(
|
||||
sq_program_cntl.ps_num_reg)));
|
||||
if (!edram_rov_used_) {
|
||||
using DepthStencilMode =
|
||||
DxbcShaderTranslator::Modification::DepthStencilMode;
|
||||
if ((depth_float24_conversion_ ==
|
||||
flags::DepthFloat24Conversion::kOnOutputTruncating ||
|
||||
depth_float24_conversion_ ==
|
||||
flags::DepthFloat24Conversion::kOnOutputRounding) &&
|
||||
regs.Get<reg::RB_DEPTHCONTROL>().z_enable &&
|
||||
regs.Get<reg::RB_DEPTH_INFO>().depth_format ==
|
||||
xenos::DepthRenderTargetFormat::kD24FS8) {
|
||||
pixel_shader_modification.depth_stencil_mode =
|
||||
DepthStencilMode::kEarlyHint;
|
||||
depth_float24_conversion_ ==
|
||||
flags::DepthFloat24Conversion::kOnOutputTruncating
|
||||
? DepthStencilMode::kFloat24Truncating
|
||||
: DepthStencilMode::kFloat24Rounding;
|
||||
} else {
|
||||
pixel_shader_modification.depth_stencil_mode =
|
||||
DepthStencilMode::kNoModifiers;
|
||||
auto rb_colorcontrol = regs.Get<reg::RB_COLORCONTROL>();
|
||||
if (pixel_shader->implicit_early_z_write_allowed() &&
|
||||
(!rb_colorcontrol.alpha_test_enable ||
|
||||
rb_colorcontrol.alpha_func == xenos::CompareFunction::kAlways) &&
|
||||
!rb_colorcontrol.alpha_to_mask_enable) {
|
||||
pixel_shader_modification.depth_stencil_mode =
|
||||
DepthStencilMode::kEarlyHint;
|
||||
} else {
|
||||
pixel_shader_modification.depth_stencil_mode =
|
||||
DepthStencilMode::kNoModifiers;
|
||||
}
|
||||
}
|
||||
}
|
||||
pixel_shader_modification_out = pixel_shader_modification;
|
||||
} else {
|
||||
pixel_shader_modification_out = DxbcShaderTranslator::Modification(
|
||||
shader_translator_->GetDefaultModification(xenos::ShaderType::kPixel,
|
||||
0));
|
||||
}
|
||||
pixel_shader_modification_out = pixel_shader_modification;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -979,62 +998,6 @@ PipelineCache::GetCurrentHostVertexShaderTypeIfValid() const {
|
||||
return Shader::HostVertexShaderType(-1);
|
||||
}
|
||||
|
||||
bool PipelineCache::EnsureShadersTranslated(
|
||||
D3D12Shader::D3D12Translation* vertex_shader,
|
||||
D3D12Shader::D3D12Translation* pixel_shader) {
|
||||
const auto& regs = register_file_;
|
||||
auto sq_program_cntl = regs.Get<reg::SQ_PROGRAM_CNTL>();
|
||||
|
||||
// Edge flags are not supported yet (because polygon primitives are not).
|
||||
assert_true(sq_program_cntl.vs_export_mode !=
|
||||
xenos::VertexShaderExportMode::kPosition2VectorsEdge &&
|
||||
sq_program_cntl.vs_export_mode !=
|
||||
xenos::VertexShaderExportMode::kPosition2VectorsEdgeKill);
|
||||
assert_false(sq_program_cntl.gen_index_vtx);
|
||||
|
||||
if (!vertex_shader->is_translated()) {
|
||||
if (!TranslateShader(*shader_translator_, *vertex_shader, sq_program_cntl,
|
||||
dxbc_converter_, dxc_utils_, dxc_compiler_)) {
|
||||
XELOGE("Failed to translate the vertex shader!");
|
||||
return false;
|
||||
}
|
||||
if (shader_storage_file_ && vertex_shader->shader().ucode_storage_index() !=
|
||||
shader_storage_index_) {
|
||||
vertex_shader->shader().set_ucode_storage_index(shader_storage_index_);
|
||||
assert_not_null(storage_write_thread_);
|
||||
shader_storage_file_flush_needed_ = true;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(storage_write_request_lock_);
|
||||
storage_write_shader_queue_.push_back(
|
||||
std::make_pair(&vertex_shader->shader(), sq_program_cntl));
|
||||
}
|
||||
storage_write_request_cond_.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
if (pixel_shader != nullptr && !pixel_shader->is_translated()) {
|
||||
if (!TranslateShader(*shader_translator_, *pixel_shader, sq_program_cntl,
|
||||
dxbc_converter_, dxc_utils_, dxc_compiler_)) {
|
||||
XELOGE("Failed to translate the pixel shader!");
|
||||
return false;
|
||||
}
|
||||
if (shader_storage_file_ &&
|
||||
pixel_shader->shader().ucode_storage_index() != shader_storage_index_) {
|
||||
pixel_shader->shader().set_ucode_storage_index(shader_storage_index_);
|
||||
assert_not_null(storage_write_thread_);
|
||||
shader_storage_file_flush_needed_ = true;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(storage_write_request_lock_);
|
||||
storage_write_shader_queue_.push_back(
|
||||
std::make_pair(&pixel_shader->shader(), sq_program_cntl));
|
||||
}
|
||||
storage_write_request_cond_.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PipelineCache::ConfigurePipeline(
|
||||
D3D12Shader::D3D12Translation* vertex_shader,
|
||||
D3D12Shader::D3D12Translation* pixel_shader,
|
||||
@@ -1078,8 +1041,50 @@ bool PipelineCache::ConfigurePipeline(
|
||||
}
|
||||
}
|
||||
|
||||
if (!EnsureShadersTranslated(vertex_shader, pixel_shader)) {
|
||||
return false;
|
||||
// Ensure shaders are translated.
|
||||
// Edge flags are not supported yet (because polygon primitives are not).
|
||||
assert_true(register_file_.Get<reg::SQ_PROGRAM_CNTL>().vs_export_mode !=
|
||||
xenos::VertexShaderExportMode::kPosition2VectorsEdge &&
|
||||
register_file_.Get<reg::SQ_PROGRAM_CNTL>().vs_export_mode !=
|
||||
xenos::VertexShaderExportMode::kPosition2VectorsEdgeKill);
|
||||
assert_false(register_file_.Get<reg::SQ_PROGRAM_CNTL>().gen_index_vtx);
|
||||
if (!vertex_shader->is_translated()) {
|
||||
vertex_shader->shader().AnalyzeUcode(ucode_disasm_buffer_);
|
||||
if (!TranslateAnalyzedShader(*shader_translator_, *vertex_shader,
|
||||
dxbc_converter_, dxc_utils_, dxc_compiler_)) {
|
||||
XELOGE("Failed to translate the vertex shader!");
|
||||
return false;
|
||||
}
|
||||
if (shader_storage_file_ && vertex_shader->shader().ucode_storage_index() !=
|
||||
shader_storage_index_) {
|
||||
vertex_shader->shader().set_ucode_storage_index(shader_storage_index_);
|
||||
assert_not_null(storage_write_thread_);
|
||||
shader_storage_file_flush_needed_ = true;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(storage_write_request_lock_);
|
||||
storage_write_shader_queue_.push_back(&vertex_shader->shader());
|
||||
}
|
||||
storage_write_request_cond_.notify_all();
|
||||
}
|
||||
}
|
||||
if (pixel_shader != nullptr && !pixel_shader->is_translated()) {
|
||||
pixel_shader->shader().AnalyzeUcode(ucode_disasm_buffer_);
|
||||
if (!TranslateAnalyzedShader(*shader_translator_, *pixel_shader,
|
||||
dxbc_converter_, dxc_utils_, dxc_compiler_)) {
|
||||
XELOGE("Failed to translate the pixel shader!");
|
||||
return false;
|
||||
}
|
||||
if (shader_storage_file_ &&
|
||||
pixel_shader->shader().ucode_storage_index() != shader_storage_index_) {
|
||||
pixel_shader->shader().set_ucode_storage_index(shader_storage_index_);
|
||||
assert_not_null(storage_write_thread_);
|
||||
shader_storage_file_flush_needed_ = true;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(storage_write_request_lock_);
|
||||
storage_write_shader_queue_.push_back(&pixel_shader->shader());
|
||||
}
|
||||
storage_write_request_cond_.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
Pipeline* new_pipeline = new Pipeline;
|
||||
@@ -1121,17 +1126,15 @@ bool PipelineCache::ConfigurePipeline(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PipelineCache::TranslateShader(DxbcShaderTranslator& translator,
|
||||
D3D12Shader::D3D12Translation& translation,
|
||||
reg::SQ_PROGRAM_CNTL cntl,
|
||||
IDxbcConverter* dxbc_converter,
|
||||
IDxcUtils* dxc_utils,
|
||||
IDxcCompiler* dxc_compiler) {
|
||||
bool PipelineCache::TranslateAnalyzedShader(
|
||||
DxbcShaderTranslator& translator,
|
||||
D3D12Shader::D3D12Translation& translation, IDxbcConverter* dxbc_converter,
|
||||
IDxcUtils* dxc_utils, IDxcCompiler* dxc_compiler) {
|
||||
D3D12Shader& shader = static_cast<D3D12Shader&>(translation.shader());
|
||||
|
||||
// Perform translation.
|
||||
// If this fails the shader will be marked as invalid and ignored later.
|
||||
if (!translator.Translate(translation, cntl)) {
|
||||
if (!translator.TranslateAnalyzedShader(translation)) {
|
||||
XELOGE("Shader {:016X} translation failed; marking as ignored",
|
||||
shader.ucode_data_hash());
|
||||
return false;
|
||||
@@ -1171,21 +1174,21 @@ bool PipelineCache::TranslateShader(DxbcShaderTranslator& translator,
|
||||
|
||||
// Set up texture and sampler binding layouts.
|
||||
if (shader.EnterBindingLayoutUserUIDSetup()) {
|
||||
uint32_t texture_binding_count;
|
||||
const D3D12Shader::TextureBinding* texture_bindings =
|
||||
shader.GetTextureBindings(texture_binding_count);
|
||||
uint32_t sampler_binding_count;
|
||||
const D3D12Shader::SamplerBinding* sampler_bindings =
|
||||
shader.GetSamplerBindings(sampler_binding_count);
|
||||
const std::vector<D3D12Shader::TextureBinding>& texture_bindings =
|
||||
shader.GetTextureBindingsAfterTranslation();
|
||||
uint32_t texture_binding_count = uint32_t(texture_bindings.size());
|
||||
const std::vector<D3D12Shader::SamplerBinding>& sampler_bindings =
|
||||
shader.GetSamplerBindingsAfterTranslation();
|
||||
uint32_t sampler_binding_count = uint32_t(sampler_bindings.size());
|
||||
assert_false(bindless_resources_used_ &&
|
||||
texture_binding_count + sampler_binding_count >
|
||||
D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * 4);
|
||||
size_t texture_binding_layout_bytes =
|
||||
texture_binding_count * sizeof(*texture_bindings);
|
||||
texture_binding_count * sizeof(*texture_bindings.data());
|
||||
uint64_t texture_binding_layout_hash = 0;
|
||||
if (texture_binding_count) {
|
||||
texture_binding_layout_hash =
|
||||
XXH3_64bits(texture_bindings, texture_binding_layout_bytes);
|
||||
XXH3_64bits(texture_bindings.data(), texture_binding_layout_bytes);
|
||||
}
|
||||
uint32_t bindless_sampler_count =
|
||||
bindless_resources_used_ ? sampler_binding_count : 0;
|
||||
@@ -1223,7 +1226,8 @@ bool PipelineCache::TranslateShader(DxbcShaderTranslator& translator,
|
||||
if (it->second.vector_span_length == texture_binding_count &&
|
||||
!std::memcmp(texture_binding_layouts_.data() +
|
||||
it->second.vector_span_offset,
|
||||
texture_bindings, texture_binding_layout_bytes)) {
|
||||
texture_bindings.data(),
|
||||
texture_binding_layout_bytes)) {
|
||||
texture_binding_layout_uid = it->second.uid;
|
||||
break;
|
||||
}
|
||||
@@ -1242,7 +1246,7 @@ bool PipelineCache::TranslateShader(DxbcShaderTranslator& translator,
|
||||
texture_binding_count);
|
||||
std::memcpy(
|
||||
texture_binding_layouts_.data() + new_uid.vector_span_offset,
|
||||
texture_bindings, texture_binding_layout_bytes);
|
||||
texture_bindings.data(), texture_binding_layout_bytes);
|
||||
texture_binding_layout_map_.emplace(texture_binding_layout_hash,
|
||||
new_uid);
|
||||
}
|
||||
@@ -1576,8 +1580,10 @@ bool PipelineCache::GetCurrentStateDescription(
|
||||
|
||||
// Render targets and blending state. 32 because of 0x1F mask, for safety
|
||||
// (all unknown to zero).
|
||||
uint32_t color_mask = command_processor_.GetCurrentColorMask(
|
||||
pixel_shader ? &pixel_shader->shader() : nullptr);
|
||||
uint32_t color_mask =
|
||||
pixel_shader ? command_processor_.GetCurrentColorMask(
|
||||
pixel_shader->shader().writes_color_targets())
|
||||
: 0;
|
||||
static const PipelineBlendFactor kBlendFactorMap[32] = {
|
||||
/* 0 */ PipelineBlendFactor::kZero,
|
||||
/* 1 */ PipelineBlendFactor::kOne,
|
||||
@@ -2038,7 +2044,7 @@ void PipelineCache::StorageWriteThread() {
|
||||
fflush(pipeline_storage_file_);
|
||||
}
|
||||
|
||||
std::pair<const Shader*, reg::SQ_PROGRAM_CNTL> shader_pair = {};
|
||||
const Shader* shader = nullptr;
|
||||
PipelineStoredDescription pipeline_description;
|
||||
bool write_pipeline = false;
|
||||
{
|
||||
@@ -2047,7 +2053,7 @@ void PipelineCache::StorageWriteThread() {
|
||||
return;
|
||||
}
|
||||
if (!storage_write_shader_queue_.empty()) {
|
||||
shader_pair = storage_write_shader_queue_.front();
|
||||
shader = storage_write_shader_queue_.front();
|
||||
storage_write_shader_queue_.pop_front();
|
||||
} else if (storage_write_flush_shaders_) {
|
||||
storage_write_flush_shaders_ = false;
|
||||
@@ -2063,18 +2069,16 @@ void PipelineCache::StorageWriteThread() {
|
||||
storage_write_flush_pipelines_ = false;
|
||||
flush_pipelines = true;
|
||||
}
|
||||
if (!shader_pair.first && !write_pipeline) {
|
||||
if (!shader && !write_pipeline) {
|
||||
storage_write_request_cond_.wait(lock);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const Shader* shader = shader_pair.first;
|
||||
if (shader) {
|
||||
shader_header.ucode_data_hash = shader->ucode_data_hash();
|
||||
shader_header.ucode_dword_count = shader->ucode_dword_count();
|
||||
shader_header.type = shader->type();
|
||||
shader_header.sq_program_cntl = shader_pair.second;
|
||||
assert_not_null(shader_storage_file_);
|
||||
fwrite(&shader_header, sizeof(shader_header), 1, shader_storage_file_);
|
||||
if (shader_header.ucode_dword_count) {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "xenia/base/hash.h"
|
||||
#include "xenia/base/platform.h"
|
||||
#include "xenia/base/string_buffer.h"
|
||||
#include "xenia/base/threading.h"
|
||||
#include "xenia/gpu/d3d12/d3d12_shader.h"
|
||||
#include "xenia/gpu/d3d12/render_target_cache.h"
|
||||
@@ -63,15 +64,12 @@ class PipelineCache {
|
||||
D3D12Shader* LoadShader(xenos::ShaderType shader_type,
|
||||
const uint32_t* host_address, uint32_t dword_count);
|
||||
|
||||
// Retrieves the shader modifications for the current state, and returns
|
||||
// whether they are valid.
|
||||
bool GetCurrentShaderModifications(
|
||||
// Ensures microcode is analyzed, retrieves the shader modifications for the
|
||||
// current state, and returns whether they are valid.
|
||||
bool AnalyzeShaderUcodeAndGetCurrentModifications(
|
||||
D3D12Shader* vertex_shader, D3D12Shader* pixel_shader,
|
||||
DxbcShaderTranslator::Modification& vertex_shader_modification_out,
|
||||
DxbcShaderTranslator::Modification& pixel_shader_modification_out) const;
|
||||
|
||||
// Translates shaders if needed, also making shader info up to date.
|
||||
bool EnsureShadersTranslated(D3D12Shader::D3D12Translation* vertex_shader,
|
||||
D3D12Shader::D3D12Translation* pixel_shader);
|
||||
DxbcShaderTranslator::Modification& pixel_shader_modification_out);
|
||||
|
||||
bool ConfigurePipeline(
|
||||
D3D12Shader::D3D12Translation* vertex_shader,
|
||||
@@ -93,9 +91,7 @@ class PipelineCache {
|
||||
uint32_t ucode_dword_count : 31;
|
||||
xenos::ShaderType type : 1;
|
||||
|
||||
reg::SQ_PROGRAM_CNTL sq_program_cntl;
|
||||
|
||||
static constexpr uint32_t kVersion = 0x20201207;
|
||||
static constexpr uint32_t kVersion = 0x20201219;
|
||||
});
|
||||
|
||||
// Update PipelineDescription::kVersion if any of the Pipeline* enums are
|
||||
@@ -171,10 +167,10 @@ class PipelineCache {
|
||||
|
||||
XEPACKEDSTRUCT(PipelineDescription, {
|
||||
uint64_t vertex_shader_hash;
|
||||
uint64_t vertex_shader_modification;
|
||||
// 0 if drawing without a pixel shader.
|
||||
uint64_t pixel_shader_hash;
|
||||
uint32_t vertex_shader_modification;
|
||||
uint32_t pixel_shader_modification;
|
||||
uint64_t pixel_shader_modification;
|
||||
|
||||
int32_t depth_bias;
|
||||
float depth_bias_slope_scaled;
|
||||
@@ -208,7 +204,7 @@ class PipelineCache {
|
||||
|
||||
PipelineRenderTarget render_targets[4];
|
||||
|
||||
static constexpr uint32_t kVersion = 0x20201207;
|
||||
static constexpr uint32_t kVersion = 0x20201219;
|
||||
});
|
||||
|
||||
XEPACKEDSTRUCT(PipelineStoredDescription, {
|
||||
@@ -232,12 +228,11 @@ class PipelineCache {
|
||||
uint64_t data_hash);
|
||||
|
||||
// Can be called from multiple threads.
|
||||
bool TranslateShader(DxbcShaderTranslator& translator,
|
||||
D3D12Shader::D3D12Translation& translation,
|
||||
reg::SQ_PROGRAM_CNTL cntl,
|
||||
IDxbcConverter* dxbc_converter = nullptr,
|
||||
IDxcUtils* dxc_utils = nullptr,
|
||||
IDxcCompiler* dxc_compiler = nullptr);
|
||||
bool TranslateAnalyzedShader(DxbcShaderTranslator& translator,
|
||||
D3D12Shader::D3D12Translation& translation,
|
||||
IDxbcConverter* dxbc_converter = nullptr,
|
||||
IDxcUtils* dxc_utils = nullptr,
|
||||
IDxcCompiler* dxc_compiler = nullptr);
|
||||
|
||||
bool GetCurrentStateDescription(
|
||||
D3D12Shader::D3D12Translation* vertex_shader,
|
||||
@@ -257,7 +252,9 @@ class PipelineCache {
|
||||
flags::DepthFloat24Conversion depth_float24_conversion_;
|
||||
uint32_t resolution_scale_;
|
||||
|
||||
// Reusable shader translator.
|
||||
// Temporary storage for AnalyzeUcode calls on the processor thread.
|
||||
StringBuffer ucode_disasm_buffer_;
|
||||
// Reusable shader translator for the processor thread.
|
||||
std::unique_ptr<DxbcShaderTranslator> shader_translator_;
|
||||
|
||||
// Command processor thread DXIL conversion/disassembly interfaces, if DXIL
|
||||
@@ -332,8 +329,7 @@ class PipelineCache {
|
||||
std::condition_variable storage_write_request_cond_;
|
||||
// Storage thread input is protected with storage_write_request_lock_, and the
|
||||
// thread is notified about its change via storage_write_request_cond_.
|
||||
std::deque<std::pair<const Shader*, reg::SQ_PROGRAM_CNTL>>
|
||||
storage_write_shader_queue_;
|
||||
std::deque<const Shader*> storage_write_shader_queue_;
|
||||
std::deque<PipelineStoredDescription> storage_write_pipeline_queue_;
|
||||
bool storage_write_flush_shaders_ = false;
|
||||
bool storage_write_flush_pipelines_ = false;
|
||||
|
||||
@@ -535,7 +535,8 @@ void RenderTargetCache::EndFrame() {
|
||||
FlushAndUnbindRenderTargets();
|
||||
}
|
||||
|
||||
bool RenderTargetCache::UpdateRenderTargets(const D3D12Shader* pixel_shader) {
|
||||
bool RenderTargetCache::UpdateRenderTargets(
|
||||
uint32_t shader_writes_color_targets) {
|
||||
// There are two kinds of render target binding updates in this implementation
|
||||
// in case something has been changed - full and partial.
|
||||
//
|
||||
@@ -635,7 +636,8 @@ bool RenderTargetCache::UpdateRenderTargets(const D3D12Shader* pixel_shader) {
|
||||
uint32_t edram_bases[5];
|
||||
uint32_t formats[5];
|
||||
bool formats_are_64bpp[5];
|
||||
uint32_t color_mask = command_processor_.GetCurrentColorMask(pixel_shader);
|
||||
uint32_t color_mask =
|
||||
command_processor_.GetCurrentColorMask(shader_writes_color_targets);
|
||||
for (uint32_t i = 0; i < 4; ++i) {
|
||||
enabled[i] = (color_mask & (0xF << (i * 4))) != 0;
|
||||
auto color_info = regs.Get<reg::RB_COLOR_INFO>(
|
||||
|
||||
@@ -269,7 +269,7 @@ class RenderTargetCache {
|
||||
void EndFrame();
|
||||
// Called in the beginning of a draw call - may bind pipelines and change the
|
||||
// view descriptor heap.
|
||||
bool UpdateRenderTargets(const D3D12Shader* pixel_shader);
|
||||
bool UpdateRenderTargets(uint32_t shader_writes_color_targets);
|
||||
// Returns the host-to-guest mappings and host formats of currently bound
|
||||
// render targets for pipeline creation and remapping in shaders. They are
|
||||
// consecutive, and format DXGI_FORMAT_UNKNOWN terminates the list. Depth
|
||||
|
||||
@@ -1334,8 +1334,8 @@ void TextureCache::RequestTextures(uint32_t used_texture_mask) {
|
||||
bool TextureCache::AreActiveTextureSRVKeysUpToDate(
|
||||
const TextureSRVKey* keys,
|
||||
const D3D12Shader::TextureBinding* host_shader_bindings,
|
||||
uint32_t host_shader_binding_count) const {
|
||||
for (uint32_t i = 0; i < host_shader_binding_count; ++i) {
|
||||
size_t host_shader_binding_count) const {
|
||||
for (size_t i = 0; i < host_shader_binding_count; ++i) {
|
||||
const TextureSRVKey& key = keys[i];
|
||||
const TextureBinding& binding =
|
||||
texture_bindings_[host_shader_bindings[i].fetch_constant];
|
||||
@@ -1350,8 +1350,8 @@ bool TextureCache::AreActiveTextureSRVKeysUpToDate(
|
||||
void TextureCache::WriteActiveTextureSRVKeys(
|
||||
TextureSRVKey* keys,
|
||||
const D3D12Shader::TextureBinding* host_shader_bindings,
|
||||
uint32_t host_shader_binding_count) const {
|
||||
for (uint32_t i = 0; i < host_shader_binding_count; ++i) {
|
||||
size_t host_shader_binding_count) const {
|
||||
for (size_t i = 0; i < host_shader_binding_count; ++i) {
|
||||
TextureSRVKey& key = keys[i];
|
||||
const TextureBinding& binding =
|
||||
texture_bindings_[host_shader_bindings[i].fetch_constant];
|
||||
|
||||
@@ -196,14 +196,14 @@ class TextureCache {
|
||||
bool AreActiveTextureSRVKeysUpToDate(
|
||||
const TextureSRVKey* keys,
|
||||
const D3D12Shader::TextureBinding* host_shader_bindings,
|
||||
uint32_t host_shader_binding_count) const;
|
||||
size_t host_shader_binding_count) const;
|
||||
// Exports the current binding data to texture SRV keys so they can be stored
|
||||
// for checking whether subsequent draw calls can keep using the same
|
||||
// bindings. Write host_shader_binding_count keys.
|
||||
void WriteActiveTextureSRVKeys(
|
||||
TextureSRVKey* keys,
|
||||
const D3D12Shader::TextureBinding* host_shader_bindings,
|
||||
uint32_t host_shader_binding_count) const;
|
||||
size_t host_shader_binding_count) const;
|
||||
// Returns the post-swizzle signedness of a currently bound texture (must be
|
||||
// called after RequestTextures).
|
||||
uint8_t GetActiveTextureSwizzledSigns(uint32_t index) const {
|
||||
|
||||
Reference in New Issue
Block a user