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 = {};
}
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& vertex_attributes = regs.pipeline.vertex_attributes;
@ -211,7 +212,9 @@ RasterizerAccelerated::VertexArrayInfo RasterizerAccelerated::AnalyzeVertexArray
u32 vs_input_size = 0;
for (const auto& loader : vertex_attributes.attribute_loaders) {
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
VertexArrayInfo AnalyzeVertexArray(bool is_indexed);
VertexArrayInfo AnalyzeVertexArray(bool is_indexed, u32 stride_alignment = 1);
protected:
std::array<u16, 0x30000> cached_pages{};

View File

@ -492,12 +492,19 @@ bool Instance::CreateDevice() {
}
#if __APPLE__
const vk::StructureChain portability_chain =
const vk::StructureChain portability_features_chain =
physical_device.getFeatures2<vk::PhysicalDeviceFeatures2,
vk::PhysicalDevicePortabilitySubsetFeaturesKHR>();
const vk::PhysicalDevicePortabilitySubsetFeaturesKHR portability_features =
portability_chain.get<vk::PhysicalDevicePortabilitySubsetFeaturesKHR>();
portability_features_chain.get<vk::PhysicalDevicePortabilitySubsetFeaturesKHR>();
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
try {

View File

@ -195,6 +195,11 @@ public:
return triangle_fan_supported;
}
/// Returns the minimum vertex stride alignment
u32 GetMinVertexStrideAlignment() const {
return min_vertex_stride_alignment;
}
private:
/// Returns the optimal supported usage for the requested format
vk::FormatFeatureFlags GetFormatFeatures(vk::Format format);
@ -233,6 +238,7 @@ private:
u32 graphics_queue_family_index{0};
bool triangle_fan_supported{true};
u32 min_vertex_stride_alignment{1};
bool timeline_semaphores{};
bool extended_dynamic_state{};
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;
PAddr base_address = vertex_attributes.GetPhysicalBaseAddress(); // GPUREG_ATTR_BUF_BASE
const u32 stride_alignment = instance.GetMinVertexStrideAlignment();
VertexLayout& layout = pipeline_info.vertex_layout;
layout.attribute_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);
const u32 vertex_num = vs_input_index_max - vs_input_index_min + 1;
const u32 data_size = loader.byte_count * vertex_num;
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
VertexBinding& binding = layout.bindings[layout.binding_count];
binding.binding.Assign(layout.binding_count);
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
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;
@ -392,7 +406,7 @@ bool RasterizerVulkan::AccelerateDrawBatchInternal(bool is_indexed) {
const auto& regs = Pica::g_state.regs;
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 &&
!instance.IsTriangleFanSupported()) {