[Vulkan] Non-GS point sprites + minor SPIR-V fixes

This commit is contained in:
Triang3l
2022-07-27 17:14:28 +03:00
parent ff7ef05063
commit 7595cdb52b
14 changed files with 721 additions and 274 deletions

View File

@@ -2171,7 +2171,9 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
// TODO(Triang3l): Tessellation, geometry-type-specific vertex shader,
// vertex shader as compute.
if (primitive_processing_result.host_vertex_shader_type !=
Shader::HostVertexShaderType::kVertex) {
Shader::HostVertexShaderType::kVertex &&
primitive_processing_result.host_vertex_shader_type !=
Shader::HostVertexShaderType::kPointListAsTriangleStrip) {
return false;
}
@@ -2179,7 +2181,7 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
vertex_shader_modification =
pipeline_cache_->GetCurrentVertexShaderModification(
*vertex_shader, primitive_processing_result.host_vertex_shader_type,
interpolator_mask);
interpolator_mask, ps_param_gen_pos != UINT32_MAX);
pixel_shader_modification =
pixel_shader ? pipeline_cache_->GetCurrentPixelShaderModification(
*pixel_shader, interpolator_mask, ps_param_gen_pos)
@@ -2348,6 +2350,7 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
}
const ui::vulkan::VulkanProvider& provider = GetVulkanProvider();
const VkPhysicalDeviceFeatures& device_features = provider.device_features();
const VkPhysicalDeviceLimits& device_limits =
provider.device_properties().limits;
@@ -2382,11 +2385,23 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
UpdateDynamicState(viewport_info, primitive_polygonal,
normalized_depth_control);
auto vgt_draw_initiator = regs.Get<reg::VGT_DRAW_INITIATOR>();
// Whether to load the guest 32-bit (usually big-endian) vertex index
// indirectly in the vertex shader if full 32-bit indices are not supported by
// the host.
bool shader_32bit_index_dma =
!device_features.fullDrawIndexUint32 &&
primitive_processing_result.index_buffer_type ==
PrimitiveProcessor::ProcessedIndexBufferType::kGuestDMA &&
vgt_draw_initiator.index_size == xenos::IndexFormat::kInt32 &&
primitive_processing_result.host_vertex_shader_type ==
Shader::HostVertexShaderType::kVertex;
// Update system constants before uploading them.
bool vertex_shader_index_load;
UpdateSystemConstantValues(primitive_polygonal, primitive_processing_result,
viewport_info, used_texture_mask,
vertex_shader_index_load);
shader_32bit_index_dma, viewport_info,
used_texture_mask);
// Update uniform buffers and descriptor sets after binding the pipeline with
// the new layout.
@@ -2453,13 +2468,13 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
// Draw.
if (primitive_processing_result.index_buffer_type ==
PrimitiveProcessor::ProcessedIndexBufferType::kNone ||
vertex_shader_index_load) {
shader_32bit_index_dma) {
deferred_command_buffer_.CmdVkDraw(
primitive_processing_result.host_draw_vertex_count, 1, 0, 0);
} else {
std::pair<VkBuffer, VkDeviceSize> index_buffer;
switch (primitive_processing_result.index_buffer_type) {
case PrimitiveProcessor::ProcessedIndexBufferType::kGuest:
case PrimitiveProcessor::ProcessedIndexBufferType::kGuestDMA:
index_buffer.first = shared_memory_->buffer();
index_buffer.second = primitive_processing_result.guest_index_base;
break;
@@ -2467,7 +2482,8 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
index_buffer = primitive_processor_->GetConvertedIndexBuffer(
primitive_processing_result.host_index_buffer_handle);
break;
case PrimitiveProcessor::ProcessedIndexBufferType::kHostBuiltin:
case PrimitiveProcessor::ProcessedIndexBufferType::kHostBuiltinForAuto:
case PrimitiveProcessor::ProcessedIndexBufferType::kHostBuiltinForDMA:
index_buffer = primitive_processor_->GetBuiltinIndexBuffer(
primitive_processing_result.host_index_buffer_handle);
break;
@@ -3342,8 +3358,8 @@ void VulkanCommandProcessor::UpdateDynamicState(
void VulkanCommandProcessor::UpdateSystemConstantValues(
bool primitive_polygonal,
const PrimitiveProcessor::ProcessingResult& primitive_processing_result,
const draw_util::ViewportInfo& viewport_info, uint32_t used_texture_mask,
bool& vertex_shader_index_load_out) {
bool shader_32bit_index_dma, const draw_util::ViewportInfo& viewport_info,
uint32_t used_texture_mask) {
#if XE_UI_VULKAN_FINE_GRAINED_DRAW_SCOPES
SCOPE_profile_cpu_f("gpu");
#endif // XE_UI_VULKAN_FINE_GRAINED_DRAW_SCOPES
@@ -3367,51 +3383,17 @@ void VulkanCommandProcessor::UpdateSystemConstantValues(
// Flags.
uint32_t flags = 0;
// Vertex index shader loading.
bool vertex_shader_index_load = false;
// Only for ProcessedIndexBufferType kGuest since kHostConverted indices may
// be not loaded into the GPU memory (only read on the CPU), though
// kHostConverted must never be used for point lists and rectangle lists
// without geometry shaders anyway. For regular 32-bit index fetching without
// fullDrawIndexUint32, kHostConverted indices are already byte-swapped and
// truncated to 24 bits, so indirect fetch is not needed.
if (shader_32bit_index_dma) {
flags |= SpirvShaderTranslator::kSysFlag_VertexIndexLoad;
}
if (primitive_processing_result.index_buffer_type ==
PrimitiveProcessor::ProcessedIndexBufferType::kGuest) {
switch (primitive_processing_result.host_vertex_shader_type) {
case Shader::HostVertexShaderType::kVertex: {
// For guest (usually big-endian) 32-bit indices when they're not
// supported by the device.
if (vgt_draw_initiator.index_size == xenos::IndexFormat::kInt32) {
const ui::vulkan::VulkanProvider& provider = GetVulkanProvider();
const VkPhysicalDeviceFeatures& device_features =
provider.device_features();
if (!device_features.fullDrawIndexUint32) {
vertex_shader_index_load = true;
flags |= SpirvShaderTranslator::kSysFlag_VertexIndexLoad;
}
}
} break;
// kMemexportCompute never comes out of the PrimitiveProcessor, as
// memexport compute shaders are executed alongside their vertex
// counterparts, since they may still result in drawing.
case Shader::HostVertexShaderType::kPointListAsTriangleStrip:
case Shader::HostVertexShaderType::kRectangleListAsTriangleStrip: {
// Always loading the guest index buffer indirectly if it's used, as
// host indexing contains a part needed specifically for the host for
// the construction of the primitive - host vertices don't map 1:1 to
// guest ones.
vertex_shader_index_load = true;
flags |=
SpirvShaderTranslator::kSysFlag_ComputeOrPrimitiveVertexIndexLoad;
if (vgt_draw_initiator.index_size == xenos::IndexFormat::kInt32) {
flags |= SpirvShaderTranslator ::
kSysFlag_ComputeOrPrimitiveVertexIndexLoad32Bit;
}
} break;
default:
break;
PrimitiveProcessor::ProcessedIndexBufferType::kHostBuiltinForDMA) {
flags |= SpirvShaderTranslator::kSysFlag_ComputeOrPrimitiveVertexIndexLoad;
if (vgt_draw_initiator.index_size == xenos::IndexFormat::kInt32) {
flags |= SpirvShaderTranslator ::
kSysFlag_ComputeOrPrimitiveVertexIndexLoad32Bit;
}
}
vertex_shader_index_load_out = vertex_shader_index_load;
// W0 division control.
// http://www.x.org/docs/AMD/old/evergreen_3D_registers_v2.pdf
// 8: VTX_XY_FMT = true: the incoming XY have already been multiplied by 1/W0.
@@ -3466,9 +3448,9 @@ void VulkanCommandProcessor::UpdateSystemConstantValues(
// Index or tessellation edge factor buffer endianness.
dirty |= system_constants_.vertex_index_endian !=
primitive_processing_result.host_index_endian;
primitive_processing_result.host_shader_index_endian;
system_constants_.vertex_index_endian =
primitive_processing_result.host_index_endian;
primitive_processing_result.host_shader_index_endian;
// Vertex index offset.
dirty |= system_constants_.vertex_base_index != vgt_indx_offset;

View File

@@ -436,8 +436,8 @@ class VulkanCommandProcessor : public CommandProcessor {
void UpdateSystemConstantValues(
bool primitive_polygonal,
const PrimitiveProcessor::ProcessingResult& primitive_processing_result,
const draw_util::ViewportInfo& viewport_info, uint32_t used_texture_mask,
bool& vertex_shader_index_load_out);
bool shader_32bit_index_dma, const draw_util::ViewportInfo& viewport_info,
uint32_t used_texture_mask);
bool UpdateBindings(const VulkanShader* vertex_shader,
const VulkanShader* pixel_shader);
// Allocates a descriptor set and fills one or two VkWriteDescriptorSet

View File

@@ -118,7 +118,7 @@ VulkanShader* VulkanPipelineCache::LoadShader(xenos::ShaderType shader_type,
SpirvShaderTranslator::Modification
VulkanPipelineCache::GetCurrentVertexShaderModification(
const Shader& shader, Shader::HostVertexShaderType host_vertex_shader_type,
uint32_t interpolator_mask) const {
uint32_t interpolator_mask, bool ps_param_gen_used) const {
assert_true(shader.type() == xenos::ShaderType::kVertex);
assert_true(shader.is_ucode_analyzed());
const auto& regs = register_file_;
@@ -133,10 +133,15 @@ VulkanPipelineCache::GetCurrentVertexShaderModification(
modification.vertex.interpolator_mask = interpolator_mask;
modification.vertex.output_point_size =
uint32_t((shader.writes_point_size_edge_flag_kill_vertex() & 0b001) &&
regs.Get<reg::VGT_DRAW_INITIATOR>().prim_type ==
xenos::PrimitiveType::kPointList);
if (host_vertex_shader_type ==
Shader::HostVertexShaderType::kPointListAsTriangleStrip) {
modification.vertex.output_point_parameters = uint32_t(ps_param_gen_used);
} else {
modification.vertex.output_point_parameters =
uint32_t((shader.writes_point_size_edge_flag_kill_vertex() & 0b001) &&
regs.Get<reg::VGT_DRAW_INITIATOR>().prim_type ==
xenos::PrimitiveType::kPointList);
}
return modification;
}
@@ -828,6 +833,17 @@ bool VulkanPipelineCache::GetGeometryShaderKey(
if (geometry_shader_type == PipelineGeometryShader::kNone) {
return false;
}
// For kPointListAsTriangleStrip, output_point_parameters has a different
// meaning (the coordinates, not the size). However, the AsTriangleStrip host
// vertex shader types are needed specifically when geometry shaders are not
// supported as fallbacks.
if (vertex_shader_modification.vertex.host_vertex_shader_type ==
Shader::HostVertexShaderType::kPointListAsTriangleStrip ||
vertex_shader_modification.vertex.host_vertex_shader_type ==
Shader::HostVertexShaderType::kRectangleListAsTriangleStrip) {
assert_always();
return false;
}
GeometryShaderKey key;
key.type = geometry_shader_type;
// TODO(Triang3l): Once all needed inputs and outputs are added, uncomment the
@@ -840,7 +856,8 @@ bool VulkanPipelineCache::GetGeometryShaderKey(
/* vertex_shader_modification.vertex.user_clip_plane_cull */ 0;
key.has_vertex_kill_and =
/* vertex_shader_modification.vertex.vertex_kill_and */ 0;
key.has_point_size = vertex_shader_modification.vertex.output_point_size;
key.has_point_size =
vertex_shader_modification.vertex.output_point_parameters;
key.has_point_coordinates = pixel_shader_modification.pixel.param_gen_point;
key_out = key;
return true;

View File

@@ -71,7 +71,7 @@ class VulkanPipelineCache {
SpirvShaderTranslator::Modification GetCurrentVertexShaderModification(
const Shader& shader,
Shader::HostVertexShaderType host_vertex_shader_type,
uint32_t interpolator_mask) const;
uint32_t interpolator_mask, bool ps_param_gen_used) const;
SpirvShaderTranslator::Modification GetCurrentPixelShaderModification(
const Shader& shader, uint32_t interpolator_mask,
uint32_t param_gen_pos) const;

View File

@@ -36,7 +36,9 @@ bool VulkanPrimitiveProcessor::Initialize() {
if (!InitializeCommon(device_features.fullDrawIndexUint32,
!device_portability_subset_features ||
device_portability_subset_features->triangleFans,
false, device_features.geometryShader)) {
false, device_features.geometryShader,
device_features.geometryShader,
device_features.geometryShader)) {
Shutdown();
return false;
}
@@ -127,9 +129,9 @@ void VulkanPrimitiveProcessor::EndFrame() {
frame_index_buffers_.clear();
}
bool VulkanPrimitiveProcessor::InitializeBuiltin16BitIndexBuffer(
uint32_t index_count, std::function<void(uint16_t*)> fill_callback) {
assert_not_zero(index_count);
bool VulkanPrimitiveProcessor::InitializeBuiltinIndexBuffer(
size_t size_bytes, std::function<void(void*)> fill_callback) {
assert_not_zero(size_bytes);
assert_true(builtin_index_buffer_ == VK_NULL_HANDLE);
assert_true(builtin_index_buffer_memory_ == VK_NULL_HANDLE);
assert_true(builtin_index_buffer_upload_ == VK_NULL_HANDLE);
@@ -140,7 +142,7 @@ bool VulkanPrimitiveProcessor::InitializeBuiltin16BitIndexBuffer(
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
VkDevice device = provider.device();
builtin_index_buffer_size_ = VkDeviceSize(sizeof(uint16_t) * index_count);
builtin_index_buffer_size_ = VkDeviceSize(size_bytes);
if (!ui::vulkan::util::CreateDedicatedAllocationBuffer(
provider, builtin_index_buffer_size_,
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
@@ -148,8 +150,8 @@ bool VulkanPrimitiveProcessor::InitializeBuiltin16BitIndexBuffer(
builtin_index_buffer_memory_)) {
XELOGE(
"Vulkan primitive processor: Failed to create the built-in index "
"buffer GPU resource with {} 16-bit indices",
index_count);
"buffer GPU resource with {} bytes",
size_bytes);
return false;
}
uint32_t upload_memory_type;
@@ -161,8 +163,8 @@ bool VulkanPrimitiveProcessor::InitializeBuiltin16BitIndexBuffer(
&upload_memory_type)) {
XELOGE(
"Vulkan primitive processor: Failed to create the built-in index "
"buffer upload resource with {} 16-bit indices",
index_count);
"buffer upload resource with {} bytes",
size_bytes);
ui::vulkan::util::DestroyAndNullHandle(dfn.vkDestroyBuffer, device,
builtin_index_buffer_);
ui::vulkan::util::DestroyAndNullHandle(dfn.vkFreeMemory, device,
@@ -175,8 +177,8 @@ bool VulkanPrimitiveProcessor::InitializeBuiltin16BitIndexBuffer(
VK_WHOLE_SIZE, 0, &mapping) != VK_SUCCESS) {
XELOGE(
"Vulkan primitive processor: Failed to map the built-in index buffer "
"upload resource with {} 16-bit indices",
index_count);
"upload resource with {} bytes",
size_bytes);
ui::vulkan::util::DestroyAndNullHandle(dfn.vkDestroyBuffer, device,
builtin_index_buffer_upload_);
ui::vulkan::util::DestroyAndNullHandle(dfn.vkFreeMemory, device,
@@ -187,7 +189,7 @@ bool VulkanPrimitiveProcessor::InitializeBuiltin16BitIndexBuffer(
builtin_index_buffer_memory_);
return false;
}
fill_callback(reinterpret_cast<uint16_t*>(mapping));
fill_callback(mapping);
ui::vulkan::util::FlushMappedMemoryRange(
provider, builtin_index_buffer_memory_, upload_memory_type);
dfn.vkUnmapMemory(device, builtin_index_buffer_upload_memory_);

View File

@@ -56,9 +56,8 @@ class VulkanPrimitiveProcessor final : public PrimitiveProcessor {
}
protected:
bool InitializeBuiltin16BitIndexBuffer(
uint32_t index_count,
std::function<void(uint16_t*)> fill_callback) override;
bool InitializeBuiltinIndexBuffer(
size_t size_bytes, std::function<void(void*)> fill_callback) override;
void* RequestHostConvertedIndexBufferForCurrentFrame(
xenos::IndexFormat format, uint32_t index_count, bool coalign_for_simd,