[Vulkan] Samplers (only 1.0 core features for now)

This commit is contained in:
Triang3l
2022-06-28 22:42:18 +03:00
parent 5d9061cf99
commit 05ef7a273a
6 changed files with 550 additions and 62 deletions

View File

@@ -2174,26 +2174,6 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
}
// TODO(Triang3l): Memory export.
if (!BeginSubmission(true)) {
return false;
}
// Process primitives.
PrimitiveProcessor::ProcessingResult primitive_processing_result;
if (!primitive_processor_->Process(primitive_processing_result)) {
return false;
}
if (!primitive_processing_result.host_draw_vertex_count) {
// Nothing to draw.
return true;
}
// TODO(Triang3l): Tessellation, geometry-type-specific vertex shader, vertex
// shader as compute.
if (primitive_processing_result.host_vertex_shader_type !=
Shader::HostVertexShaderType::kVertex) {
return false;
}
reg::RB_DEPTHCONTROL normalized_depth_control =
draw_util::GetNormalizedDepthControl(regs);
uint32_t normalized_color_mask =
@@ -2201,14 +2181,132 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
regs, pixel_shader->writes_color_targets())
: 0;
// Shader modifications.
SpirvShaderTranslator::Modification vertex_shader_modification =
pipeline_cache_->GetCurrentVertexShaderModification(
*vertex_shader, primitive_processing_result.host_vertex_shader_type);
SpirvShaderTranslator::Modification pixel_shader_modification =
pixel_shader ? pipeline_cache_->GetCurrentPixelShaderModification(
*pixel_shader, normalized_color_mask)
: SpirvShaderTranslator::Modification(0);
PrimitiveProcessor::ProcessingResult primitive_processing_result;
SpirvShaderTranslator::Modification vertex_shader_modification;
SpirvShaderTranslator::Modification pixel_shader_modification;
VulkanShader::VulkanTranslation* vertex_shader_translation;
VulkanShader::VulkanTranslation* pixel_shader_translation;
// Two iterations because a submission (even the current one - in which case
// it needs to be ended, and a new one must be started) may need to be awaited
// in case of a sampler count overflow, and if that happens, all subsystem
// updates done previously must be performed again because the updates done
// before the awaiting may be referencing objects destroyed by
// CompletedSubmissionUpdated.
for (uint32_t i = 0; i < 2; ++i) {
if (!BeginSubmission(true)) {
return false;
}
// Process primitives.
if (!primitive_processor_->Process(primitive_processing_result)) {
return false;
}
if (!primitive_processing_result.host_draw_vertex_count) {
// Nothing to draw.
return true;
}
// TODO(Triang3l): Tessellation, geometry-type-specific vertex shader,
// vertex shader as compute.
if (primitive_processing_result.host_vertex_shader_type !=
Shader::HostVertexShaderType::kVertex) {
return false;
}
// Shader modifications.
vertex_shader_modification =
pipeline_cache_->GetCurrentVertexShaderModification(
*vertex_shader,
primitive_processing_result.host_vertex_shader_type);
pixel_shader_modification =
pixel_shader ? pipeline_cache_->GetCurrentPixelShaderModification(
*pixel_shader, normalized_color_mask)
: SpirvShaderTranslator::Modification(0);
// Translate the shaders now to obtain the sampler bindings.
vertex_shader_translation = static_cast<VulkanShader::VulkanTranslation*>(
vertex_shader->GetOrCreateTranslation(
vertex_shader_modification.value));
pixel_shader_translation =
pixel_shader ? static_cast<VulkanShader::VulkanTranslation*>(
pixel_shader->GetOrCreateTranslation(
pixel_shader_modification.value))
: nullptr;
if (!pipeline_cache_->EnsureShadersTranslated(vertex_shader_translation,
pixel_shader_translation)) {
return false;
}
// Obtain the samplers. Note that the bindings don't depend on the shader
// modification, so if on the second iteration of this loop it becomes
// different for some reason (like a race condition with the guest in index
// buffer processing in the primitive processor resulting in different host
// vertex shader types), the bindings will stay the same.
// TODO(Triang3l): Sampler caching and reuse for adjacent draws within one
// submission.
uint32_t samplers_overflowed_count = 0;
for (uint32_t j = 0; j < 2; ++j) {
std::vector<std::pair<VulkanTextureCache::SamplerParameters, VkSampler>>&
shader_samplers =
j ? current_samplers_pixel_ : current_samplers_vertex_;
if (!i) {
shader_samplers.clear();
}
const VulkanShader* shader = j ? pixel_shader : vertex_shader;
if (!shader) {
continue;
}
const std::vector<VulkanShader::SamplerBinding>& shader_sampler_bindings =
shader->GetSamplerBindingsAfterTranslation();
if (!i) {
shader_samplers.reserve(shader_sampler_bindings.size());
for (const VulkanShader::SamplerBinding& shader_sampler_binding :
shader_sampler_bindings) {
shader_samplers.emplace_back(
texture_cache_->GetSamplerParameters(shader_sampler_binding),
VK_NULL_HANDLE);
}
}
for (std::pair<VulkanTextureCache::SamplerParameters, VkSampler>&
shader_sampler_pair : shader_samplers) {
// UseSampler calls are needed even on the second iteration in case the
// submission was broken (and thus the last usage submission indices for
// the used samplers need to be updated) due to an overflow within one
// submission. Though sampler overflow is a very rare situation overall.
bool sampler_overflowed;
VkSampler shader_sampler = texture_cache_->UseSampler(
shader_sampler_pair.first, sampler_overflowed);
shader_sampler_pair.second = shader_sampler;
if (shader_sampler == VK_NULL_HANDLE) {
if (!sampler_overflowed || i) {
// If !sampler_overflowed, just failed to create a sampler for some
// reason.
// If i == 1, an overflow has happened twice, can't recover from it
// anymore (would enter an infinite loop otherwise if the number of
// attempts was not limited to 2). Possibly too many unique samplers
// in one draw, or failed to await submission completion.
return false;
}
++samplers_overflowed_count;
}
}
}
if (!samplers_overflowed_count) {
break;
}
assert_zero(i);
// Free space for as many samplers as how many haven't been allocated
// successfully - obtain the submission index that needs to be awaited to
// reuse `samplers_overflowed_count` slots. This must be done after all the
// UseSampler calls, not inside the loop calling UseSampler, because earlier
// UseSampler calls may "mark for deletion" some samplers that later
// UseSampler calls in the loop may actually demand.
uint64_t sampler_overflow_await_submission =
texture_cache_->GetSubmissionToAwaitOnSamplerOverflow(
samplers_overflowed_count);
assert_true(sampler_overflow_await_submission <= GetCurrentSubmission());
CheckSubmissionFenceAndDeviceLoss(sampler_overflow_await_submission);
}
// Set up the render targets - this may perform dispatches and draws.
if (!render_target_cache_->Update(is_rasterization_done,
@@ -2220,15 +2318,6 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
// Create the pipeline (for this, need the render pass from the render target
// cache), translating the shaders - doing this now to obtain the used
// textures.
VulkanShader::VulkanTranslation* vertex_shader_translation =
static_cast<VulkanShader::VulkanTranslation*>(
vertex_shader->GetOrCreateTranslation(
vertex_shader_modification.value));
VulkanShader::VulkanTranslation* pixel_shader_translation =
pixel_shader ? static_cast<VulkanShader::VulkanTranslation*>(
pixel_shader->GetOrCreateTranslation(
pixel_shader_modification.value))
: nullptr;
VkPipeline pipeline;
const VulkanPipelineCache::PipelineLayoutProvider* pipeline_layout_provider;
if (!pipeline_cache_->ConfigurePipeline(
@@ -3532,18 +3621,15 @@ bool VulkanCommandProcessor::UpdateBindings(const VulkanShader* vertex_shader,
(write_pixel_textures ? texture_count_pixel : 0));
size_t vertex_sampler_image_info_offset = descriptor_write_image_info_.size();
if (write_vertex_samplers) {
// TODO(Triang3l): Real samplers.
for (const VulkanShader::SamplerBinding& sampler_binding :
samplers_vertex) {
for (const std::pair<VulkanTextureCache::SamplerParameters, VkSampler>&
sampler_pair : current_samplers_vertex_) {
VkDescriptorImageInfo& descriptor_image_info =
descriptor_write_image_info_.emplace_back();
descriptor_image_info.sampler = provider.GetHostSampler(
ui::vulkan::VulkanProvider::HostSampler::kNearestClamp);
descriptor_image_info.sampler = sampler_pair.second;
}
}
size_t vertex_texture_image_info_offset = descriptor_write_image_info_.size();
if (write_vertex_textures) {
// TODO(Triang3l): Real textures.
for (const VulkanShader::TextureBinding& texture_binding :
textures_vertex) {
VkDescriptorImageInfo& descriptor_image_info =
@@ -3558,18 +3644,15 @@ bool VulkanCommandProcessor::UpdateBindings(const VulkanShader* vertex_shader,
}
size_t pixel_sampler_image_info_offset = descriptor_write_image_info_.size();
if (write_pixel_samplers) {
// TODO(Triang3l): Real samplers.
for (const VulkanShader::SamplerBinding& sampler_binding :
*samplers_pixel) {
for (const std::pair<VulkanTextureCache::SamplerParameters, VkSampler>&
sampler_pair : current_samplers_pixel_) {
VkDescriptorImageInfo& descriptor_image_info =
descriptor_write_image_info_.emplace_back();
descriptor_image_info.sampler = provider.GetHostSampler(
ui::vulkan::VulkanProvider::HostSampler::kNearestClamp);
descriptor_image_info.sampler = sampler_pair.second;
}
}
size_t pixel_texture_image_info_offset = descriptor_write_image_info_.size();
if (write_pixel_textures) {
// TODO(Triang3l): Real textures.
for (const VulkanShader::TextureBinding& texture_binding :
*textures_pixel) {
VkDescriptorImageInfo& descriptor_image_info =