[Vulkan] Non-GS point sprites + minor SPIR-V fixes
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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_);
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user