From a6b7c9c309cb1891bb4cd7764c780bc583c763ff Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sat, 2 Jul 2016 17:27:53 +0300 Subject: [PATCH] vk: Avoid double-copy for vertex attributes (#1852) * vk: Avoid double-copy for vertex attributes fix buffer overflow vk: Fix vertex attrib offset_in_dst for batched draw calls * whitespace fix only --- rpcs3/Emu/RSX/VK/VKGSRender.cpp | 116 +++---- rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp | 450 +++++++++++++-------------- 2 files changed, 266 insertions(+), 300 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 439ef06f2e..fffde04e1a 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -1236,11 +1236,11 @@ void VKGSRender::flip(int buffer) { bool resize_screen = false; - if (m_client_height != m_frame->client_height() || - m_client_width != m_frame->client_width()) - { - if (!!m_frame->client_height() && !!m_frame->client_width()) - resize_screen = true; + if (m_client_height != m_frame->client_height() || + m_client_width != m_frame->client_width()) + { + if (!!m_frame->client_height() && !!m_frame->client_width()) + resize_screen = true; } if (!resize_screen) @@ -1324,59 +1324,59 @@ void VKGSRender::flip(int buffer) */ CHECK_RESULT(vkEndCommandBuffer(m_command_buffer)); - - //Will have to block until rendering is completed - VkFence resize_fence = VK_NULL_HANDLE; - VkFenceCreateInfo infos = {}; - infos.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - - vkQueueWaitIdle(m_swap_chain->get_present_queue()); - vkDeviceWaitIdle(*m_device); - - vkCreateFence((*m_device), &infos, nullptr, &resize_fence); - - //Wait for all grpahics tasks to complete - VkPipelineStageFlags pipe_stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; - VkSubmitInfo submit_infos = {}; - submit_infos.commandBufferCount = 0; - submit_infos.pCommandBuffers = nullptr; - submit_infos.pWaitDstStageMask = &pipe_stage_flags; - submit_infos.pWaitSemaphores = nullptr; - submit_infos.waitSemaphoreCount = 0; - submit_infos.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - CHECK_RESULT(vkQueueSubmit(m_swap_chain->get_present_queue(), 1, &submit_infos, resize_fence)); - - vkWaitForFences((*m_device), 1, &resize_fence, VK_TRUE, UINT64_MAX); - vkResetFences((*m_device), 1, &resize_fence); - - vkDeviceWaitIdle(*m_device); - - //Rebuild swapchain. Old swapchain destruction is handled by the init_swapchain call - m_client_width = m_frame->client_width(); - m_client_height = m_frame->client_height(); - m_swap_chain->init_swapchain(m_client_width, m_client_height); - - //Prepare new swapchain images for use - CHECK_RESULT(vkResetCommandPool(*m_device, m_command_buffer_pool, 0)); - open_command_buffer(); - - for (u32 i = 0; i < m_swap_chain->get_swap_image_count(); ++i) - { - vk::change_image_layout(m_command_buffer, m_swap_chain->get_swap_chain_image(i), - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, - vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT)); - - VkClearColorValue clear_color{}; - auto range = vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT); - vkCmdClearColorImage(m_command_buffer, m_swap_chain->get_swap_chain_image(i), VK_IMAGE_LAYOUT_GENERAL, &clear_color, 1, &range); - vk::change_image_layout(m_command_buffer, m_swap_chain->get_swap_chain_image(i), - VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT)); - } - - //Flush the command buffer - close_and_submit_command_buffer({}, resize_fence); - CHECK_RESULT(vkWaitForFences((*m_device), 1, &resize_fence, VK_TRUE, UINT64_MAX)); + + //Will have to block until rendering is completed + VkFence resize_fence = VK_NULL_HANDLE; + VkFenceCreateInfo infos = {}; + infos.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + + vkQueueWaitIdle(m_swap_chain->get_present_queue()); + vkDeviceWaitIdle(*m_device); + + vkCreateFence((*m_device), &infos, nullptr, &resize_fence); + + //Wait for all grpahics tasks to complete + VkPipelineStageFlags pipe_stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; + VkSubmitInfo submit_infos = {}; + submit_infos.commandBufferCount = 0; + submit_infos.pCommandBuffers = nullptr; + submit_infos.pWaitDstStageMask = &pipe_stage_flags; + submit_infos.pWaitSemaphores = nullptr; + submit_infos.waitSemaphoreCount = 0; + submit_infos.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + CHECK_RESULT(vkQueueSubmit(m_swap_chain->get_present_queue(), 1, &submit_infos, resize_fence)); + + vkWaitForFences((*m_device), 1, &resize_fence, VK_TRUE, UINT64_MAX); + vkResetFences((*m_device), 1, &resize_fence); + + vkDeviceWaitIdle(*m_device); + + //Rebuild swapchain. Old swapchain destruction is handled by the init_swapchain call + m_client_width = m_frame->client_width(); + m_client_height = m_frame->client_height(); + m_swap_chain->init_swapchain(m_client_width, m_client_height); + + //Prepare new swapchain images for use + CHECK_RESULT(vkResetCommandPool(*m_device, m_command_buffer_pool, 0)); + open_command_buffer(); + + for (u32 i = 0; i < m_swap_chain->get_swap_image_count(); ++i) + { + vk::change_image_layout(m_command_buffer, m_swap_chain->get_swap_chain_image(i), + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, + vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT)); + + VkClearColorValue clear_color{}; + auto range = vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT); + vkCmdClearColorImage(m_command_buffer, m_swap_chain->get_swap_chain_image(i), VK_IMAGE_LAYOUT_GENERAL, &clear_color, 1, &range); + vk::change_image_layout(m_command_buffer, m_swap_chain->get_swap_chain_image(i), + VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT)); + } + + //Flush the command buffer + close_and_submit_command_buffer({}, resize_fence); + CHECK_RESULT(vkWaitForFences((*m_device), 1, &resize_fence, VK_TRUE, UINT64_MAX)); vkDestroyFence((*m_device), resize_fence, nullptr); } diff --git a/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp b/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp index 77d6cfb849..69e320f1d3 100644 --- a/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp +++ b/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp @@ -88,61 +88,14 @@ namespace vk /** * Expand line loop array to line strip array; simply loop back the last vertex to the first.. */ - u32 expand_line_loop_array_to_strip(u32 vertex_draw_count, std::vector& indices) + void expand_line_loop_array_to_strip(u32 vertex_draw_count, u16* indices) { u32 i = 0; - indices.resize(vertex_draw_count + 1); for (; i < vertex_draw_count; ++i) indices[i] = i; indices[i] = 0; - return static_cast(indices.size()); - } - - template - u32 expand_indexed_line_loop_to_strip(u32 original_count, const T* original_indices, std::vector& indices) - { - indices.resize(original_count + 1); - - u32 i = 0; - for (; i < original_count; ++i) - indices[i] = original_indices[i]; - - indices[i] = original_indices[0]; - return static_cast(indices.size()); - } - - /** - * Template: Expand any N-compoent vector to a larger X-component vector and pad unused slots with 1 - */ - template - void expand_array_components(const T* src_data, std::vector& dst_data, u32 vertex_count) - { - u32 dst_size = (vertex_count * dst_components * sizeof(T)); - dst_data.resize(dst_size); - - T* src = const_cast(src_data); - T* dst = reinterpret_cast(dst_data.data()); - - for (u32 index = 0; index < vertex_count; ++index) - { - for (u8 channel = 0; channel < dst_components; channel++) - { - if (channel < src_components) - { - *dst = *src; - - dst++; - src++; - } - else - { - *dst = (T)(padding); - dst++; - } - } - } } template @@ -196,6 +149,17 @@ namespace vk { switch (type) { + case rsx::vertex_base_type::f: + { + if (vertex_size == 3) + { + float *dst = reinterpret_cast(data); + for (u32 i = 0, idx = 3; i < vertex_count; ++i, idx += 4) + dst[idx] = 1.f; + } + + break; + } case rsx::vertex_base_type::sf: { if (vertex_size == 3) @@ -212,30 +176,121 @@ namespace vk } } } -} -namespace -{ - struct data_heap_alloc + /** + * Template: Expand any N-compoent vector to a larger X-component vector and pad unused slots with 1 + */ + template + void expand_array_components(const T* src_data, void *dst_ptr, u32 vertex_count) { - static size_t alloc_and_copy(vk::vk_data_heap& data_heap_info, size_t size, std::function ptr)> copy_function) + T* src = const_cast(src_data); + T* dst = static_cast(dst_ptr); + + for (u32 index = 0; index < vertex_count; ++index) { - size_t offset = data_heap_info.alloc<256>(size); - void* buf = data_heap_info.map(offset, size); - gsl::span mapped_span = { reinterpret_cast(buf), gsl::narrow(size) }; - copy_function(mapped_span); - data_heap_info.unmap(); - return offset; + for (u8 channel = 0; channel < dst_components; channel++) + { + if (channel < src_components) + { + *dst = *src; + + dst++; + src++; + } + else + { + *dst = (T)(padding); + dst++; + } + } } - }; + } + + u32 get_emulated_index_array_size(rsx::primitive_type type, u32 vertex_count) + { + switch (type) + { + case rsx::primitive_type::line_loop: + return vertex_count + 1; + default: + return static_cast(get_index_count(type, vertex_count)); + } + } + + 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) + { + bool emulated = false; + get_appropriate_topology(type, emulated); + + u32 min_index, max_index; + + if (!emulated) + { + 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); + } + } + + 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); + } + } + } + } } std::tuple VKGSRender::upload_vertex_data() { //initialize vertex attributes - std::vector vertex_arrays_data; - const std::string reg_table[] = { "in_pos_buffer", "in_weight_buffer", "in_normal_buffer", @@ -248,30 +303,62 @@ VKGSRender::upload_vertex_data() u32 input_mask = rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_INPUT_MASK]; - std::vector vertex_index_array; + size_t offset_in_index_buffer = -1; vertex_draw_count = 0; u32 min_index, max_index; - if (draw_command == rsx::draw_command::indexed) + bool is_indexed_draw = (draw_command == rsx::draw_command::indexed); + bool primitives_emulated = false; + u32 index_count = 0; + + VkIndexType index_format = VK_INDEX_TYPE_UINT16; + VkPrimitiveTopology prims = vk::get_appropriate_topology(draw_mode, primitives_emulated); + + if (draw_command == rsx::draw_command::array) { - rsx::index_array_type type = rsx::to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4); - u32 type_size = gsl::narrow(get_index_type_size(type)); - for (const auto& first_count : first_count_commands) + for (const auto &first_count : first_count_commands) { vertex_draw_count += first_count.second; } + } - vertex_index_array.resize(vertex_draw_count * type_size); - - switch (type) + if (draw_command == rsx::draw_command::indexed || primitives_emulated) + { + rsx::index_array_type type = rsx::to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4); + u32 type_size = gsl::narrow(get_index_type_size(type)); + + if (is_indexed_draw) //Could be emulated or not, emulated array vertex count already computed above { - case rsx::index_array_type::u32: - std::tie(min_index, max_index) = write_index_array_data_to_buffer_untouched(gsl::span((u32*)vertex_index_array.data(), vertex_draw_count), first_count_commands); - break; - case rsx::index_array_type::u16: - std::tie(min_index, max_index) = write_index_array_data_to_buffer_untouched(gsl::span((u16*)vertex_index_array.data(), vertex_draw_count), first_count_commands); - break; + for (const auto& first_count : first_count_commands) + { + vertex_draw_count += first_count.second; + } } + + index_count = vertex_draw_count; + u32 upload_size = vertex_draw_count * type_size; + + std::vector> ranges = first_count_commands; + + if (primitives_emulated) + { + index_count = vk::get_emulated_index_array_size(draw_mode, vertex_draw_count); + upload_size = index_count * sizeof(u16); + + if (is_indexed_draw) + { + ranges.resize(0); + ranges.push_back(std::pair(0, vertex_draw_count)); + } + } + + 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); + + m_index_buffer_ring_info.unmap(); + is_indexed_draw = true; } if (draw_command == rsx::draw_command::inlined_array) @@ -306,9 +393,9 @@ VKGSRender::upload_vertex_data() const u32 data_size = element_size * vertex_draw_count; const VkFormat format = vk::get_suitable_vk_format(vertex_info.type, vertex_info.size); - vertex_arrays_data.resize(data_size); + u32 offset_in_attrib_buffer = m_attrib_ring_info.alloc<256>(data_size); u8 *src = reinterpret_cast(inline_vertex_array.data()); - u8 *dst = vertex_arrays_data.data(); + u8 *dst = static_cast(m_attrib_ring_info.map(offset_in_attrib_buffer, data_size)); src += offsets[index]; u8 opt_size = vertex_info.size; @@ -341,21 +428,12 @@ VKGSRender::upload_vertex_data() throw EXCEPTION("Unknown base type %d", vertex_info.type); } - size_t offset_in_attrib_buffer = data_heap_alloc::alloc_and_copy(m_attrib_ring_info, data_size, [&vertex_arrays_data, data_size](gsl::span ptr) { memcpy(ptr.data(), vertex_arrays_data.data(), data_size); }); - + m_attrib_ring_info.unmap(); m_buffer_view_to_clean.push_back(std::make_unique(*m_device, m_attrib_ring_info.heap->value, format, offset_in_attrib_buffer, data_size)); m_program->bind_uniform(m_buffer_view_to_clean.back()->value, reg_table[index], descriptor_sets); } } - if (draw_command == rsx::draw_command::array) - { - for (const auto &first_count : first_count_commands) - { - vertex_draw_count += first_count.second; - } - } - if (draw_command == rsx::draw_command::array || draw_command == rsx::draw_command::indexed) { for (int index = 0; index < rsx::limits::vertex_count; ++index) @@ -373,12 +451,14 @@ VKGSRender::upload_vertex_data() if (vertex_arrays_info[index].size > 0) { auto &vertex_info = vertex_arrays_info[index]; - // Active vertex array - std::vector vertex_array; // Fill vertex_array u32 element_size = rsx::get_vertex_type_size_on_host(vertex_info.type, vertex_info.size); - vertex_array.resize(vertex_draw_count * element_size); + u32 real_element_size = vk::get_suitable_vk_size(vertex_info.type, vertex_info.size); + + u32 upload_size = real_element_size * vertex_draw_count; + u32 offset_in_attrib_buffer = 0; + bool requires_expansion = vk::requires_component_expansion(vertex_info.type, vertex_info.size); // Get source pointer u32 base_offset = rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_OFFSET]; @@ -391,45 +471,38 @@ VKGSRender::upload_vertex_data() if (draw_command == rsx::draw_command::array) { size_t offset = 0; - gsl::span dest_span(vertex_array); - vk::prepare_buffer_for_writing(vertex_array.data(), vertex_info.type, vertex_info.size, vertex_draw_count); - + offset_in_attrib_buffer = m_attrib_ring_info.alloc<256>(upload_size); + void *dst = m_attrib_ring_info.map(offset_in_attrib_buffer, upload_size); + vk::prepare_buffer_for_writing(dst, vertex_info.type, vertex_info.size, vertex_draw_count); + + gsl::span dest_span(static_cast(dst), upload_size); + for (const auto &first_count : first_count_commands) { - write_vertex_array_data_to_buffer(dest_span.subspan(offset), src_ptr, first_count.first, first_count.second, vertex_info.type, vertex_info.size, vertex_info.stride, element_size); - offset += first_count.second * element_size; + write_vertex_array_data_to_buffer(dest_span.subspan(offset), src_ptr, first_count.first, first_count.second, vertex_info.type, vertex_info.size, vertex_info.stride, real_element_size); + offset += first_count.second * real_element_size; } + + m_attrib_ring_info.unmap(); } + if (draw_command == rsx::draw_command::indexed) { num_stored_verts = (max_index + 1); - vertex_array.resize((max_index + 1) * element_size); - gsl::span dest_span(vertex_array); - vk::prepare_buffer_for_writing(vertex_array.data(), vertex_info.type, vertex_info.size, vertex_draw_count); + upload_size = real_element_size * num_stored_verts; + offset_in_attrib_buffer = m_attrib_ring_info.alloc<256>(upload_size); + void *dst = m_attrib_ring_info.map(offset_in_attrib_buffer, upload_size); + + gsl::span dest_span(static_cast(dst), upload_size); + vk::prepare_buffer_for_writing(dst, vertex_info.type, vertex_info.size, num_stored_verts); - write_vertex_array_data_to_buffer(dest_span, src_ptr, 0, max_index + 1, vertex_info.type, vertex_info.size, vertex_info.stride, element_size); - } - - std::vector converted_buffer; - void *data_ptr = vertex_array.data(); - - if (vk::requires_component_expansion(vertex_info.type, vertex_info.size)) - { - switch (vertex_info.type) - { - case rsx::vertex_base_type::f: - vk::expand_array_components(reinterpret_cast(vertex_array.data()), converted_buffer, num_stored_verts); - break; - } - - data_ptr = static_cast(converted_buffer.data()); + write_vertex_array_data_to_buffer(dest_span, src_ptr, 0, max_index + 1, vertex_info.type, vertex_info.size, vertex_info.stride, real_element_size); + m_attrib_ring_info.unmap(); } const VkFormat format = vk::get_suitable_vk_format(vertex_info.type, vertex_info.size); - const u32 data_size = vk::get_suitable_vk_size(vertex_info.type, vertex_info.size) * num_stored_verts; - size_t offset_in_attrib_buffer = data_heap_alloc::alloc_and_copy(m_attrib_ring_info, data_size, [data_ptr, data_size](gsl::span ptr) { memcpy(ptr.data(), data_ptr, data_size); }); - m_buffer_view_to_clean.push_back(std::make_unique(*m_device, m_attrib_ring_info.heap->value, format, offset_in_attrib_buffer, data_size)); + m_buffer_view_to_clean.push_back(std::make_unique(*m_device, m_attrib_ring_info.heap->value, format, offset_in_attrib_buffer, upload_size)); m_program->bind_uniform(m_buffer_view_to_clean.back()->value, reg_table[index], descriptor_sets); } else if (register_vertex_info[index].size > 0) @@ -445,27 +518,29 @@ VKGSRender::upload_vertex_data() size_t data_size = vertex_data.size(); const VkFormat format = vk::get_suitable_vk_format(vertex_info.type, vertex_info.size); - std::vector converted_buffer; + u32 offset_in_attrib_buffer = 0; void *data_ptr = vertex_data.data(); if (vk::requires_component_expansion(vertex_info.type, vertex_info.size)) { - switch (vertex_info.type) - { - case rsx::vertex_base_type::f: - { - const u32 num_stored_verts = static_cast(data_size / (sizeof(float) * vertex_info.size)); - vk::expand_array_components(reinterpret_cast(vertex_data.data()), converted_buffer, num_stored_verts); - break; - } - } + const u32 num_stored_verts = static_cast(data_size / (sizeof(float) * vertex_info.size)); + const u32 real_element_size = vk::get_suitable_vk_size(vertex_info.type, vertex_info.size); - data_ptr = static_cast(converted_buffer.data()); - data_size = converted_buffer.size(); + data_size = real_element_size * num_stored_verts; + offset_in_attrib_buffer = m_attrib_ring_info.alloc<256>(data_size); + void *dst = m_attrib_ring_info.map(offset_in_attrib_buffer, data_size); + + vk::expand_array_components(reinterpret_cast(vertex_data.data()), dst, num_stored_verts); + m_attrib_ring_info.unmap(); + } + else + { + offset_in_attrib_buffer = m_attrib_ring_info.alloc<256>(data_size); + void *dst = m_attrib_ring_info.map(offset_in_attrib_buffer, data_size); + memcpy(dst, vertex_data.data(), data_size); + m_attrib_ring_info.unmap(); } - - size_t offset_in_attrib_buffer = data_heap_alloc::alloc_and_copy(m_attrib_ring_info, data_size, [data_ptr, data_size](gsl::span ptr) { memcpy(ptr.data(), data_ptr, data_size); }); m_buffer_view_to_clean.push_back(std::make_unique(*m_device, m_attrib_ring_info.heap->value, format, offset_in_attrib_buffer, data_size)); m_program->bind_uniform(m_buffer_view_to_clean.back()->value, reg_table[index], descriptor_sets); break; @@ -477,116 +552,7 @@ VKGSRender::upload_vertex_data() } } } - - bool is_indexed_draw = (draw_command == rsx::draw_command::indexed); - bool index_buffer_filled = false; - bool primitives_emulated = false; - u32 index_count = vertex_draw_count; - - VkIndexType index_format = VK_INDEX_TYPE_UINT16; - VkPrimitiveTopology prims = vk::get_appropriate_topology(draw_mode, primitives_emulated); - - size_t offset_in_index_buffer = -1; - - if (primitives_emulated) - { - //Line loops are line-strips with loop-back; using line-strips-with-adj doesnt work for vulkan - if (draw_mode == rsx::primitive_type::line_loop) - { - std::vector indices; - - if (!is_indexed_draw) - { - index_count = vk::expand_line_loop_array_to_strip(vertex_draw_count, indices); - size_t upload_size = index_count * sizeof(u16); - offset_in_index_buffer = m_index_buffer_ring_info.alloc<256>(upload_size); - void* buf = m_index_buffer_ring_info.heap->map(offset_in_index_buffer, upload_size); - memcpy(buf, indices.data(), upload_size); - m_index_buffer_ring_info.heap->unmap(); - } - else - { - rsx::index_array_type indexed_type = rsx::to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4); - if (indexed_type == rsx::index_array_type::u32) - { - index_format = VK_INDEX_TYPE_UINT32; - std::vector indices32; - - index_count = vk::expand_indexed_line_loop_to_strip(vertex_draw_count, (u32*)vertex_index_array.data(), indices32); - size_t upload_size = index_count * sizeof(u32); - offset_in_index_buffer = m_index_buffer_ring_info.alloc<256>(upload_size); - void* buf = m_index_buffer_ring_info.heap->map(offset_in_index_buffer, upload_size); - memcpy(buf, indices32.data(), upload_size); - m_index_buffer_ring_info.heap->unmap(); - } - else - { - index_count = vk::expand_indexed_line_loop_to_strip(vertex_draw_count, (u16*)vertex_index_array.data(), indices); - size_t upload_size = index_count * sizeof(u16); - offset_in_index_buffer = m_index_buffer_ring_info.alloc<256>(upload_size); - void* buf = m_index_buffer_ring_info.heap->map(offset_in_index_buffer, upload_size); - memcpy(buf, indices.data(), upload_size); - m_index_buffer_ring_info.heap->unmap(); - } - } - } - else - { - index_count = static_cast(get_index_count(draw_mode, vertex_draw_count)); - std::vector indices(index_count); - - if (is_indexed_draw) - { - rsx::index_array_type indexed_type = rsx::to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4); - size_t index_size = get_index_type_size(indexed_type); - - std::vector> ranges; - ranges.push_back(std::pair(0, vertex_draw_count)); - - gsl::span dst = { (gsl::byte*)indices.data(), gsl::narrow(index_count * 2) }; - write_index_array_data_to_buffer(dst, rsx::index_array_type::u16, draw_mode, ranges); - } - else - { - write_index_array_for_non_indexed_non_native_primitive_to_buffer(reinterpret_cast(indices.data()), draw_mode, 0, vertex_draw_count); - } - - size_t upload_size = index_count * sizeof(u16); - offset_in_index_buffer = m_index_buffer_ring_info.alloc<256>(upload_size); - void* buf = m_index_buffer_ring_info.heap->map(offset_in_index_buffer, upload_size); - memcpy(buf, indices.data(), upload_size); - m_index_buffer_ring_info.heap->unmap(); - } - - is_indexed_draw = true; - index_buffer_filled = true; - } - - if (!index_buffer_filled && is_indexed_draw) - { - rsx::index_array_type indexed_type = rsx::to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4); - index_format = VK_INDEX_TYPE_UINT16; - VkFormat fmt = VK_FORMAT_R16_UINT; - - u32 elem_size = static_cast(get_index_type_size(indexed_type)); - - if (indexed_type == rsx::index_array_type::u32) - { - index_format = VK_INDEX_TYPE_UINT32; - fmt = VK_FORMAT_R32_UINT; - } - - u32 index_sz = static_cast(vertex_index_array.size()) / elem_size; - if (index_sz != vertex_draw_count) - LOG_ERROR(RSX, "Vertex draw count mismatch!"); - - size_t upload_size = vertex_index_array.size(); - offset_in_index_buffer = m_index_buffer_ring_info.alloc<256>(upload_size); - void* buf = m_index_buffer_ring_info.heap->map(offset_in_index_buffer, upload_size); - memcpy(buf, vertex_index_array.data(), upload_size); - m_index_buffer_ring_info.heap->unmap(); - } - + return std::make_tuple(prims, is_indexed_draw, index_count, offset_in_index_buffer, index_format); }