mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-12-10 13:48:40 +00:00
renderer_vulkan: Simplify vertex binding logic and properly handle null buffers. (#2104)
* renderer_vulkan: Simplify vertex binding logic and properly handle null buffers. * renderer_vulkan: Remove need for empty bindVertexBuffers2EXT.
This commit is contained in:
@@ -57,35 +57,11 @@ GraphicsPipeline::GraphicsPipeline(
|
||||
pipeline_layout = std::move(layout);
|
||||
SetObjectName(device, *pipeline_layout, "Graphics PipelineLayout {}", debug_str);
|
||||
|
||||
boost::container::static_vector<vk::VertexInputBindingDescription, 32> vertex_bindings;
|
||||
boost::container::static_vector<vk::VertexInputAttributeDescription, 32> vertex_attributes;
|
||||
if (fetch_shader && !instance.IsVertexInputDynamicState()) {
|
||||
const auto& vs_info = GetStage(Shader::LogicalStage::Vertex);
|
||||
for (const auto& attrib : fetch_shader->attributes) {
|
||||
if (attrib.UsesStepRates()) {
|
||||
// Skip attribute binding as the data will be pulled by shader
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto buffer = attrib.GetSharp(vs_info);
|
||||
if (buffer.GetSize() == 0) {
|
||||
continue;
|
||||
}
|
||||
vertex_attributes.push_back({
|
||||
.location = attrib.semantic,
|
||||
.binding = attrib.semantic,
|
||||
.format = LiverpoolToVK::SurfaceFormat(buffer.GetDataFmt(), buffer.GetNumberFmt()),
|
||||
.offset = 0,
|
||||
});
|
||||
vertex_bindings.push_back({
|
||||
.binding = attrib.semantic,
|
||||
.stride = buffer.GetStride(),
|
||||
.inputRate =
|
||||
attrib.GetStepRate() == Shader::Gcn::VertexAttribute::InstanceIdType::None
|
||||
? vk::VertexInputRate::eVertex
|
||||
: vk::VertexInputRate::eInstance,
|
||||
});
|
||||
}
|
||||
VertexInputs<vk::VertexInputAttributeDescription> vertex_attributes;
|
||||
VertexInputs<vk::VertexInputBindingDescription> vertex_bindings;
|
||||
VertexInputs<AmdGpu::Buffer> guest_buffers;
|
||||
if (!instance.IsVertexInputDynamicState()) {
|
||||
GetVertexInputs(vertex_attributes, vertex_bindings, guest_buffers);
|
||||
}
|
||||
|
||||
const vk::PipelineVertexInputStateCreateInfo vertex_input_info = {
|
||||
@@ -161,7 +137,7 @@ GraphicsPipeline::GraphicsPipeline(
|
||||
}
|
||||
if (instance.IsVertexInputDynamicState()) {
|
||||
dynamic_states.push_back(vk::DynamicState::eVertexInputEXT);
|
||||
} else {
|
||||
} else if (!vertex_bindings.empty()) {
|
||||
dynamic_states.push_back(vk::DynamicState::eVertexInputBindingStrideEXT);
|
||||
}
|
||||
|
||||
@@ -329,6 +305,51 @@ GraphicsPipeline::GraphicsPipeline(
|
||||
|
||||
GraphicsPipeline::~GraphicsPipeline() = default;
|
||||
|
||||
template <typename Attribute, typename Binding>
|
||||
void GraphicsPipeline::GetVertexInputs(VertexInputs<Attribute>& attributes,
|
||||
VertexInputs<Binding>& bindings,
|
||||
VertexInputs<AmdGpu::Buffer>& guest_buffers) const {
|
||||
if (!fetch_shader || fetch_shader->attributes.empty()) {
|
||||
return;
|
||||
}
|
||||
const auto& vs_info = GetStage(Shader::LogicalStage::Vertex);
|
||||
for (const auto& attrib : fetch_shader->attributes) {
|
||||
if (attrib.UsesStepRates()) {
|
||||
// Skip attribute binding as the data will be pulled by shader.
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& buffer = attrib.GetSharp(vs_info);
|
||||
attributes.push_back(Attribute{
|
||||
.location = attrib.semantic,
|
||||
.binding = attrib.semantic,
|
||||
.format = LiverpoolToVK::SurfaceFormat(buffer.GetDataFmt(), buffer.GetNumberFmt()),
|
||||
.offset = 0,
|
||||
});
|
||||
bindings.push_back(Binding{
|
||||
.binding = attrib.semantic,
|
||||
.stride = buffer.GetStride(),
|
||||
.inputRate = attrib.GetStepRate() == Shader::Gcn::VertexAttribute::InstanceIdType::None
|
||||
? vk::VertexInputRate::eVertex
|
||||
: vk::VertexInputRate::eInstance,
|
||||
});
|
||||
if constexpr (std::is_same_v<Attribute, vk::VertexInputBindingDescription2EXT>) {
|
||||
bindings.back().divisor = 1;
|
||||
}
|
||||
guest_buffers.emplace_back(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
// Declare templated GetVertexInputs for necessary types.
|
||||
template void GraphicsPipeline::GetVertexInputs(
|
||||
VertexInputs<vk::VertexInputAttributeDescription>& attributes,
|
||||
VertexInputs<vk::VertexInputBindingDescription>& bindings,
|
||||
VertexInputs<AmdGpu::Buffer>& guest_buffers) const;
|
||||
template void GraphicsPipeline::GetVertexInputs(
|
||||
VertexInputs<vk::VertexInputAttributeDescription2EXT>& attributes,
|
||||
VertexInputs<vk::VertexInputBindingDescription2EXT>& bindings,
|
||||
VertexInputs<AmdGpu::Buffer>& guest_buffers) const;
|
||||
|
||||
void GraphicsPipeline::BuildDescSetLayout() {
|
||||
boost::container::small_vector<vk::DescriptorSetLayoutBinding, 32> bindings;
|
||||
u32 binding{};
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/container/static_vector.hpp>
|
||||
#include <xxhash.h>
|
||||
|
||||
#include "common/types.h"
|
||||
@@ -27,6 +28,9 @@ class DescriptorHeap;
|
||||
|
||||
using Liverpool = AmdGpu::Liverpool;
|
||||
|
||||
template <typename T>
|
||||
using VertexInputs = boost::container::static_vector<T, MaxVertexBufferCount>;
|
||||
|
||||
struct GraphicsPipelineKey {
|
||||
std::array<size_t, MaxShaderStages> stage_hashes;
|
||||
u32 num_color_attachments;
|
||||
@@ -100,6 +104,11 @@ public:
|
||||
key.prim_type == AmdGpu::PrimitiveType::QuadList;
|
||||
}
|
||||
|
||||
/// Gets the attributes and bindings for vertex inputs.
|
||||
template <typename Attribute, typename Binding>
|
||||
void GetVertexInputs(VertexInputs<Attribute>& attributes, VertexInputs<Binding>& bindings,
|
||||
VertexInputs<AmdGpu::Buffer>& guest_buffers) const;
|
||||
|
||||
private:
|
||||
void BuildDescSetLayout();
|
||||
|
||||
|
||||
@@ -420,17 +420,17 @@ bool PipelineCache::RefreshGraphicsKey() {
|
||||
}
|
||||
}
|
||||
|
||||
const auto vs_info = infos[static_cast<u32>(Shader::LogicalStage::Vertex)];
|
||||
const auto* vs_info = infos[static_cast<u32>(Shader::LogicalStage::Vertex)];
|
||||
if (vs_info && fetch_shader && !instance.IsVertexInputDynamicState()) {
|
||||
// Without vertex input dynamic state, the pipeline needs to specialize on format.
|
||||
// Stride will still be handled outside the pipeline using dynamic state.
|
||||
u32 vertex_binding = 0;
|
||||
for (const auto& attrib : fetch_shader->attributes) {
|
||||
if (attrib.UsesStepRates()) {
|
||||
// Skip attribute binding as the data will be pulled by shader.
|
||||
continue;
|
||||
}
|
||||
const auto& buffer = attrib.GetSharp(*vs_info);
|
||||
if (buffer.GetSize() == 0) {
|
||||
continue;
|
||||
}
|
||||
ASSERT(vertex_binding < MaxVertexBufferCount);
|
||||
key.vertex_buffer_formats[vertex_binding++] =
|
||||
Vulkan::LiverpoolToVK::SurfaceFormat(buffer.GetDataFmt(), buffer.GetNumberFmt());
|
||||
|
||||
@@ -248,9 +248,7 @@ void Rasterizer::Draw(bool is_indexed, u32 index_offset) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& vs_info = pipeline->GetStage(Shader::LogicalStage::Vertex);
|
||||
const auto& fetch_shader = pipeline->GetFetchShader();
|
||||
buffer_cache.BindVertexBuffers(vs_info, fetch_shader);
|
||||
buffer_cache.BindVertexBuffers(*pipeline);
|
||||
if (is_indexed) {
|
||||
buffer_cache.BindIndexBuffer(index_offset);
|
||||
}
|
||||
@@ -258,6 +256,8 @@ void Rasterizer::Draw(bool is_indexed, u32 index_offset) {
|
||||
BeginRendering(*pipeline, state);
|
||||
UpdateDynamicState(*pipeline);
|
||||
|
||||
const auto& vs_info = pipeline->GetStage(Shader::LogicalStage::Vertex);
|
||||
const auto& fetch_shader = pipeline->GetFetchShader();
|
||||
const auto [vertex_offset, instance_offset] = GetDrawOffsets(regs, vs_info, fetch_shader);
|
||||
|
||||
const auto cmdbuf = scheduler.CommandBuffer();
|
||||
@@ -292,9 +292,7 @@ void Rasterizer::DrawIndirect(bool is_indexed, VAddr arg_address, u32 offset, u3
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& vs_info = pipeline->GetStage(Shader::LogicalStage::Vertex);
|
||||
const auto& fetch_shader = pipeline->GetFetchShader();
|
||||
buffer_cache.BindVertexBuffers(vs_info, fetch_shader);
|
||||
buffer_cache.BindVertexBuffers(*pipeline);
|
||||
if (is_indexed) {
|
||||
buffer_cache.BindIndexBuffer(0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user