diff --git a/rpcs3/Emu/RSX/Common/BufferUtils.cpp b/rpcs3/Emu/RSX/Common/BufferUtils.cpp index cae40ab9cc..88cce470d8 100644 --- a/rpcs3/Emu/RSX/Common/BufferUtils.cpp +++ b/rpcs3/Emu/RSX/Common/BufferUtils.cpp @@ -243,11 +243,11 @@ bool is_primitive_native(rsx::primitive_type draw_mode) { case rsx::primitive_type::points: case rsx::primitive_type::lines: - case rsx::primitive_type::line_loop: case rsx::primitive_type::line_strip: case rsx::primitive_type::triangles: case rsx::primitive_type::triangle_strip: return true; + case rsx::primitive_type::line_loop: case rsx::primitive_type::polygon: case rsx::primitive_type::triangle_fan: case rsx::primitive_type::quads: @@ -270,6 +270,8 @@ size_t get_index_count(rsx::primitive_type draw_mode, unsigned initial_index_cou switch (draw_mode) { + case rsx::primitive_type::line_loop: + return initial_index_count + 1; case rsx::primitive_type::polygon: case rsx::primitive_type::triangle_fan: return (initial_index_count - 2) * 3; @@ -297,6 +299,11 @@ void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst, unsigned short *typedDst = (unsigned short *)(dst); switch (draw_mode) { + case rsx::primitive_type::line_loop: + for (unsigned i = 0; i < count; ++i) + dst[i] = i; + dst[count] = 0; + return; case rsx::primitive_type::triangle_fan: case rsx::primitive_type::polygon: for (unsigned i = 0; i < (count - 2); i++) @@ -334,7 +341,6 @@ void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst, return; case rsx::primitive_type::points: case rsx::primitive_type::lines: - case rsx::primitive_type::line_loop: case rsx::primitive_type::line_strip: case rsx::primitive_type::triangles: case rsx::primitive_type::triangle_strip: @@ -342,111 +348,68 @@ void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst, } } -// TODO: Unify indexed and non indexed primitive expansion ? -// FIXME: these functions shouldn't access rsx::method_registers (global) -template -std::tuple write_index_array_data_to_buffer_impl(gsl::span dst, rsx::primitive_type draw_mode, const std::vector > &first_count_arguments) + +namespace { - 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(); - - u32 type_size = gsl::narrow(get_index_type_size(type)); - - - EXPECTS(rsx::method_registers.vertex_data_base_index() == 0); - - bool is_primitive_restart_enabled = rsx::method_registers.restart_index_enabled(); - u32 primitive_restart_index = rsx::method_registers.restart_index(); - - // Disjoint first_counts ranges not supported atm - for (int i = 0; i < first_count_arguments.size() - 1; i++) + /** + * Get first index and index count from a draw indexed clause. + */ + std::tuple get_first_count_from_draw_indexed_clause(const std::vector>& first_count_arguments) { - const std::tuple &range = first_count_arguments[i]; - const std::tuple &next_range = first_count_arguments[i + 1]; - EXPECTS(std::get<0>(range) + std::get<1>(range) == std::get<0>(next_range)); - } - u32 first = std::get<0>(first_count_arguments.front()); - u32 count = std::get<0>(first_count_arguments.back()) + std::get<1>(first_count_arguments.back()) - first; - auto ptr = vm::ps3::_ptr(address + first * type_size); - - switch (draw_mode) - { - case rsx::primitive_type::points: - case rsx::primitive_type::lines: - case rsx::primitive_type::line_loop: - case rsx::primitive_type::line_strip: - case rsx::primitive_type::triangles: - case rsx::primitive_type::triangle_strip: - case rsx::primitive_type::quad_strip: - return upload_untouched({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index); - case rsx::primitive_type::polygon: - case rsx::primitive_type::triangle_fan: - return expand_indexed_triangle_fan({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index); - case rsx::primitive_type::quads: - return expand_indexed_quads({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index); + u32 first = std::get<0>(first_count_arguments.front()); + u32 count = std::get<0>(first_count_arguments.back()) + std::get<1>(first_count_arguments.back()) - first; + return std::make_tuple(first, count); } - throw EXCEPTION("Unknown draw mode"); + + // TODO: Unify indexed and non indexed primitive expansion ? + template + std::tuple write_index_array_data_to_buffer_impl(gsl::span dst, + gsl::span> src, + rsx::primitive_type draw_mode, bool restart_index_enabled, u32 restart_index, const std::vector > &first_count_arguments, + std::function expands) + { + u32 first; + u32 count; + std::tie(first, count) = get_first_count_from_draw_indexed_clause(first_count_arguments); + + if (!expands(draw_mode)) return upload_untouched(src.subspan(first), dst, restart_index_enabled, restart_index); + + switch (draw_mode) + { + case rsx::primitive_type::line_loop: + { + const auto &returnvalue = upload_untouched(src.subspan(first), dst, restart_index_enabled, restart_index); + dst[count] = src[first]; + return returnvalue; + } + case rsx::primitive_type::polygon: + case rsx::primitive_type::triangle_fan: + return expand_indexed_triangle_fan(src.subspan(first), dst, restart_index_enabled, restart_index); + case rsx::primitive_type::quads: + return expand_indexed_quads(src.subspan(first), dst, restart_index_enabled, restart_index); + } + throw EXCEPTION("Don't know how to expand draw mode"); + } } -std::tuple write_index_array_data_to_buffer(gsl::span dst, rsx::index_array_type type, rsx::primitive_type draw_mode, const std::vector > &first_count_arguments) +std::tuple write_index_array_data_to_buffer(gsl::span dst, + gsl::span src, + rsx::index_array_type type, rsx::primitive_type draw_mode, bool restart_index_enabled, u32 restart_index, const std::vector > &first_count_arguments, + std::function expands) { switch (type) { case rsx::index_array_type::u16: - return write_index_array_data_to_buffer_impl(as_span_workaround(dst), draw_mode, first_count_arguments); + return write_index_array_data_to_buffer_impl(as_span_workaround(dst), + gsl::as_span>(src), draw_mode, restart_index_enabled, restart_index, first_count_arguments, expands); case rsx::index_array_type::u32: - return write_index_array_data_to_buffer_impl(as_span_workaround(dst), draw_mode, first_count_arguments); + return write_index_array_data_to_buffer_impl(as_span_workaround(dst), + gsl::as_span>(src), draw_mode, restart_index_enabled, restart_index, first_count_arguments, expands); } throw EXCEPTION("Unknown index type"); } -std::tuple write_index_array_data_to_buffer_untouched(gsl::span dst, const std::vector > &first_count_arguments) -{ - 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(); - - u32 type_size = gsl::narrow(get_index_type_size(type)); - bool is_primitive_restart_enabled = rsx::method_registers.restart_index_enabled(); - u32 primitive_restart_index = rsx::method_registers.restart_index(); - - // Disjoint first_counts ranges not supported atm - for (int i = 0; i < first_count_arguments.size() - 1; i++) - { - const std::tuple &range = first_count_arguments[i]; - const std::tuple &next_range = first_count_arguments[i + 1]; - EXPECTS(std::get<0>(range) + std::get<1>(range) == std::get<0>(next_range)); - } - u32 first = std::get<0>(first_count_arguments.front()); - u32 count = std::get<0>(first_count_arguments.back()) + std::get<1>(first_count_arguments.back()) - first; - auto ptr = vm::ps3::_ptr(address + first * type_size); - - return upload_untouched({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index); -} - -std::tuple write_index_array_data_to_buffer_untouched(gsl::span dst, const std::vector > &first_count_arguments) -{ - 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(); - - u32 type_size = gsl::narrow(get_index_type_size(type)); - bool is_primitive_restart_enabled = rsx::method_registers.restart_index_enabled(); - u16 primitive_restart_index = rsx::method_registers.restart_index(); - - // Disjoint first_counts ranges not supported atm - for (int i = 0; i < first_count_arguments.size() - 1; i++) - { - const std::tuple &range = first_count_arguments[i]; - const std::tuple &next_range = first_count_arguments[i + 1]; - EXPECTS(std::get<0>(range) + std::get<1>(range) == std::get<0>(next_range)); - } - u32 first = std::get<0>(first_count_arguments.front()); - u32 count = std::get<0>(first_count_arguments.back()) + std::get<1>(first_count_arguments.back()) - first; - auto ptr = vm::ps3::_ptr(address + first * type_size); - - return upload_untouched({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index); -} - void stream_vector(void *dst, u32 x, u32 y, u32 z, u32 w) { __m128i vector = _mm_set_epi32(w, z, y, x); diff --git a/rpcs3/Emu/RSX/Common/BufferUtils.h b/rpcs3/Emu/RSX/Common/BufferUtils.h index f8213ec27a..6c9918ba3b 100644 --- a/rpcs3/Emu/RSX/Common/BufferUtils.h +++ b/rpcs3/Emu/RSX/Common/BufferUtils.h @@ -30,16 +30,11 @@ size_t get_index_type_size(rsx::index_array_type type); /** * Write count indexes using (first, first + count) ranges. * Returns min/max index found during the process. - * The function expands index buffer for non native primitive type. + * The function expands index buffer for non native primitive type if expands(draw_mode) return true. */ -std::tuple write_index_array_data_to_buffer(gsl::span dst, rsx::index_array_type, rsx::primitive_type draw_mode, const std::vector > &first_count_arguments); - - -/** - * Doesn't expand index - */ -std::tuple write_index_array_data_to_buffer_untouched(gsl::span dst, const std::vector > &first_count_arguments); -std::tuple write_index_array_data_to_buffer_untouched(gsl::span dst, const std::vector > &first_count_arguments); +std::tuple write_index_array_data_to_buffer(gsl::span dst, gsl::span src, + rsx::index_array_type, rsx::primitive_type draw_mode, bool restart_index_enabled, u32 restart_index, const std::vector > &first_count_arguments, + std::function expands); /** * Write index data needed to emulate non indexed non native primitive mode. diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp index c53b8c0f67..2fda5b8589 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp @@ -380,7 +380,9 @@ std::tuple> D3D12GSRe u32 min_index, max_index; gsl::span dst{ reinterpret_cast(mapped_buffer), gsl::narrow(buffer_size) }; - std::tie(min_index, max_index) = write_index_array_data_to_buffer(dst, indexed_type, draw_mode, first_count_commands); + std::tie(min_index, max_index) = write_index_array_data_to_buffer(dst, get_raw_index_array(first_count_commands), + indexed_type, draw_mode, rsx::method_registers.restart_index_enabled(), rsx::method_registers.restart_index(), first_count_commands, + [](auto prim) { return !is_primitive_native(prim); }); m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); D3D12_INDEX_BUFFER_VIEW index_buffer_view = { diff --git a/rpcs3/Emu/RSX/GL/vertex_buffer.cpp b/rpcs3/Emu/RSX/GL/vertex_buffer.cpp index 22bb187490..c66dcc9c94 100644 --- a/rpcs3/Emu/RSX/GL/vertex_buffer.cpp +++ b/rpcs3/Emu/RSX/GL/vertex_buffer.cpp @@ -154,28 +154,19 @@ namespace return std::make_tuple(vertex_draw_count, mapping.second); } - std::tuple upload_index_buffer(void *ptr, rsx::index_array_type type, rsx::primitive_type draw_mode, const std::vector> first_count_commands, u32 initial_vertex_count) + std::tuple upload_index_buffer(gsl::span raw_index_buffer, void *ptr, rsx::index_array_type type, rsx::primitive_type draw_mode, const std::vector> first_count_commands, u32 initial_vertex_count) { u32 min_index, max_index, vertex_draw_count = initial_vertex_count; - if (gl::is_primitive_native(draw_mode)) - { - if (type == rsx::index_array_type::u16) - std::tie(min_index, max_index) = write_index_array_data_to_buffer_untouched(gsl::span{(u16*)ptr, vertex_draw_count}, first_count_commands); - else - std::tie(min_index, max_index) = write_index_array_data_to_buffer_untouched(gsl::span{(u32*)ptr, vertex_draw_count}, first_count_commands); + vertex_draw_count = (u32)get_index_count(draw_mode, gsl::narrow(vertex_draw_count)); - } - else - { - vertex_draw_count = (u32)get_index_count(draw_mode, gsl::narrow(vertex_draw_count)); - - u32 type_size = gsl::narrow(get_index_type_size(type)); - u32 block_sz = vertex_draw_count * type_size; - - gsl::span dst{ reinterpret_cast(ptr), gsl::narrow(block_sz) }; - std::tie(min_index, max_index) = write_index_array_data_to_buffer(dst, type, draw_mode, first_count_commands); - } + u32 type_size = gsl::narrow(get_index_type_size(type)); + u32 block_sz = vertex_draw_count * type_size; + + gsl::span dst{ reinterpret_cast(ptr), gsl::narrow(block_sz) }; + std::tie(min_index, max_index) = write_index_array_data_to_buffer(dst, raw_index_buffer, + type, draw_mode, rsx::method_registers.restart_index_enabled(), rsx::method_registers.restart_index(), first_count_commands, + [](auto prim) { return !is_primitive_native(prim); }); return std::make_tuple(min_index, max_index, vertex_draw_count); } @@ -223,7 +214,7 @@ u32 GLGSRender::set_vertex_buffer() void *ptr = mapping.first; offset_in_index_buffer = mapping.second; - std::tie(min_index, max_index, vertex_draw_count) = upload_index_buffer(ptr, type, draw_mode, first_count_commands, vertex_draw_count); + std::tie(min_index, max_index, vertex_draw_count) = upload_index_buffer(get_raw_index_array(first_count_commands), ptr, type, draw_mode, first_count_commands, vertex_draw_count); m_index_ring_buffer.unmap(); } diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 1cecca8660..c5b4fcfb70 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -318,17 +318,9 @@ namespace rsx { draw_state.vertex_count += range.second; } - - if (draw_state.state.index_type() == rsx::index_array_type::u16) - { - draw_state.index.resize(2 * draw_state.vertex_count); - } - if (draw_state.state.index_type() == rsx::index_array_type::u32) - { - draw_state.index.resize(4 * draw_state.vertex_count); - } - gsl::span dst = { (gsl::byte*)draw_state.index.data(), gsl::narrow(draw_state.index.size()) }; - write_index_array_data_to_buffer(dst, draw_state.state.index_type(), draw_mode, first_count_commands); + auto index_raw_data_ptr = get_raw_index_array(first_count_commands); + draw_state.index.resize(index_raw_data_ptr.size_bytes()); + std::copy(index_raw_data_ptr.begin(), index_raw_data_ptr.end(), draw_state.index.begin()); } draw_state.programs = get_programs(); @@ -580,6 +572,28 @@ namespace rsx return get_system_time() * 1000; } + gsl::span thread::get_raw_index_array(const std::vector >& draw_indexed_clause) const + { + 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(); + + u32 type_size = gsl::narrow(get_index_type_size(type)); + bool is_primitive_restart_enabled = rsx::method_registers.restart_index_enabled(); + u32 primitive_restart_index = rsx::method_registers.restart_index(); + + // Disjoint first_counts ranges not supported atm + for (int i = 0; i < draw_indexed_clause.size() - 1; i++) + { + const std::tuple &range = draw_indexed_clause[i]; + const std::tuple &next_range = draw_indexed_clause[i + 1]; + EXPECTS(std::get<0>(range) + std::get<1>(range) == std::get<0>(next_range)); + } + u32 first = std::get<0>(draw_indexed_clause.front()); + u32 count = std::get<0>(draw_indexed_clause.back()) + std::get<1>(draw_indexed_clause.back()) - first; + const gsl::byte* ptr = static_cast(vm::base(address)); + return{ ptr, count * type_size }; + } + void thread::do_internal_task() { if (m_internal_tasks.empty()) diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index c137512b6c..50bef6a194 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -11,6 +11,7 @@ #include "RSXFragmentProgram.h" #include "rsx_methods.h" #include "rsx_trace.h" +#include #include "Utilities/Thread.h" #include "Utilities/Timer.h" @@ -252,6 +253,8 @@ namespace rsx virtual u64 timestamp() const; virtual bool on_access_violation(u32 address, bool is_writing) { return false; } + gsl::span get_raw_index_array(const std::vector >& draw_indexed_clause) const; + private: std::mutex m_mtx_task; diff --git a/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp b/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp index 84752f89c2..c257aeec6b 100644 --- a/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp +++ b/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp @@ -85,19 +85,6 @@ namespace vk } } - /** - * Expand line loop array to line strip array; simply loop back the last vertex to the first.. - */ - void expand_line_loop_array_to_strip(u32 vertex_draw_count, u16* indices) - { - u32 i = 0; - - for (; i < vertex_draw_count; ++i) - indices[i] = i; - - indices[i] = 0; - } - template void copy_inlined_data_to_buffer(void *src_data, void *dst_data, u32 vertex_count, rsx::vertex_base_type type, u8 src_channels, u8 dst_channels, u16 element_size, u16 stride) { @@ -206,84 +193,36 @@ namespace vk } } - u32 get_emulated_index_array_size(rsx::primitive_type type, u32 vertex_count) + VkIndexType get_index_type(rsx::index_array_type type) { switch (type) { - case rsx::primitive_type::line_loop: - return vertex_count + 1; - default: - return static_cast(get_index_count(type, vertex_count)); + case rsx::index_array_type::u32: + return VK_INDEX_TYPE_UINT32; + case rsx::index_array_type::u16: + return VK_INDEX_TYPE_UINT16; } + throw; } - std::tuple upload_index_buffer(rsx::primitive_type type, rsx::index_array_type index_type, void *dst_ptr, bool indexed_draw, u32 vertex_count, u32 index_count, std::vector> first_count_commands) + std::tuple upload_index_buffer(gsl::span raw_index_buffer, rsx::primitive_type type, rsx::index_array_type index_type, void *dst_ptr, bool indexed_draw, u32 vertex_count, u32 index_count, std::vector> first_count_commands) { bool emulated = false; get_appropriate_topology(type, emulated); - u32 min_index, max_index; - - if (!emulated) + if (indexed_draw) { - switch (index_type) - { - case rsx::index_array_type::u32: - std::tie(min_index, max_index) = write_index_array_data_to_buffer_untouched(gsl::span((u32*)dst_ptr, vertex_count), first_count_commands); - return std::make_tuple(min_index, max_index, VK_INDEX_TYPE_UINT32); - case rsx::index_array_type::u16: - std::tie(min_index, max_index) = write_index_array_data_to_buffer_untouched(gsl::span((u16*)dst_ptr, vertex_count), first_count_commands); - return std::make_tuple(min_index, max_index, VK_INDEX_TYPE_UINT16); - } + u32 min_index, max_index; + size_t index_size = (index_type == rsx::index_array_type::u32) ? 4 : 2; + std::tie(min_index, max_index) = write_index_array_data_to_buffer(gsl::span(static_cast(dst_ptr), vertex_count * index_size), raw_index_buffer, + index_type, type, rsx::method_registers.restart_index_enabled(), rsx::method_registers.restart_index(), first_count_commands, + [](auto prim) { return !is_primitive_native(prim); }); + + return std::make_tuple(min_index, max_index, get_index_type(index_type)); } - switch (type) - { - case rsx::primitive_type::line_loop: - { - if (!indexed_draw) - { - expand_line_loop_array_to_strip(vertex_count, static_cast(dst_ptr)); - return std::make_tuple(0, vertex_count-1, VK_INDEX_TYPE_UINT16); - } - - VkIndexType vk_index_type = VK_INDEX_TYPE_UINT16; - - switch (index_type) - { - case rsx::index_array_type::u32: - { - u32 *idx_ptr = static_cast(dst_ptr); - std::tie(min_index, max_index) = write_index_array_data_to_buffer_untouched(gsl::span(idx_ptr, vertex_count), first_count_commands); - idx_ptr[vertex_count] = idx_ptr[0]; - vk_index_type = VK_INDEX_TYPE_UINT32; - break; - } - case rsx::index_array_type::u16: - { - u16 *idx_ptr = static_cast(dst_ptr); - std::tie(min_index, max_index) = write_index_array_data_to_buffer_untouched(gsl::span(idx_ptr, vertex_count), first_count_commands); - idx_ptr[vertex_count] = idx_ptr[0]; - break; - } - } - - return std::make_tuple(min_index, max_index, vk_index_type); - } - default: - { - if (indexed_draw) - { - std::tie(min_index, max_index) = write_index_array_data_to_buffer(gsl::span(static_cast(dst_ptr), index_count * 2), rsx::index_array_type::u16, type, first_count_commands); - return std::make_tuple(min_index, max_index, VK_INDEX_TYPE_UINT16); - } - else - { - write_index_array_for_non_indexed_non_native_primitive_to_buffer(reinterpret_cast(dst_ptr), type, 0, vertex_count); - return std::make_tuple(0, vertex_count-1, VK_INDEX_TYPE_UINT16); - } - } - } + write_index_array_for_non_indexed_non_native_primitive_to_buffer(reinterpret_cast(dst_ptr), type, 0, vertex_count); + return std::make_tuple(0, vertex_count-1, VK_INDEX_TYPE_UINT16); } } @@ -342,7 +281,7 @@ VKGSRender::upload_vertex_data() if (primitives_emulated) { - index_count = vk::get_emulated_index_array_size(draw_mode, vertex_draw_count); + index_count = get_index_count(draw_mode, vertex_draw_count); upload_size = index_count * sizeof(u16); if (is_indexed_draw) @@ -355,7 +294,7 @@ VKGSRender::upload_vertex_data() offset_in_index_buffer = m_index_buffer_ring_info.alloc<256>(upload_size); void* buf = m_index_buffer_ring_info.map(offset_in_index_buffer, upload_size); - std::tie(min_index, max_index, index_format) = vk::upload_index_buffer(draw_mode, type, buf, is_indexed_draw, vertex_draw_count, index_count, ranges); + std::tie(min_index, max_index, index_format) = vk::upload_index_buffer(get_raw_index_array(ranges), draw_mode, type, buf, is_indexed_draw, vertex_draw_count, index_count, ranges); m_index_buffer_ring_info.unmap(); is_indexed_draw = true;