From f72157bcec170ed75b72dffeb2e5636d23036ec4 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Tue, 25 Sep 2018 20:29:24 +0300 Subject: [PATCH] rsx: Fix vertex attrib parsing --- rpcs3/Emu/RSX/GL/GLGSRender.cpp | 8 +++++++ rpcs3/Emu/RSX/GL/GLVertexBuffers.cpp | 7 ++++-- rpcs3/Emu/RSX/RSXThread.cpp | 4 ---- rpcs3/Emu/RSX/RSXThread.h | 33 ++++++++++++++++++++++++++++ rpcs3/Emu/RSX/VK/VKGSRender.cpp | 7 ++++++ rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp | 7 ++++-- 6 files changed, 58 insertions(+), 8 deletions(-) diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index b07148cf7f..cfb2ce4f61 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -218,6 +218,14 @@ void GLGSRender::end() //Do vertex upload before RTT prep / texture lookups to give the driver time to push data auto upload_info = set_vertex_buffer(); + if (upload_info.vertex_draw_count == 0) + { + // Malformed vertex setup; abort + do_heap_cleanup(); + rsx::thread::end(); + return; + } + //Check if depth buffer is bound and valid //If ds is not initialized clear it; it seems new depth textures should have depth cleared auto copy_rtt_contents = [this](gl::render_target *surface, bool is_depth) diff --git a/rpcs3/Emu/RSX/GL/GLVertexBuffers.cpp b/rpcs3/Emu/RSX/GL/GLVertexBuffers.cpp index 1ed354b0a5..2175303036 100644 --- a/rpcs3/Emu/RSX/GL/GLVertexBuffers.cpp +++ b/rpcs3/Emu/RSX/GL/GLVertexBuffers.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "GLGSRender.h" #include "../rsx_methods.h" #include "../Common/BufferUtils.h" @@ -158,7 +158,7 @@ namespace vertex_input_state operator()(const rsx::draw_inlined_array& command) { - const u32 vertex_count = m_vertex_layout.interleaved_blocks[0].locations.size() ? ((u32)command.inline_vertex_array.size() * sizeof(u32)) / m_vertex_layout.interleaved_blocks[0].attribute_stride : 0; + const u32 vertex_count = (u32)(command.inline_vertex_array.size() * sizeof(u32)) / m_vertex_layout.interleaved_blocks[0].attribute_stride; if (!gl::is_primitive_native(rsx::method_registers.current_draw_clause.primitive)) { @@ -186,6 +186,9 @@ gl::vertex_upload_info GLGSRender::set_vertex_buffer() m_vertex_layout = analyse_inputs_interleaved(); + if (!m_vertex_layout.validate()) + return {}; + //Write index buffers and count verts auto result = std::visit(draw_command_visitor(*m_index_ring_buffer, m_vertex_layout), get_draw_command(rsx::method_registers)); diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 0c4b17a389..06a805514e 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -1776,10 +1776,6 @@ namespace rsx for (u8 index = 0; index < rsx::limits::vertex_count; ++index) { - // Check if vertex stream is enabled - if (!(input_mask & (1 << index))) - continue; - auto &vinfo = state.vertex_arrays_info[index]; if (vinfo.size() > 0) diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 7d0bd185a7..033e7d8113 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -204,6 +204,39 @@ namespace rsx std::vector referenced_registers; // Volatile register data std::array attribute_placement; + + vertex_input_layout() + { + attribute_placement.fill(attribute_buffer_placement::none); + } + + bool validate() const + { + switch (attribute_placement[0]) + { + case attribute_buffer_placement::transient: + { + if (!referenced_registers.empty() && referenced_registers.front() == 0) + { + // ATTR[0] is position which cannot be from a register + return false; + } + + // The source is inline array or immediate draw push buffer + return true; + } + case attribute_buffer_placement::persistent: + { + // Attribute stride cannot be 0, proper packing stride is computed elsewhere + verify(HERE), (!interleaved_blocks.empty() && interleaved_blocks[0].attribute_stride != 0); + return true; + } + case attribute_buffer_placement::none: + { + return false; + } + } + } }; struct framebuffer_layout diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 1945d83a0c..29f11eca51 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -1364,6 +1364,13 @@ void VKGSRender::end() std::chrono::time_point vertex_end = steady_clock::now(); m_vertex_upload_time += std::chrono::duration_cast(vertex_end - vertex_start).count(); + if (!upload_info.vertex_draw_count) + { + // Malformed vertex setup; abort + rsx::thread::end(); + return; + } + // Load program execution environment program_start = vertex_end; load_program_env(upload_info); diff --git a/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp b/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp index 84939ef461..1ea2f62296 100644 --- a/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp +++ b/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "Emu/Memory/vm.h" #include "Emu/System.h" #include "VKGSRender.h" @@ -212,7 +212,7 @@ namespace auto &draw_clause = rsx::method_registers.current_draw_clause; VkPrimitiveTopology prims = vk::get_appropriate_topology(draw_clause.primitive, primitives_emulated); - const u32 vertex_count = m_vertex_layout.interleaved_blocks[0].locations.size() ? ((u32)command.inline_vertex_array.size() * sizeof(u32)) / m_vertex_layout.interleaved_blocks[0].attribute_stride : 0; + const u32 vertex_count = ((u32)command.inline_vertex_array.size() * sizeof(u32)) / m_vertex_layout.interleaved_blocks[0].attribute_stride; if (!primitives_emulated) { @@ -235,6 +235,9 @@ vk::vertex_upload_info VKGSRender::upload_vertex_data() { m_vertex_layout = analyse_inputs_interleaved(); + if (!m_vertex_layout.validate()) + return {}; + draw_command_visitor visitor(m_index_buffer_ring_info, m_vertex_layout); auto result = std::visit(visitor, get_draw_command(rsx::method_registers));