diff --git a/rpcs3/Emu/RSX/Common/BufferUtils.cpp b/rpcs3/Emu/RSX/Common/BufferUtils.cpp index a653e182a4..17b5126032 100644 --- a/rpcs3/Emu/RSX/Common/BufferUtils.cpp +++ b/rpcs3/Emu/RSX/Common/BufferUtils.cpp @@ -456,7 +456,7 @@ void write_vertex_array_data_to_buffer(gsl::span raw_dst_span, gsl::s namespace { template -std::tuple upload_untouched(gsl::span> src, gsl::span dst, bool is_primitive_restart_enabled, T primitive_restart_index) +std::tuple upload_untouched(gsl::span> src, gsl::span dst, bool is_primitive_restart_enabled, T primitive_restart_index) { T min_index = -1; T max_index = 0; @@ -468,6 +468,10 @@ std::tuple upload_untouched(gsl::span> src, gsl::span { if (is_primitive_restart_enabled && index == primitive_restart_index) { + // List types do not need primitive restart. Just skip over this instead + if (rsx::method_registers.current_draw_clause.is_disjoint_primitive) + continue; + index = -1; } else @@ -478,62 +482,68 @@ std::tuple upload_untouched(gsl::span> src, gsl::span dst[dst_idx++] = index; } - return std::make_tuple(min_index, max_index); + return std::make_tuple(min_index, max_index, ::narrow(dst_idx)); } -// FIXME: expanded primitive type may not support primitive restart correctly template -std::tuple expand_indexed_triangle_fan(gsl::span> src, gsl::span dst, bool is_primitive_restart_enabled, T primitive_restart_index) +std::tuple expand_indexed_triangle_fan(gsl::span> src, gsl::span dst, bool is_primitive_restart_enabled, T primitive_restart_index) { - T min_index = -1; + const T invalid_index = (T)-1; + + T min_index = invalid_index; T max_index = 0; verify(HERE), (dst.size() >= 3 * (src.size() - 2)); - const T index0 = src[0]; - if (!is_primitive_restart_enabled || index0 != -1) // Cut - { - min_index = std::min(min_index, index0); - max_index = std::max(max_index, index0); - } - size_t dst_idx = 0; - while (src.size() > 2) + size_t src_idx = 0; + + bool needs_anchor = true; + T anchor = invalid_index; + T last_index = invalid_index; + + for (size_t src_idx = 0; src_idx < src.size(); ++src_idx) { - gsl::span> tri_indexes = src.subspan(0, 2); - T index1 = tri_indexes[0]; - if (is_primitive_restart_enabled && index1 == primitive_restart_index) + if (needs_anchor) { - index1 = -1; - } - else - { - min_index = std::min(min_index, index1); - max_index = std::max(max_index, index1); - } - T index2 = tri_indexes[1]; - if (is_primitive_restart_enabled && index2 == primitive_restart_index) - { - index2 = -1; - } - else - { - min_index = std::min(min_index, index2); - max_index = std::max(max_index, index2); + if (is_primitive_restart_enabled && src[src_idx] == primitive_restart_index) + continue; + + anchor = src[src_idx]; + needs_anchor = false; + continue; } - dst[dst_idx++] = index0; - dst[dst_idx++] = index1; - dst[dst_idx++] = index2; + if (is_primitive_restart_enabled && src[src_idx] == primitive_restart_index) + { + needs_anchor = true; + last_index = invalid_index; + continue; + } - src = src.subspan(2); + T index = src[src_idx]; + max_index = std::max(max_index, index); + min_index = std::min(min_index, index); + + if (last_index == invalid_index) + { + //Need at least one anchor and one outer index to create a triange + last_index = index; + continue; + } + + dst[dst_idx++] = anchor; + dst[dst_idx++] = last_index; + dst[dst_idx++] = index; + + last_index = index; } - return std::make_tuple(min_index, max_index); + + return std::make_tuple(min_index, max_index, ::narrow(dst_idx)); } -// FIXME: expanded primitive type may not support primitive restart correctly template -std::tuple expand_indexed_quads(gsl::span> src, gsl::span dst, bool is_primitive_restart_enabled, T primitive_restart_index) +std::tuple expand_indexed_quads(gsl::span> src, gsl::span dst, bool is_primitive_restart_enabled, T primitive_restart_index) { T min_index = -1; T max_index = 0; @@ -541,62 +551,39 @@ std::tuple expand_indexed_quads(gsl::span> src, gsl::span verify(HERE), (4 * dst.size_bytes() >= 6 * src.size_bytes()); size_t dst_idx = 0; - while (!src.empty()) + size_t set_size = 0; + T tmp_indices[4]; + + for (int src_idx = 0; src_idx < src.size(); ++src_idx) { - gsl::span> quad_indexes = src.subspan(0, 4); - T index0 = quad_indexes[0]; - if (is_primitive_restart_enabled && index0 == primitive_restart_index) + T index = src[src_idx]; + if (is_primitive_restart_enabled && index == primitive_restart_index) { - index0 = -1; - } - else - { - min_index = std::min(min_index, index0); - max_index = std::max(max_index, index0); - } - T index1 = quad_indexes[1]; - if (is_primitive_restart_enabled && index1 == primitive_restart_index) - { - index1 = -1; - } - else - { - min_index = std::min(min_index, index1); - max_index = std::max(max_index, index1); - } - T index2 = quad_indexes[2]; - if (is_primitive_restart_enabled && index2 == primitive_restart_index) - { - index2 = -1; - } - else - { - min_index = std::min(min_index, index2); - max_index = std::max(max_index, index2); - } - T index3 = quad_indexes[3]; - if (is_primitive_restart_enabled &&index3 == primitive_restart_index) - { - index3 = -1; - } - else - { - min_index = std::min(min_index, index3); - max_index = std::max(max_index, index3); + //empty temp buffer + set_size = 0; + continue; } - // First triangle - dst[dst_idx++] = index0; - dst[dst_idx++] = index1; - dst[dst_idx++] = index2; - // Second triangle - dst[dst_idx++] = index2; - dst[dst_idx++] = index3; - dst[dst_idx++] = index0; + tmp_indices[set_size++] = index; + max_index = std::max(max_index, index); + min_index = std::min(min_index, index); - src = src.subspan(4); + if (set_size == 4) + { + // First triangle + dst[dst_idx++] = tmp_indices[0]; + dst[dst_idx++] = tmp_indices[1]; + dst[dst_idx++] = tmp_indices[2]; + // Second triangle + dst[dst_idx++] = tmp_indices[2]; + dst[dst_idx++] = tmp_indices[3]; + dst[dst_idx++] = tmp_indices[0]; + + set_size = 0; + } } - return std::make_tuple(min_index, max_index); + + return std::make_tuple(min_index, max_index, ::narrow(dst_idx)); } } @@ -714,7 +701,7 @@ namespace // TODO: Unify indexed and non indexed primitive expansion ? template - std::tuple write_index_array_data_to_buffer_impl(gsl::span dst, + 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) @@ -743,7 +730,7 @@ namespace } } -std::tuple write_index_array_data_to_buffer(gsl::span dst, +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) diff --git a/rpcs3/Emu/RSX/Common/BufferUtils.h b/rpcs3/Emu/RSX/Common/BufferUtils.h index 0bcf7bd4b8..2cdc7b28d5 100644 --- a/rpcs3/Emu/RSX/Common/BufferUtils.h +++ b/rpcs3/Emu/RSX/Common/BufferUtils.h @@ -29,10 +29,10 @@ u32 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. + * Returns min/max index found during the process and the number of valid indices written to the buffer. * 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, gsl::span src, +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); diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp index 8ee853cd1d..e0b5b00d4c 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp @@ -410,7 +410,7 @@ namespace gsl::span dst{ reinterpret_cast(mapped_buffer), ::narrow(buffer_size)}; - std::tie(min_index, max_index) = + std::tie(min_index, max_index, index_count) = write_index_array_data_to_buffer(dst, command.raw_index_buffer, indexed_type, rsx::method_registers.current_draw_clause.primitive, rsx::method_registers.restart_index_enabled(), diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 5e3c5c1bed..27b87b3ca9 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -503,8 +503,9 @@ void GLGSRender::end() { const GLenum index_type = std::get<0>(indexed_draw_info.value()); const u32 index_offset = std::get<1>(indexed_draw_info.value()); + const bool restarts_valid = gl::is_primitive_native(rsx::method_registers.current_draw_clause.primitive) && !rsx::method_registers.current_draw_clause.is_disjoint_primitive; - if (gl_state.enable(rsx::method_registers.restart_index_enabled(), GL_PRIMITIVE_RESTART)) + if (gl_state.enable(restarts_valid && rsx::method_registers.restart_index_enabled(), GL_PRIMITIVE_RESTART)) { glPrimitiveRestartIndex((index_type == GL_UNSIGNED_SHORT)? 0xffff: 0xffffffff); } diff --git a/rpcs3/Emu/RSX/GL/GLVertexBuffers.cpp b/rpcs3/Emu/RSX/GL/GLVertexBuffers.cpp index 164ae7934d..d988aa9a4e 100644 --- a/rpcs3/Emu/RSX/GL/GLVertexBuffers.cpp +++ b/rpcs3/Emu/RSX/GL/GLVertexBuffers.cpp @@ -51,7 +51,7 @@ namespace u32 block_sz = vertex_draw_count * type_size; gsl::span dst{ reinterpret_cast(ptr), ::narrow(block_sz) }; - std::tie(min_index, max_index) = write_index_array_data_to_buffer(dst, raw_index_buffer, + std::tie(min_index, max_index, vertex_draw_count) = 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 !gl::is_primitive_native(prim); }); diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index a7febdaae1..26d9b5a81c 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -1842,16 +1842,17 @@ bool VKGSRender::check_program_status() vk::pipeline_props properties = {}; - bool unused; + bool emulated_primitive_type; bool update_blend_constants = false; bool update_stencil_info_back = false; bool update_stencil_info_front = false; bool update_depth_bounds = false; properties.ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - properties.ia.topology = vk::get_appropriate_topology(rsx::method_registers.current_draw_clause.primitive, unused); + properties.ia.topology = vk::get_appropriate_topology(rsx::method_registers.current_draw_clause.primitive, emulated_primitive_type); - if (rsx::method_registers.current_draw_clause.command == rsx::draw_command::indexed && rsx::method_registers.restart_index_enabled() && !vk::emulate_primitive_restart()) + const bool restarts_valid = rsx::method_registers.current_draw_clause.command == rsx::draw_command::indexed && !emulated_primitive_type && !rsx::method_registers.current_draw_clause.is_disjoint_primitive; + if (rsx::method_registers.restart_index_enabled() && !vk::emulate_primitive_restart() && restarts_valid) properties.ia.primitiveRestartEnable = VK_TRUE; else properties.ia.primitiveRestartEnable = VK_FALSE; diff --git a/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp b/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp index 16b93c529a..ee9c614c4c 100644 --- a/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp +++ b/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp @@ -157,7 +157,7 @@ namespace * Upload index (and expands it if primitive type is not natively supported). */ u32 min_index, max_index; - std::tie(min_index, max_index) = write_index_array_data_to_buffer( + std::tie(min_index, max_index, index_count) = write_index_array_data_to_buffer( dst, command.raw_index_buffer, index_type, rsx::method_registers.current_draw_clause.primitive,