mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-29 22:20:48 +00:00
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
This commit is contained in:
parent
85c4392b34
commit
a6b7c9c309
@ -1236,11 +1236,11 @@ void VKGSRender::flip(int buffer)
|
|||||||
{
|
{
|
||||||
bool resize_screen = false;
|
bool resize_screen = false;
|
||||||
|
|
||||||
if (m_client_height != m_frame->client_height() ||
|
if (m_client_height != m_frame->client_height() ||
|
||||||
m_client_width != m_frame->client_width())
|
m_client_width != m_frame->client_width())
|
||||||
{
|
{
|
||||||
if (!!m_frame->client_height() && !!m_frame->client_width())
|
if (!!m_frame->client_height() && !!m_frame->client_width())
|
||||||
resize_screen = true;
|
resize_screen = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!resize_screen)
|
if (!resize_screen)
|
||||||
@ -1324,59 +1324,59 @@ void VKGSRender::flip(int buffer)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
CHECK_RESULT(vkEndCommandBuffer(m_command_buffer));
|
CHECK_RESULT(vkEndCommandBuffer(m_command_buffer));
|
||||||
|
|
||||||
//Will have to block until rendering is completed
|
//Will have to block until rendering is completed
|
||||||
VkFence resize_fence = VK_NULL_HANDLE;
|
VkFence resize_fence = VK_NULL_HANDLE;
|
||||||
VkFenceCreateInfo infos = {};
|
VkFenceCreateInfo infos = {};
|
||||||
infos.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
infos.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||||
|
|
||||||
vkQueueWaitIdle(m_swap_chain->get_present_queue());
|
vkQueueWaitIdle(m_swap_chain->get_present_queue());
|
||||||
vkDeviceWaitIdle(*m_device);
|
vkDeviceWaitIdle(*m_device);
|
||||||
|
|
||||||
vkCreateFence((*m_device), &infos, nullptr, &resize_fence);
|
vkCreateFence((*m_device), &infos, nullptr, &resize_fence);
|
||||||
|
|
||||||
//Wait for all grpahics tasks to complete
|
//Wait for all grpahics tasks to complete
|
||||||
VkPipelineStageFlags pipe_stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
|
VkPipelineStageFlags pipe_stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
|
||||||
VkSubmitInfo submit_infos = {};
|
VkSubmitInfo submit_infos = {};
|
||||||
submit_infos.commandBufferCount = 0;
|
submit_infos.commandBufferCount = 0;
|
||||||
submit_infos.pCommandBuffers = nullptr;
|
submit_infos.pCommandBuffers = nullptr;
|
||||||
submit_infos.pWaitDstStageMask = &pipe_stage_flags;
|
submit_infos.pWaitDstStageMask = &pipe_stage_flags;
|
||||||
submit_infos.pWaitSemaphores = nullptr;
|
submit_infos.pWaitSemaphores = nullptr;
|
||||||
submit_infos.waitSemaphoreCount = 0;
|
submit_infos.waitSemaphoreCount = 0;
|
||||||
submit_infos.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
submit_infos.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
CHECK_RESULT(vkQueueSubmit(m_swap_chain->get_present_queue(), 1, &submit_infos, resize_fence));
|
CHECK_RESULT(vkQueueSubmit(m_swap_chain->get_present_queue(), 1, &submit_infos, resize_fence));
|
||||||
|
|
||||||
vkWaitForFences((*m_device), 1, &resize_fence, VK_TRUE, UINT64_MAX);
|
vkWaitForFences((*m_device), 1, &resize_fence, VK_TRUE, UINT64_MAX);
|
||||||
vkResetFences((*m_device), 1, &resize_fence);
|
vkResetFences((*m_device), 1, &resize_fence);
|
||||||
|
|
||||||
vkDeviceWaitIdle(*m_device);
|
vkDeviceWaitIdle(*m_device);
|
||||||
|
|
||||||
//Rebuild swapchain. Old swapchain destruction is handled by the init_swapchain call
|
//Rebuild swapchain. Old swapchain destruction is handled by the init_swapchain call
|
||||||
m_client_width = m_frame->client_width();
|
m_client_width = m_frame->client_width();
|
||||||
m_client_height = m_frame->client_height();
|
m_client_height = m_frame->client_height();
|
||||||
m_swap_chain->init_swapchain(m_client_width, m_client_height);
|
m_swap_chain->init_swapchain(m_client_width, m_client_height);
|
||||||
|
|
||||||
//Prepare new swapchain images for use
|
//Prepare new swapchain images for use
|
||||||
CHECK_RESULT(vkResetCommandPool(*m_device, m_command_buffer_pool, 0));
|
CHECK_RESULT(vkResetCommandPool(*m_device, m_command_buffer_pool, 0));
|
||||||
open_command_buffer();
|
open_command_buffer();
|
||||||
|
|
||||||
for (u32 i = 0; i < m_swap_chain->get_swap_image_count(); ++i)
|
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::change_image_layout(m_command_buffer, m_swap_chain->get_swap_chain_image(i),
|
||||||
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
|
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
|
||||||
vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT));
|
vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT));
|
||||||
|
|
||||||
VkClearColorValue clear_color{};
|
VkClearColorValue clear_color{};
|
||||||
auto range = vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT);
|
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);
|
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::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_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
||||||
vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT));
|
vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT));
|
||||||
}
|
}
|
||||||
|
|
||||||
//Flush the command buffer
|
//Flush the command buffer
|
||||||
close_and_submit_command_buffer({}, resize_fence);
|
close_and_submit_command_buffer({}, resize_fence);
|
||||||
CHECK_RESULT(vkWaitForFences((*m_device), 1, &resize_fence, VK_TRUE, UINT64_MAX));
|
CHECK_RESULT(vkWaitForFences((*m_device), 1, &resize_fence, VK_TRUE, UINT64_MAX));
|
||||||
vkDestroyFence((*m_device), resize_fence, nullptr);
|
vkDestroyFence((*m_device), resize_fence, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,61 +88,14 @@ namespace vk
|
|||||||
/**
|
/**
|
||||||
* Expand line loop array to line strip array; simply loop back the last vertex to the first..
|
* 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<u16>& indices)
|
void expand_line_loop_array_to_strip(u32 vertex_draw_count, u16* indices)
|
||||||
{
|
{
|
||||||
u32 i = 0;
|
u32 i = 0;
|
||||||
indices.resize(vertex_draw_count + 1);
|
|
||||||
|
|
||||||
for (; i < vertex_draw_count; ++i)
|
for (; i < vertex_draw_count; ++i)
|
||||||
indices[i] = i;
|
indices[i] = i;
|
||||||
|
|
||||||
indices[i] = 0;
|
indices[i] = 0;
|
||||||
return static_cast<u32>(indices.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
u32 expand_indexed_line_loop_to_strip(u32 original_count, const T* original_indices, std::vector<T>& 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<u32>(indices.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Template: Expand any N-compoent vector to a larger X-component vector and pad unused slots with 1
|
|
||||||
*/
|
|
||||||
template<typename T, u8 src_components, u8 dst_components, u32 padding>
|
|
||||||
void expand_array_components(const T* src_data, std::vector<u8>& dst_data, u32 vertex_count)
|
|
||||||
{
|
|
||||||
u32 dst_size = (vertex_count * dst_components * sizeof(T));
|
|
||||||
dst_data.resize(dst_size);
|
|
||||||
|
|
||||||
T* src = const_cast<T*>(src_data);
|
|
||||||
T* dst = reinterpret_cast<T*>(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 <typename T, u32 padding>
|
template <typename T, u32 padding>
|
||||||
@ -196,6 +149,17 @@ namespace vk
|
|||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
case rsx::vertex_base_type::f:
|
||||||
|
{
|
||||||
|
if (vertex_size == 3)
|
||||||
|
{
|
||||||
|
float *dst = reinterpret_cast<float*>(data);
|
||||||
|
for (u32 i = 0, idx = 3; i < vertex_count; ++i, idx += 4)
|
||||||
|
dst[idx] = 1.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
case rsx::vertex_base_type::sf:
|
case rsx::vertex_base_type::sf:
|
||||||
{
|
{
|
||||||
if (vertex_size == 3)
|
if (vertex_size == 3)
|
||||||
@ -212,30 +176,121 @@ namespace vk
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
namespace
|
/**
|
||||||
{
|
* Template: Expand any N-compoent vector to a larger X-component vector and pad unused slots with 1
|
||||||
struct data_heap_alloc
|
*/
|
||||||
|
template<typename T, u8 src_components, u8 dst_components, u32 padding>
|
||||||
|
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<void(gsl::span<gsl::byte> ptr)> copy_function)
|
T* src = const_cast<T*>(src_data);
|
||||||
|
T* dst = static_cast<T*>(dst_ptr);
|
||||||
|
|
||||||
|
for (u32 index = 0; index < vertex_count; ++index)
|
||||||
{
|
{
|
||||||
size_t offset = data_heap_info.alloc<256>(size);
|
for (u8 channel = 0; channel < dst_components; channel++)
|
||||||
void* buf = data_heap_info.map(offset, size);
|
{
|
||||||
gsl::span<gsl::byte> mapped_span = { reinterpret_cast<gsl::byte*>(buf), gsl::narrow<int>(size) };
|
if (channel < src_components)
|
||||||
copy_function(mapped_span);
|
{
|
||||||
data_heap_info.unmap();
|
*dst = *src;
|
||||||
return offset;
|
|
||||||
|
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<u32>(get_index_count(type, vertex_count));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<u32, u32, VkIndexType> 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<std::pair<u32, u32>> 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>((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>((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<u16*>(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<u32*>(dst_ptr);
|
||||||
|
std::tie(min_index, max_index) = write_index_array_data_to_buffer_untouched(gsl::span<u32>(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<u16*>(dst_ptr);
|
||||||
|
std::tie(min_index, max_index) = write_index_array_data_to_buffer_untouched(gsl::span<u16>(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<gsl::byte>(static_cast<gsl::byte*>(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<char*>(dst_ptr), type, 0, vertex_count);
|
||||||
|
return std::make_tuple(0, vertex_count-1, VK_INDEX_TYPE_UINT16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<VkPrimitiveTopology, bool, u32, VkDeviceSize, VkIndexType>
|
std::tuple<VkPrimitiveTopology, bool, u32, VkDeviceSize, VkIndexType>
|
||||||
VKGSRender::upload_vertex_data()
|
VKGSRender::upload_vertex_data()
|
||||||
{
|
{
|
||||||
//initialize vertex attributes
|
//initialize vertex attributes
|
||||||
std::vector<u8> vertex_arrays_data;
|
|
||||||
|
|
||||||
const std::string reg_table[] =
|
const std::string reg_table[] =
|
||||||
{
|
{
|
||||||
"in_pos_buffer", "in_weight_buffer", "in_normal_buffer",
|
"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];
|
u32 input_mask = rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_INPUT_MASK];
|
||||||
|
|
||||||
std::vector<u8> vertex_index_array;
|
size_t offset_in_index_buffer = -1;
|
||||||
vertex_draw_count = 0;
|
vertex_draw_count = 0;
|
||||||
u32 min_index, max_index;
|
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);
|
for (const auto &first_count : first_count_commands)
|
||||||
u32 type_size = gsl::narrow<u32>(get_index_type_size(type));
|
|
||||||
for (const auto& first_count : first_count_commands)
|
|
||||||
{
|
{
|
||||||
vertex_draw_count += first_count.second;
|
vertex_draw_count += first_count.second;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
vertex_index_array.resize(vertex_draw_count * type_size);
|
if (draw_command == rsx::draw_command::indexed || primitives_emulated)
|
||||||
|
{
|
||||||
switch (type)
|
rsx::index_array_type type = rsx::to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4);
|
||||||
|
u32 type_size = gsl::narrow<u32>(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:
|
for (const auto& first_count : first_count_commands)
|
||||||
std::tie(min_index, max_index) = write_index_array_data_to_buffer_untouched(gsl::span<u32>((u32*)vertex_index_array.data(), vertex_draw_count), first_count_commands);
|
{
|
||||||
break;
|
vertex_draw_count += first_count.second;
|
||||||
case rsx::index_array_type::u16:
|
}
|
||||||
std::tie(min_index, max_index) = write_index_array_data_to_buffer_untouched(gsl::span<u16>((u16*)vertex_index_array.data(), vertex_draw_count), first_count_commands);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
index_count = vertex_draw_count;
|
||||||
|
u32 upload_size = vertex_draw_count * type_size;
|
||||||
|
|
||||||
|
std::vector<std::pair<u32, u32>> 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<u32, u32>(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)
|
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 u32 data_size = element_size * vertex_draw_count;
|
||||||
const VkFormat format = vk::get_suitable_vk_format(vertex_info.type, vertex_info.size);
|
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<u8*>(inline_vertex_array.data());
|
u8 *src = reinterpret_cast<u8*>(inline_vertex_array.data());
|
||||||
u8 *dst = vertex_arrays_data.data();
|
u8 *dst = static_cast<u8*>(m_attrib_ring_info.map(offset_in_attrib_buffer, data_size));
|
||||||
|
|
||||||
src += offsets[index];
|
src += offsets[index];
|
||||||
u8 opt_size = vertex_info.size;
|
u8 opt_size = vertex_info.size;
|
||||||
@ -341,21 +428,12 @@ VKGSRender::upload_vertex_data()
|
|||||||
throw EXCEPTION("Unknown base type %d", vertex_info.type);
|
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<gsl::byte> 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<vk::buffer_view>(*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<vk::buffer_view>(*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);
|
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)
|
if (draw_command == rsx::draw_command::array || draw_command == rsx::draw_command::indexed)
|
||||||
{
|
{
|
||||||
for (int index = 0; index < rsx::limits::vertex_count; ++index)
|
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)
|
if (vertex_arrays_info[index].size > 0)
|
||||||
{
|
{
|
||||||
auto &vertex_info = vertex_arrays_info[index];
|
auto &vertex_info = vertex_arrays_info[index];
|
||||||
// Active vertex array
|
|
||||||
std::vector<gsl::byte> vertex_array;
|
|
||||||
|
|
||||||
// Fill vertex_array
|
// Fill vertex_array
|
||||||
u32 element_size = rsx::get_vertex_type_size_on_host(vertex_info.type, vertex_info.size);
|
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
|
// Get source pointer
|
||||||
u32 base_offset = rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_OFFSET];
|
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)
|
if (draw_command == rsx::draw_command::array)
|
||||||
{
|
{
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
gsl::span<gsl::byte> dest_span(vertex_array);
|
offset_in_attrib_buffer = m_attrib_ring_info.alloc<256>(upload_size);
|
||||||
vk::prepare_buffer_for_writing(vertex_array.data(), vertex_info.type, vertex_info.size, vertex_draw_count);
|
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<gsl::byte> dest_span(static_cast<gsl::byte*>(dst), upload_size);
|
||||||
|
|
||||||
for (const auto &first_count : first_count_commands)
|
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);
|
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 * element_size;
|
offset += first_count.second * real_element_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_attrib_ring_info.unmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (draw_command == rsx::draw_command::indexed)
|
if (draw_command == rsx::draw_command::indexed)
|
||||||
{
|
{
|
||||||
num_stored_verts = (max_index + 1);
|
num_stored_verts = (max_index + 1);
|
||||||
vertex_array.resize((max_index + 1) * element_size);
|
upload_size = real_element_size * num_stored_verts;
|
||||||
gsl::span<gsl::byte> dest_span(vertex_array);
|
offset_in_attrib_buffer = m_attrib_ring_info.alloc<256>(upload_size);
|
||||||
vk::prepare_buffer_for_writing(vertex_array.data(), vertex_info.type, vertex_info.size, vertex_draw_count);
|
void *dst = m_attrib_ring_info.map(offset_in_attrib_buffer, upload_size);
|
||||||
|
|
||||||
|
gsl::span<gsl::byte> dest_span(static_cast<gsl::byte*>(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);
|
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();
|
||||||
|
|
||||||
std::vector<u8> 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<float, 3, 4, 1>(reinterpret_cast<float*>(vertex_array.data()), converted_buffer, num_stored_verts);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
data_ptr = static_cast<void*>(converted_buffer.data());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const VkFormat format = vk::get_suitable_vk_format(vertex_info.type, vertex_info.size);
|
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<gsl::byte> ptr) { memcpy(ptr.data(), data_ptr, data_size); });
|
m_buffer_view_to_clean.push_back(std::make_unique<vk::buffer_view>(*m_device, m_attrib_ring_info.heap->value, format, offset_in_attrib_buffer, upload_size));
|
||||||
m_buffer_view_to_clean.push_back(std::make_unique<vk::buffer_view>(*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);
|
m_program->bind_uniform(m_buffer_view_to_clean.back()->value, reg_table[index], descriptor_sets);
|
||||||
}
|
}
|
||||||
else if (register_vertex_info[index].size > 0)
|
else if (register_vertex_info[index].size > 0)
|
||||||
@ -445,27 +518,29 @@ VKGSRender::upload_vertex_data()
|
|||||||
size_t data_size = vertex_data.size();
|
size_t data_size = vertex_data.size();
|
||||||
const VkFormat format = vk::get_suitable_vk_format(vertex_info.type, vertex_info.size);
|
const VkFormat format = vk::get_suitable_vk_format(vertex_info.type, vertex_info.size);
|
||||||
|
|
||||||
std::vector<u8> converted_buffer;
|
u32 offset_in_attrib_buffer = 0;
|
||||||
void *data_ptr = vertex_data.data();
|
void *data_ptr = vertex_data.data();
|
||||||
|
|
||||||
if (vk::requires_component_expansion(vertex_info.type, vertex_info.size))
|
if (vk::requires_component_expansion(vertex_info.type, vertex_info.size))
|
||||||
{
|
{
|
||||||
switch (vertex_info.type)
|
const u32 num_stored_verts = static_cast<u32>(data_size / (sizeof(float) * vertex_info.size));
|
||||||
{
|
const u32 real_element_size = vk::get_suitable_vk_size(vertex_info.type, vertex_info.size);
|
||||||
case rsx::vertex_base_type::f:
|
|
||||||
{
|
|
||||||
const u32 num_stored_verts = static_cast<u32>(data_size / (sizeof(float) * vertex_info.size));
|
|
||||||
vk::expand_array_components<float, 3, 4, 1>(reinterpret_cast<float*>(vertex_data.data()), converted_buffer, num_stored_verts);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data_ptr = static_cast<void*>(converted_buffer.data());
|
data_size = real_element_size * num_stored_verts;
|
||||||
data_size = converted_buffer.size();
|
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<float, 3, 4, 1>(reinterpret_cast<float*>(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<gsl::byte> ptr) { memcpy(ptr.data(), data_ptr, data_size); });
|
|
||||||
m_buffer_view_to_clean.push_back(std::make_unique<vk::buffer_view>(*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<vk::buffer_view>(*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);
|
m_program->bind_uniform(m_buffer_view_to_clean.back()->value, reg_table[index], descriptor_sets);
|
||||||
break;
|
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<u16> 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<u32> 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<u32>(get_index_count(draw_mode, vertex_draw_count));
|
|
||||||
std::vector<u16> 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<std::pair<u32, u32>> ranges;
|
|
||||||
ranges.push_back(std::pair<u32, u32>(0, vertex_draw_count));
|
|
||||||
|
|
||||||
gsl::span<gsl::byte> dst = { (gsl::byte*)indices.data(), gsl::narrow<int>(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<char*>(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<u32>(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<u32>(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);
|
return std::make_tuple(prims, is_indexed_draw, index_count, offset_in_index_buffer, index_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user