mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 19:45:20 +00:00
rsx/vk: Workaround for polaris primitive restart bug
This commit is contained in:
parent
5146f3ec47
commit
3d05e61f7e
6 changed files with 110 additions and 8 deletions
|
@ -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)
|
||||
{
|
||||
|
@ -1244,12 +1245,23 @@ void VKGSRender::end()
|
|||
}
|
||||
else
|
||||
{
|
||||
u32 first_vertex = 0;
|
||||
for (const auto &range : rsx::method_registers.current_draw_clause.first_count_commands)
|
||||
if (!is_emulated_restart)
|
||||
{
|
||||
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);
|
||||
first_vertex += verts;
|
||||
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, 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.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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue