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);
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)
{
@ -1243,15 +1244,26 @@ void VKGSRender::end()
vkCmdDrawIndexed(*m_current_command_buffer, index_count, 1, 0, 0, 0);
}
else
{
if (!is_emulated_restart)
{
u32 first_vertex = 0;
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);
vkCmdDrawIndexed(*m_current_command_buffer, verts, 1, 0, first_vertex, 0);
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);
}
}
}
}
vk::leave_uninterruptible();
@ -1839,7 +1851,7 @@ bool VKGSRender::check_program_status()
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);
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;
else
properties.ia.primitiveRestartEnable = VK_FALSE;

View File

@ -12,6 +12,7 @@ namespace vk
VkSampler g_null_sampler = nullptr;
bool g_cb_no_interrupt_flag = false;
bool g_drv_no_primitive_restart_flag = false;
u64 g_num_processed_frames = 0;
u64 g_num_total_frames = 0;
@ -257,6 +258,34 @@ namespace vk
void set_current_renderer(const vk::render_device &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)

View File

@ -66,6 +66,8 @@ namespace vk
vk::render_device *get_current_renderer();
void set_current_renderer(const vk::render_device &device);
bool emulate_primitive_restart();
VkComponentMapping default_component_map();
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);

View File

@ -141,18 +141,43 @@ namespace
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);
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).
*/
u32 min_index, max_index;
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,
rsx::method_registers.current_draw_clause.primitive,
rsx::method_registers.restart_index_enabled(),
rsx::method_registers.restart_index(), command.ranges_to_fetch_in_index_buffer,
[](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();
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;
/**
* 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.
*/

View File

@ -251,4 +251,33 @@ namespace rsx
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));
}
}