vulkan: Align vertex strides according to portability subset requirements. (#11)

This commit is contained in:
Steven
2023-01-02 14:36:06 -08:00
committed by GitHub
parent 8779cb7785
commit e46a88f24a
5 changed files with 41 additions and 11 deletions

View File

@ -180,7 +180,8 @@ void RasterizerAccelerated::ClearAll(bool flush) {
cached_pages = {}; cached_pages = {};
} }
RasterizerAccelerated::VertexArrayInfo RasterizerAccelerated::AnalyzeVertexArray(bool is_indexed) { RasterizerAccelerated::VertexArrayInfo RasterizerAccelerated::AnalyzeVertexArray(
bool is_indexed, u32 stride_alignment) {
const auto& regs = Pica::g_state.regs; const auto& regs = Pica::g_state.regs;
const auto& vertex_attributes = regs.pipeline.vertex_attributes; const auto& vertex_attributes = regs.pipeline.vertex_attributes;
@ -211,7 +212,9 @@ RasterizerAccelerated::VertexArrayInfo RasterizerAccelerated::AnalyzeVertexArray
u32 vs_input_size = 0; u32 vs_input_size = 0;
for (const auto& loader : vertex_attributes.attribute_loaders) { for (const auto& loader : vertex_attributes.attribute_loaders) {
if (loader.component_count != 0) { if (loader.component_count != 0) {
vs_input_size += Common::AlignUp(loader.byte_count * vertex_num, 4); const u32 aligned_stride =
Common::AlignUp(static_cast<u32>(loader.byte_count), stride_alignment);
vs_input_size += Common::AlignUp(aligned_stride * vertex_num, 4);
} }
} }

View File

@ -122,7 +122,7 @@ protected:
}; };
/// Retrieve the range and the size of the input vertex /// Retrieve the range and the size of the input vertex
VertexArrayInfo AnalyzeVertexArray(bool is_indexed); VertexArrayInfo AnalyzeVertexArray(bool is_indexed, u32 stride_alignment = 1);
protected: protected:
std::array<u16, 0x30000> cached_pages{}; std::array<u16, 0x30000> cached_pages{};

View File

@ -492,12 +492,19 @@ bool Instance::CreateDevice() {
} }
#if __APPLE__ #if __APPLE__
const vk::StructureChain portability_chain = const vk::StructureChain portability_features_chain =
physical_device.getFeatures2<vk::PhysicalDeviceFeatures2, physical_device.getFeatures2<vk::PhysicalDeviceFeatures2,
vk::PhysicalDevicePortabilitySubsetFeaturesKHR>(); vk::PhysicalDevicePortabilitySubsetFeaturesKHR>();
const vk::PhysicalDevicePortabilitySubsetFeaturesKHR portability_features = const vk::PhysicalDevicePortabilitySubsetFeaturesKHR portability_features =
portability_chain.get<vk::PhysicalDevicePortabilitySubsetFeaturesKHR>(); portability_features_chain.get<vk::PhysicalDevicePortabilitySubsetFeaturesKHR>();
triangle_fan_supported = portability_features.triangleFans; triangle_fan_supported = portability_features.triangleFans;
const vk::StructureChain portability_properties_chain =
physical_device.getProperties2<vk::PhysicalDeviceProperties2,
vk::PhysicalDevicePortabilitySubsetPropertiesKHR>();
const vk::PhysicalDevicePortabilitySubsetPropertiesKHR portability_properties =
portability_properties_chain.get<vk::PhysicalDevicePortabilitySubsetPropertiesKHR>();
min_vertex_stride_alignment = portability_properties.minVertexInputBindingStrideAlignment;
#endif #endif
try { try {

View File

@ -195,6 +195,11 @@ public:
return triangle_fan_supported; return triangle_fan_supported;
} }
/// Returns the minimum vertex stride alignment
u32 GetMinVertexStrideAlignment() const {
return min_vertex_stride_alignment;
}
private: private:
/// Returns the optimal supported usage for the requested format /// Returns the optimal supported usage for the requested format
vk::FormatFeatureFlags GetFormatFeatures(vk::Format format); vk::FormatFeatureFlags GetFormatFeatures(vk::Format format);
@ -233,6 +238,7 @@ private:
u32 graphics_queue_family_index{0}; u32 graphics_queue_family_index{0};
bool triangle_fan_supported{true}; bool triangle_fan_supported{true};
u32 min_vertex_stride_alignment{1};
bool timeline_semaphores{}; bool timeline_semaphores{};
bool extended_dynamic_state{}; bool extended_dynamic_state{};
bool push_descriptors{}; bool push_descriptors{};

View File

@ -216,6 +216,8 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
const auto& vertex_attributes = regs.pipeline.vertex_attributes; const auto& vertex_attributes = regs.pipeline.vertex_attributes;
PAddr base_address = vertex_attributes.GetPhysicalBaseAddress(); // GPUREG_ATTR_BUF_BASE PAddr base_address = vertex_attributes.GetPhysicalBaseAddress(); // GPUREG_ATTR_BUF_BASE
const u32 stride_alignment = instance.GetMinVertexStrideAlignment();
VertexLayout& layout = pipeline_info.vertex_layout; VertexLayout& layout = pipeline_info.vertex_layout;
layout.attribute_count = 0; layout.attribute_count = 0;
layout.binding_count = 0; layout.binding_count = 0;
@ -262,20 +264,32 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
base_address + loader.data_offset + (vs_input_index_min * loader.byte_count); base_address + loader.data_offset + (vs_input_index_min * loader.byte_count);
const u32 vertex_num = vs_input_index_max - vs_input_index_min + 1; const u32 vertex_num = vs_input_index_max - vs_input_index_min + 1;
const u32 data_size = loader.byte_count * vertex_num; const u32 data_size = loader.byte_count * vertex_num;
res_cache.FlushRegion(data_addr, data_size); res_cache.FlushRegion(data_addr, data_size);
std::memcpy(array_ptr + buffer_offset, VideoCore::g_memory->GetPhysicalPointer(data_addr),
data_size); const u8* src_ptr = VideoCore::g_memory->GetPhysicalPointer(data_addr);
u8* dst_ptr = array_ptr + buffer_offset;
// Align stride up if required by Vulkan implementation.
const u32 aligned_stride =
Common::AlignUp(static_cast<u32>(loader.byte_count), stride_alignment);
if (aligned_stride == loader.byte_count) {
std::memcpy(dst_ptr, src_ptr, data_size);
} else {
for (size_t vertex = 0; vertex < vertex_num; vertex++) {
std::memcpy(dst_ptr + vertex * aligned_stride, src_ptr + vertex * loader.byte_count,
loader.byte_count);
}
}
// Create the binding associated with this loader // Create the binding associated with this loader
VertexBinding& binding = layout.bindings[layout.binding_count]; VertexBinding& binding = layout.bindings[layout.binding_count];
binding.binding.Assign(layout.binding_count); binding.binding.Assign(layout.binding_count);
binding.fixed.Assign(0); binding.fixed.Assign(0);
binding.stride.Assign(loader.byte_count); binding.stride.Assign(aligned_stride);
// Keep track of the binding offsets so we can bind the vertex buffer later // Keep track of the binding offsets so we can bind the vertex buffer later
binding_offsets[layout.binding_count++] = array_offset + buffer_offset; binding_offsets[layout.binding_count++] = array_offset + buffer_offset;
buffer_offset += Common::AlignUp(data_size, 4); buffer_offset += Common::AlignUp(aligned_stride * vertex_num, 4);
} }
binding_offsets[layout.binding_count] = array_offset + buffer_offset; binding_offsets[layout.binding_count] = array_offset + buffer_offset;
@ -392,7 +406,7 @@ bool RasterizerVulkan::AccelerateDrawBatchInternal(bool is_indexed) {
const auto& regs = Pica::g_state.regs; const auto& regs = Pica::g_state.regs;
const auto [vs_input_index_min, vs_input_index_max, vs_input_size] = const auto [vs_input_index_min, vs_input_index_max, vs_input_size] =
AnalyzeVertexArray(is_indexed); AnalyzeVertexArray(is_indexed, instance.GetMinVertexStrideAlignment());
if (regs.pipeline.triangle_topology == TriangleTopology::Fan && if (regs.pipeline.triangle_topology == TriangleTopology::Fan &&
!instance.IsTriangleFanSupported()) { !instance.IsTriangleFanSupported()) {