vulkan: Align vertex strides according to portability subset requirements. (#11)
This commit is contained in:
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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{};
|
||||||
|
@ -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 {
|
||||||
|
@ -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{};
|
||||||
|
@ -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()) {
|
||||||
|
Reference in New Issue
Block a user