diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp index ca5145fda2..25eba295c3 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp @@ -395,7 +395,10 @@ namespace get_index_count(rsx::method_registers.current_draw_clause.primitive, ::narrow(get_vertex_count(command.ranges_to_fetch_in_index_buffer))); - rsx::index_array_type indexed_type = rsx::method_registers.index_type(); + rsx::index_array_type indexed_type = rsx::method_registers.current_draw_clause.is_immediate_draw? + rsx::index_array_type::u32: + rsx::method_registers.index_type(); + size_t index_size = get_index_type_size(indexed_type); // Alloc diff --git a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp index c736894baa..bf460b082f 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp @@ -291,7 +291,10 @@ void D3D12GSRender::load_program() if (rsx::method_registers.restart_index_enabled()) { - rsx::index_array_type index_type = rsx::method_registers.index_type(); + rsx::index_array_type index_type = rsx::method_registers.current_draw_clause.is_immediate_draw? + rsx::index_array_type::u32: + rsx::method_registers.index_type(); + if (index_type == rsx::index_array_type::u32) { prop.CutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF; diff --git a/rpcs3/Emu/RSX/GL/GLVertexBuffers.cpp b/rpcs3/Emu/RSX/GL/GLVertexBuffers.cpp index daa275d6c9..907e419b29 100644 --- a/rpcs3/Emu/RSX/GL/GLVertexBuffers.cpp +++ b/rpcs3/Emu/RSX/GL/GLVertexBuffers.cpp @@ -332,7 +332,10 @@ namespace { u32 min_index = 0, max_index = 0; - rsx::index_array_type type = rsx::method_registers.index_type(); + rsx::index_array_type type = rsx::method_registers.current_draw_clause.is_immediate_draw? + rsx::index_array_type::u32: + rsx::method_registers.index_type(); + u32 type_size = ::narrow(get_index_type_size(type)); u32 vertex_count = rsx::method_registers.current_draw_clause.get_elements_count(); diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 1fcdc4061a..ed5b3ff231 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -338,7 +338,7 @@ namespace rsx vertex_push_buffers[attribute].append_vertex_data(subreg_index, type, value); } - u32 thread::get_push_buffer_vertex_count() + u32 thread::get_push_buffer_vertex_count() const { //There's no restriction on which attrib shall hold vertex data, so we check them all u32 max_vertex_count = 0; @@ -350,6 +350,18 @@ namespace rsx return max_vertex_count; } + void thread::append_array_element(u32 index) + { + //Endianness is swapped because common upload code expects input in BE + //TODO: Implement fast upload path for LE inputs and do away with this + element_push_buffer.push_back(se_storage::swap(index)); + } + + u32 thread::get_push_buffer_index_count() const + { + return element_push_buffer.size(); + } + void thread::end() { rsx::method_registers.transform_constants.clear(); @@ -363,6 +375,8 @@ namespace rsx vertex_push_buffers[index].clear(); } + element_push_buffer.resize(0); + if (capture_current_frame) { u32 element_count = rsx::method_registers.current_draw_clause.get_elements_count(); @@ -651,6 +665,12 @@ namespace rsx gsl::span thread::get_raw_index_array(const std::vector >& draw_indexed_clause) const { + if (element_push_buffer.size()) + { + //Indices provided via immediate mode + return{(const gsl::byte*)element_push_buffer.data(), ::narrow(element_push_buffer.size() * sizeof(u32))}; + } + u32 address = rsx::get_address(rsx::method_registers.index_array_address(), rsx::method_registers.index_array_location()); rsx::index_array_type type = rsx::method_registers.index_type(); diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 8483270017..0d534a84fd 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -169,6 +169,7 @@ namespace rsx protected: std::stack m_call_stack; std::array vertex_push_buffers; + std::vector element_push_buffer; public: old_shaders_cache::shaders_cache shaders_cache; @@ -278,7 +279,10 @@ namespace rsx * Appends a value to the push buffer (currently only supports 32-wide types) */ void append_to_push_buffer(u32 attribute, u32 size, u32 subreg_index, vertex_base_type type, u32 value); - u32 get_push_buffer_vertex_count(); + u32 get_push_buffer_vertex_count() const; + + void append_array_element(u32 index); + u32 get_push_buffer_index_count() const; private: std::mutex m_mtx_task; diff --git a/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp b/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp index 969b8b4f12..6fc423c4f6 100644 --- a/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp +++ b/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp @@ -397,7 +397,10 @@ namespace VkPrimitiveTopology prims = vk::get_appropriate_topology( rsx::method_registers.current_draw_clause.primitive, primitives_emulated); - rsx::index_array_type index_type = rsx::method_registers.index_type(); + rsx::index_array_type index_type = rsx::method_registers.current_draw_clause.is_immediate_draw ? + rsx::index_array_type::u32 : + rsx::method_registers.index_type(); + u32 type_size = gsl::narrow(get_index_type_size(index_type)); u32 index_count = rsx::method_registers.current_draw_clause.get_elements_count(); diff --git a/rpcs3/Emu/RSX/gcm_enums.h b/rpcs3/Emu/RSX/gcm_enums.h index 286607e343..250d8ac33c 100644 --- a/rpcs3/Emu/RSX/gcm_enums.h +++ b/rpcs3/Emu/RSX/gcm_enums.h @@ -1000,12 +1000,11 @@ enum NV3089_IMAGE_IN_OFFSET = 0x0000C408 >> 2, NV3089_IMAGE_IN = 0x0000C40C >> 2, - GCM_FLIP_HEAD0 = 0X0000E920 >> 2, - GCM_FLIP_HEAD1 = 0X0000E924 >> 2, - GCM_PREPARE_DISPLAY_BUFFER_HEAD0 = 0X0000E940 >> 2, //0X940 + [HEAD << 2] - GCM_PREPARE_DISPLAY_BUFFER_HEAD1 = 0X0000E944 >> 2, - GCM_SET_USER_COMMAND = 0x0000EB00 >> 2, - GCM_SET_USER_COMMAND2 = 0x0000EB04 >> 2, + //lv1 hypervisor commands + GCM_SET_DRIVER_OBJECT = 0x0000E0000 >> 2, + GCM_FLIP_HEAD = 0X0000E920 >> 2, //0xE920:0xE924: Flip head 0 or 1 + GCM_DRIVER_QUEUE = 0X0000E940 >> 2, //0XE940:0xE95C: First two indices prepare display buffers, rest unknown + GCM_SET_USER_COMMAND = 0x0000EB00 >> 2, //0xEB00:0xEB04: User interrupt GCM_FLIP_COMMAND = 0x0000FEAC >> 2 }; diff --git a/rpcs3/Emu/RSX/rsx_methods.cpp b/rpcs3/Emu/RSX/rsx_methods.cpp index ba212074e8..bde77fbee6 100644 --- a/rpcs3/Emu/RSX/rsx_methods.cpp +++ b/rpcs3/Emu/RSX/rsx_methods.cpp @@ -203,6 +203,21 @@ namespace rsx } }; + void set_array_element16(thread* rsx, u32, u32 arg) + { + if (rsx->in_begin_end) + { + rsx->append_array_element(arg & 0xFFFF); + rsx->append_array_element(arg >> 16); + } + } + + void set_array_element32(thread* rsx, u32, u32 arg) + { + if (rsx->in_begin_end) + rsx->append_array_element(arg); + } + void draw_arrays(thread* rsx, u32 _reg, u32 arg) { rsx::method_registers.current_draw_clause.command = rsx::draw_command::array; @@ -262,12 +277,27 @@ namespace rsx } //Check if we have immediate mode vertex data in a driver-local buffer - const u32 push_buffer_vertices_count = rsxthr->get_push_buffer_vertex_count(); - if (rsx::method_registers.current_draw_clause.command == rsx::draw_command::none && push_buffer_vertices_count) + if (rsx::method_registers.current_draw_clause.command == rsx::draw_command::none) { - rsx::method_registers.current_draw_clause.command = rsx::draw_command::array; - rsx::method_registers.current_draw_clause.first_count_commands.push_back(std::make_pair(0, push_buffer_vertices_count)); + const u32 push_buffer_vertices_count = rsxthr->get_push_buffer_vertex_count(); + const u32 push_buffer_index_count = rsxthr->get_push_buffer_index_count(); + + //Need to set this flag since it overrides some register contents + rsx::method_registers.current_draw_clause.is_immediate_draw = true; + + if (push_buffer_index_count) + { + rsx::method_registers.current_draw_clause.command = rsx::draw_command::indexed; + rsx::method_registers.current_draw_clause.first_count_commands.push_back(std::make_pair(0, push_buffer_index_count)); + } + else if (push_buffer_vertices_count) + { + rsx::method_registers.current_draw_clause.command = rsx::draw_command::array; + rsx::method_registers.current_draw_clause.first_count_commands.push_back(std::make_pair(0, push_buffer_vertices_count)); + } } + else + rsx::method_registers.current_draw_clause.is_immediate_draw = false; if (!(rsx::method_registers.current_draw_clause.first_count_commands.empty() && rsx::method_registers.current_draw_clause.inline_vertex_array.empty())) @@ -1245,8 +1275,10 @@ namespace rsx methods[NV3089_IMAGE_IN] = nullptr; //Some custom GCM methods - methods[GCM_PREPARE_DISPLAY_BUFFER_HEAD0] = nullptr; - methods[GCM_PREPARE_DISPLAY_BUFFER_HEAD1] = nullptr; + methods[GCM_SET_DRIVER_OBJECT] = nullptr; + + bind_array(); + bind_array(); bind_array(); bind_array(); @@ -1290,6 +1322,8 @@ namespace rsx bind(); bind(); bind(); + bind(); + bind(); bind_range(); bind_range(); bind_range(); @@ -1338,10 +1372,7 @@ namespace rsx // custom methods bind(); - bind(); - bind(); - bind(); - bind(); + bind_array(); return true; }(); diff --git a/rpcs3/Emu/RSX/rsx_methods.h b/rpcs3/Emu/RSX/rsx_methods.h index 6e4ee4f656..e94abc8bbb 100644 --- a/rpcs3/Emu/RSX/rsx_methods.h +++ b/rpcs3/Emu/RSX/rsx_methods.h @@ -28,6 +28,8 @@ namespace rsx primitive_type primitive; draw_command command; + bool is_immediate_draw; + std::vector inline_vertex_array; /** diff --git a/rpcs3/Emu/RSX/rsx_vertex_data.h b/rpcs3/Emu/RSX/rsx_vertex_data.h index 98db60f044..14141a430c 100644 --- a/rpcs3/Emu/RSX/rsx_vertex_data.h +++ b/rpcs3/Emu/RSX/rsx_vertex_data.h @@ -110,6 +110,8 @@ struct push_buffer_vertex_info void* dst = data.data() + ((vertex_count - 1) * vertex_size) + sub_index; + //NOTE: Endianness on wide types is converted to BE here because unified upload code assumes input in BE + //TODO: Implement fast LE source inputs and remove the byteswap switch (type) { case vertex_base_type::f: