rsx/vk: Workaround for polaris primitive restart bug

This commit is contained in:
kd-11 2017-10-17 01:02:43 +03:00
parent 5146f3ec47
commit 3d05e61f7e
6 changed files with 110 additions and 8 deletions

View File

@ -1211,7 +1211,8 @@ void VKGSRender::end()
} }
std::optional<std::tuple<VkDeviceSize, VkIndexType> > index_info = std::get<4>(upload_info); std::optional<std::tuple<VkDeviceSize, VkIndexType> > index_info = std::get<4>(upload_info);
bool single_draw = rsx::method_registers.current_draw_clause.first_count_commands.size() <= 1 || rsx::method_registers.current_draw_clause.is_disjoint_primitive; const bool is_emulated_restart = (index_info && rsx::method_registers.restart_index_enabled() && vk::emulate_primitive_restart() && rsx::method_registers.current_draw_clause.command == rsx::draw_command::indexed);
const bool single_draw = !is_emulated_restart && (rsx::method_registers.current_draw_clause.first_count_commands.size() <= 1 || rsx::method_registers.current_draw_clause.is_disjoint_primitive);
if (!index_info) if (!index_info)
{ {
@ -1244,12 +1245,23 @@ void VKGSRender::end()
} }
else else
{ {
u32 first_vertex = 0; if (!is_emulated_restart)
for (const auto &range : rsx::method_registers.current_draw_clause.first_count_commands)
{ {
const auto verts = get_index_count(rsx::method_registers.current_draw_clause.primitive, range.second); u32 first_vertex = 0;
vkCmdDrawIndexed(*m_current_command_buffer, verts, 1, 0, first_vertex, 0); for (const auto &range : rsx::method_registers.current_draw_clause.first_count_commands)
first_vertex += verts; {
const auto verts = get_index_count(rsx::method_registers.current_draw_clause.primitive, range.second);
vkCmdDrawIndexed(*m_current_command_buffer, verts, 1, first_vertex, 0, 0);
first_vertex += verts;
}
}
else
{
for (const auto &range : rsx::method_registers.current_draw_clause.alternate_first_count_commands)
{
//Primitive restart splitting happens after the primitive type expansion step
vkCmdDrawIndexed(*m_current_command_buffer, range.second, 1, range.first, 0, 0);
}
} }
} }
} }
@ -1839,7 +1851,7 @@ bool VKGSRender::check_program_status()
properties.ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; 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, unused);
if (rsx::method_registers.restart_index_enabled()) if (rsx::method_registers.current_draw_clause.command == rsx::draw_command::indexed && rsx::method_registers.restart_index_enabled() && !vk::emulate_primitive_restart())
properties.ia.primitiveRestartEnable = VK_TRUE; properties.ia.primitiveRestartEnable = VK_TRUE;
else else
properties.ia.primitiveRestartEnable = VK_FALSE; properties.ia.primitiveRestartEnable = VK_FALSE;

View File

@ -12,6 +12,7 @@ namespace vk
VkSampler g_null_sampler = nullptr; VkSampler g_null_sampler = nullptr;
bool g_cb_no_interrupt_flag = false; bool g_cb_no_interrupt_flag = false;
bool g_drv_no_primitive_restart_flag = false;
u64 g_num_processed_frames = 0; u64 g_num_processed_frames = 0;
u64 g_num_total_frames = 0; u64 g_num_total_frames = 0;
@ -257,6 +258,34 @@ namespace vk
void set_current_renderer(const vk::render_device &device) void set_current_renderer(const vk::render_device &device)
{ {
g_current_renderer = device; g_current_renderer = device;
#ifdef _WIN32
const std::array<std::string, 6> black_listed =
{
// Black list all polaris unless its proven they dont have a problem with primitive restart
"RX 580",
"RX 570",
"RX 560",
"RX 480",
"RX 470",
"RX 460",
};
const auto gpu_name = g_current_renderer.gpu().name();
for (const auto& test : black_listed)
{
if (gpu_name.find(test) != std::string::npos)
{
g_drv_no_primitive_restart_flag = true;
break;
}
}
#endif
}
bool emulate_primitive_restart()
{
return g_drv_no_primitive_restart_flag;
} }
void change_image_layout(VkCommandBuffer cmd, VkImage image, VkImageLayout current_layout, VkImageLayout new_layout, VkImageSubresourceRange range) void change_image_layout(VkCommandBuffer cmd, VkImage image, VkImageLayout current_layout, VkImageLayout new_layout, VkImageSubresourceRange range)

View File

@ -66,6 +66,8 @@ namespace vk
vk::render_device *get_current_renderer(); vk::render_device *get_current_renderer();
void set_current_renderer(const vk::render_device &device); void set_current_renderer(const vk::render_device &device);
bool emulate_primitive_restart();
VkComponentMapping default_component_map(); VkComponentMapping default_component_map();
VkImageSubresource default_image_subresource(); VkImageSubresource default_image_subresource();
VkImageSubresourceRange get_image_subresource_range(uint32_t base_layer, uint32_t base_mip, uint32_t layer_count, uint32_t level_count, VkImageAspectFlags aspect); VkImageSubresourceRange get_image_subresource_range(uint32_t base_layer, uint32_t base_mip, uint32_t layer_count, uint32_t level_count, VkImageAspectFlags aspect);

View File

@ -141,18 +141,43 @@ namespace
VkDeviceSize offset_in_index_buffer = m_index_buffer_ring_info.alloc<256>(upload_size); VkDeviceSize 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); void* buf = m_index_buffer_ring_info.map(offset_in_index_buffer, upload_size);
gsl::span<gsl::byte> dst;
std::vector<gsl::byte> tmp;
if (rsx::method_registers.restart_index_enabled() && vk::emulate_primitive_restart())
{
tmp.resize(upload_size);
dst = tmp;
}
else
{
dst = gsl::span<gsl::byte>(static_cast<gsl::byte*>(buf), upload_size);
}
/** /**
* Upload index (and expands it if primitive type is not natively supported). * Upload index (and expands it if primitive type is not natively supported).
*/ */
u32 min_index, max_index; u32 min_index, max_index;
std::tie(min_index, max_index) = write_index_array_data_to_buffer( std::tie(min_index, max_index) = write_index_array_data_to_buffer(
gsl::span<gsl::byte>(static_cast<gsl::byte*>(buf), index_count * type_size), dst,
command.raw_index_buffer, index_type, command.raw_index_buffer, index_type,
rsx::method_registers.current_draw_clause.primitive, rsx::method_registers.current_draw_clause.primitive,
rsx::method_registers.restart_index_enabled(), rsx::method_registers.restart_index_enabled(),
rsx::method_registers.restart_index(), command.ranges_to_fetch_in_index_buffer, rsx::method_registers.restart_index(), command.ranges_to_fetch_in_index_buffer,
[](auto prim) { return !vk::is_primitive_native(prim); }); [](auto prim) { return !vk::is_primitive_native(prim); });
if (rsx::method_registers.restart_index_enabled() && vk::emulate_primitive_restart())
{
//Emulate primitive restart by breaking up the draw calls
rsx::method_registers.current_draw_clause.alternate_first_count_commands.resize(0);
if (index_type == rsx::index_array_type::u16)
rsx::split_index_list(reinterpret_cast<u16*>(tmp.data()), index_count, UINT16_MAX, rsx::method_registers.current_draw_clause.alternate_first_count_commands);
else
rsx::split_index_list(reinterpret_cast<u32*>(tmp.data()), index_count, UINT32_MAX, rsx::method_registers.current_draw_clause.alternate_first_count_commands);
memcpy(buf, tmp.data(), tmp.size());
}
m_index_buffer_ring_info.unmap(); m_index_buffer_ring_info.unmap();
std::optional<std::tuple<VkDeviceSize, VkIndexType>> index_info = std::optional<std::tuple<VkDeviceSize, VkIndexType>> index_info =

View File

@ -38,6 +38,11 @@ namespace rsx
*/ */
std::vector<std::pair<u32, u32> > first_count_commands; std::vector<std::pair<u32, u32> > first_count_commands;
/**
* Optionally split first-count pairs for disjoint range rendering. Valid when emulating primitive restart
*/
std::vector<std::pair<u32, u32> > alternate_first_count_commands;
/** /**
* Returns how many vertex or index will be consumed by the draw clause. * Returns how many vertex or index will be consumed by the draw clause.
*/ */

View File

@ -251,4 +251,33 @@ namespace rsx
return result; return result;
} }
template <typename T>
void split_index_list(T* indices, int index_count, T restart_index, std::vector<std::pair<u32, u32>>& out)
{
int last_valid_index = -1;
int last_start = -1;
for (int i = 0; i < index_count; ++i)
{
if (indices[i] == UINT16_MAX)
{
if (last_start >= 0)
{
out.push_back(std::make_pair(last_start, i - last_start));
last_start = -1;
}
continue;
}
if (last_start < 0)
last_start = i;
last_valid_index = i;
}
if (last_start >= 0)
out.push_back(std::make_pair(last_start, last_valid_index - last_start + 1));
}
} }