vk_rasterizer: Move vertex array setup to AccelerateDrawBatch

* Avoids state invalidating due to scheduler flushes
This commit is contained in:
GPUCode
2023-02-06 21:34:24 +02:00
parent f8b853d001
commit 84ccb45c5c
4 changed files with 37 additions and 32 deletions

View File

@ -143,6 +143,7 @@ protected:
Memory::MemorySystem& memory; Memory::MemorySystem& memory;
Pica::Regs& regs; Pica::Regs& regs;
VertexArrayInfo vertex_info;
std::vector<HardwareVertex> vertex_batch; std::vector<HardwareVertex> vertex_batch;
bool shader_dirty = true; bool shader_dirty = true;

View File

@ -955,8 +955,8 @@ void RendererVulkan::DrawScreens(Frame* frame, const Layout::FramebufferLayout&
const vk::ImageMemoryBarrier render_barrier = { const vk::ImageMemoryBarrier render_barrier = {
.srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite, .srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite,
.dstAccessMask = vk::AccessFlagBits::eTransferRead, .dstAccessMask = vk::AccessFlagBits::eTransferRead,
.oldLayout = vk::ImageLayout::eGeneral, .oldLayout = vk::ImageLayout::eTransferSrcOptimal,
.newLayout = vk::ImageLayout::eGeneral, .newLayout = vk::ImageLayout::eTransferSrcOptimal,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image, .image = image,

View File

@ -52,6 +52,8 @@ constexpr vk::ImageUsageFlags NULL_STORAGE_USAGE = NULL_USAGE | vk::ImageUsageFl
struct DrawParams { struct DrawParams {
u32 vertex_count; u32 vertex_count;
s32 vertex_offset; s32 vertex_offset;
u32 binding_count;
std::array<u32, 16> bindings;
bool is_indexed; bool is_indexed;
}; };
@ -175,8 +177,8 @@ void RasterizerVulkan::SyncFixedState() {
SyncDepthWriteMask(); SyncDepthWriteMask();
} }
void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_min, void RasterizerVulkan::SetupVertexArray() {
u32 vs_input_index_max) { const auto [vs_input_index_min, vs_input_index_max, vs_input_size] = vertex_info;
auto [array_ptr, array_offset, invalidate] = stream_buffer.Map(vs_input_size, 16); auto [array_ptr, array_offset, invalidate] = stream_buffer.Map(vs_input_size, 16);
/** /**
@ -270,12 +272,6 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
// Assign the rest of the attributes to the last binding // Assign the rest of the attributes to the last binding
SetupFixedAttribs(); SetupFixedAttribs();
// Bind the generated bindings
scheduler.Record([this, binding_count = layout.binding_count,
vertex_offsets = binding_offsets](vk::CommandBuffer cmdbuf) {
cmdbuf.bindVertexBuffers(0, binding_count, vertex_buffers.data(), vertex_offsets.data());
});
} }
void RasterizerVulkan::SetupFixedAttribs() { void RasterizerVulkan::SetupFixedAttribs() {
@ -366,13 +362,7 @@ bool RasterizerVulkan::AccelerateDrawBatch(bool is_indexed) {
} }
} }
return Draw(true, is_indexed); pipeline_info.rasterization.topology.Assign(regs.pipeline.triangle_topology);
}
bool RasterizerVulkan::AccelerateDrawBatchInternal(bool is_indexed) {
const auto [vs_input_index_min, vs_input_index_max, vs_input_size] =
AnalyzeVertexArray(is_indexed, instance.GetMinVertexStrideAlignment());
if (regs.pipeline.triangle_topology == TriangleTopology::Fan && if (regs.pipeline.triangle_topology == TriangleTopology::Fan &&
!instance.IsTriangleFanSupported()) { !instance.IsTriangleFanSupported()) {
LOG_DEBUG(Render_Vulkan, LOG_DEBUG(Render_Vulkan,
@ -380,31 +370,43 @@ bool RasterizerVulkan::AccelerateDrawBatchInternal(bool is_indexed) {
return false; return false;
} }
SetupVertexArray(vs_input_size, vs_input_index_min, vs_input_index_max); // Vertex data analysis and setup might involve rasterizer cache memory flushes
if (is_indexed) { // so perform it early to avoid invalidating our state in the middle of the draw
SetupIndexArray(); vertex_info = AnalyzeVertexArray(is_indexed, instance.GetMinVertexStrideAlignment());
} SetupVertexArray();
if (!SetupVertexShader()) { if (!SetupVertexShader()) {
return false; return false;
} }
if (!SetupGeometryShader()) { if (!SetupGeometryShader()) {
return false; return false;
} }
pipeline_info.rasterization.topology.Assign(regs.pipeline.triangle_topology); return Draw(true, is_indexed);
}
bool RasterizerVulkan::AccelerateDrawBatchInternal(bool is_indexed) {
if (is_indexed) {
SetupIndexArray();
}
if (!pipeline_cache.BindPipeline(pipeline_info, !async_shaders)) { if (!pipeline_cache.BindPipeline(pipeline_info, !async_shaders)) {
return true; ///< Skip draw call when pipeline is not ready return true; // Skip draw call when pipeline is not ready
} }
const DrawParams params = { const DrawParams params = {
.vertex_count = regs.pipeline.num_vertices, .vertex_count = regs.pipeline.num_vertices,
.vertex_offset = -static_cast<s32>(vs_input_index_min), .vertex_offset = -static_cast<s32>(vertex_info.vs_input_index_min),
.binding_count = pipeline_info.vertex_layout.binding_count,
.bindings = binding_offsets,
.is_indexed = is_indexed, .is_indexed = is_indexed,
}; };
scheduler.Record([params](vk::CommandBuffer cmdbuf) { scheduler.Record([this, params](vk::CommandBuffer cmdbuf) {
std::array<u64, 16> offsets;
std::copy(params.bindings.begin(), params.bindings.end(), offsets.begin());
cmdbuf.bindVertexBuffers(0, params.binding_count, vertex_buffers.data(), offsets.data());
if (params.is_indexed) { if (params.is_indexed) {
cmdbuf.drawIndexed(params.vertex_count, 1, 0, params.vertex_offset, 0); cmdbuf.drawIndexed(params.vertex_count, 1, 0, params.vertex_offset, 0);
} else { } else {
@ -448,6 +450,12 @@ void RasterizerVulkan::DrawTriangles() {
return; return;
} }
pipeline_info.rasterization.topology.Assign(Pica::PipelineRegs::TriangleTopology::List);
pipeline_info.vertex_layout = software_layout;
pipeline_cache.UseTrivialVertexShader();
pipeline_cache.UseTrivialGeometryShader();
Draw(false, false); Draw(false, false);
} }
@ -706,10 +714,6 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
if (accelerate) { if (accelerate) {
succeeded = AccelerateDrawBatchInternal(is_indexed); succeeded = AccelerateDrawBatchInternal(is_indexed);
} else { } else {
pipeline_info.rasterization.topology.Assign(Pica::PipelineRegs::TriangleTopology::List);
pipeline_info.vertex_layout = software_layout;
pipeline_cache.UseTrivialVertexShader();
pipeline_cache.UseTrivialGeometryShader();
pipeline_cache.BindPipeline(pipeline_info, true); pipeline_cache.BindPipeline(pipeline_info, true);
const u32 max_vertices = STREAM_BUFFER_SIZE / sizeof(HardwareVertex); const u32 max_vertices = STREAM_BUFFER_SIZE / sizeof(HardwareVertex);

View File

@ -135,7 +135,7 @@ private:
void SetupIndexArray(); void SetupIndexArray();
/// Setup vertex array for AccelerateDrawBatch /// Setup vertex array for AccelerateDrawBatch
void SetupVertexArray(u32 vs_input_size, u32 vs_input_index_min, u32 vs_input_index_max); void SetupVertexArray();
/// Setup the fixed attribute emulation in vulkan /// Setup the fixed attribute emulation in vulkan
void SetupFixedAttribs(); void SetupFixedAttribs();
@ -162,7 +162,7 @@ private:
PipelineCache pipeline_cache; PipelineCache pipeline_cache;
VertexLayout software_layout; VertexLayout software_layout;
std::array<u64, 16> binding_offsets{}; std::array<u32, 16> binding_offsets{};
std::array<bool, 16> enable_attributes{}; std::array<bool, 16> enable_attributes{};
std::array<vk::Buffer, 16> vertex_buffers; std::array<vk::Buffer, 16> vertex_buffers;
vk::Sampler default_sampler; vk::Sampler default_sampler;