rsx: Reimplement index buffer generation

- Emulate primitive restart in software whenever we get the chance
- Ensure PRIMITIVE_RESTART is never active when LIST topologies are active
- Reimplement TRIANGLE_FAN, POLYGON and QUAD expansion
This commit is contained in:
kd-11 2017-10-17 13:09:02 +03:00
parent 3d05e61f7e
commit 89dcafbe41
7 changed files with 89 additions and 100 deletions

View File

@ -456,7 +456,7 @@ void write_vertex_array_data_to_buffer(gsl::span<gsl::byte> raw_dst_span, gsl::s
namespace namespace
{ {
template<typename T> template<typename T>
std::tuple<T, T> upload_untouched(gsl::span<to_be_t<const T>> src, gsl::span<T> dst, bool is_primitive_restart_enabled, T primitive_restart_index) std::tuple<T, T, T> upload_untouched(gsl::span<to_be_t<const T>> src, gsl::span<T> dst, bool is_primitive_restart_enabled, T primitive_restart_index)
{ {
T min_index = -1; T min_index = -1;
T max_index = 0; T max_index = 0;
@ -468,6 +468,10 @@ std::tuple<T, T> upload_untouched(gsl::span<to_be_t<const T>> src, gsl::span<T>
{ {
if (is_primitive_restart_enabled && index == primitive_restart_index) if (is_primitive_restart_enabled && index == primitive_restart_index)
{ {
// List types do not need primitive restart. Just skip over this instead
if (rsx::method_registers.current_draw_clause.is_disjoint_primitive)
continue;
index = -1; index = -1;
} }
else else
@ -478,62 +482,68 @@ std::tuple<T, T> upload_untouched(gsl::span<to_be_t<const T>> src, gsl::span<T>
dst[dst_idx++] = index; dst[dst_idx++] = index;
} }
return std::make_tuple(min_index, max_index); return std::make_tuple(min_index, max_index, ::narrow<T>(dst_idx));
} }
// FIXME: expanded primitive type may not support primitive restart correctly
template<typename T> template<typename T>
std::tuple<T, T> expand_indexed_triangle_fan(gsl::span<to_be_t<const T>> src, gsl::span<T> dst, bool is_primitive_restart_enabled, T primitive_restart_index) std::tuple<T, T, T> expand_indexed_triangle_fan(gsl::span<to_be_t<const T>> src, gsl::span<T> dst, bool is_primitive_restart_enabled, T primitive_restart_index)
{ {
T min_index = -1; const T invalid_index = (T)-1;
T min_index = invalid_index;
T max_index = 0; T max_index = 0;
verify(HERE), (dst.size() >= 3 * (src.size() - 2)); verify(HERE), (dst.size() >= 3 * (src.size() - 2));
const T index0 = src[0];
if (!is_primitive_restart_enabled || index0 != -1) // Cut
{
min_index = std::min(min_index, index0);
max_index = std::max(max_index, index0);
}
size_t dst_idx = 0; size_t dst_idx = 0;
while (src.size() > 2) size_t src_idx = 0;
bool needs_anchor = true;
T anchor = invalid_index;
T last_index = invalid_index;
for (size_t src_idx = 0; src_idx < src.size(); ++src_idx)
{ {
gsl::span<to_be_t<const T>> tri_indexes = src.subspan(0, 2); if (needs_anchor)
T index1 = tri_indexes[0];
if (is_primitive_restart_enabled && index1 == primitive_restart_index)
{ {
index1 = -1; if (is_primitive_restart_enabled && src[src_idx] == primitive_restart_index)
} continue;
else
{ anchor = src[src_idx];
min_index = std::min(min_index, index1); needs_anchor = false;
max_index = std::max(max_index, index1); continue;
}
T index2 = tri_indexes[1];
if (is_primitive_restart_enabled && index2 == primitive_restart_index)
{
index2 = -1;
}
else
{
min_index = std::min(min_index, index2);
max_index = std::max(max_index, index2);
} }
dst[dst_idx++] = index0; if (is_primitive_restart_enabled && src[src_idx] == primitive_restart_index)
dst[dst_idx++] = index1; {
dst[dst_idx++] = index2; needs_anchor = true;
last_index = invalid_index;
continue;
}
src = src.subspan(2); T index = src[src_idx];
max_index = std::max(max_index, index);
min_index = std::min(min_index, index);
if (last_index == invalid_index)
{
//Need at least one anchor and one outer index to create a triange
last_index = index;
continue;
}
dst[dst_idx++] = anchor;
dst[dst_idx++] = last_index;
dst[dst_idx++] = index;
last_index = index;
} }
return std::make_tuple(min_index, max_index);
return std::make_tuple(min_index, max_index, ::narrow<T>(dst_idx));
} }
// FIXME: expanded primitive type may not support primitive restart correctly
template<typename T> template<typename T>
std::tuple<T, T> expand_indexed_quads(gsl::span<to_be_t<const T>> src, gsl::span<T> dst, bool is_primitive_restart_enabled, T primitive_restart_index) std::tuple<T, T, T> expand_indexed_quads(gsl::span<to_be_t<const T>> src, gsl::span<T> dst, bool is_primitive_restart_enabled, T primitive_restart_index)
{ {
T min_index = -1; T min_index = -1;
T max_index = 0; T max_index = 0;
@ -541,62 +551,39 @@ std::tuple<T, T> expand_indexed_quads(gsl::span<to_be_t<const T>> src, gsl::span
verify(HERE), (4 * dst.size_bytes() >= 6 * src.size_bytes()); verify(HERE), (4 * dst.size_bytes() >= 6 * src.size_bytes());
size_t dst_idx = 0; size_t dst_idx = 0;
while (!src.empty()) size_t set_size = 0;
T tmp_indices[4];
for (int src_idx = 0; src_idx < src.size(); ++src_idx)
{ {
gsl::span<to_be_t<const T>> quad_indexes = src.subspan(0, 4); T index = src[src_idx];
T index0 = quad_indexes[0]; if (is_primitive_restart_enabled && index == primitive_restart_index)
if (is_primitive_restart_enabled && index0 == primitive_restart_index)
{ {
index0 = -1; //empty temp buffer
} set_size = 0;
else continue;
{
min_index = std::min(min_index, index0);
max_index = std::max(max_index, index0);
}
T index1 = quad_indexes[1];
if (is_primitive_restart_enabled && index1 == primitive_restart_index)
{
index1 = -1;
}
else
{
min_index = std::min(min_index, index1);
max_index = std::max(max_index, index1);
}
T index2 = quad_indexes[2];
if (is_primitive_restart_enabled && index2 == primitive_restart_index)
{
index2 = -1;
}
else
{
min_index = std::min(min_index, index2);
max_index = std::max(max_index, index2);
}
T index3 = quad_indexes[3];
if (is_primitive_restart_enabled &&index3 == primitive_restart_index)
{
index3 = -1;
}
else
{
min_index = std::min(min_index, index3);
max_index = std::max(max_index, index3);
} }
// First triangle tmp_indices[set_size++] = index;
dst[dst_idx++] = index0; max_index = std::max(max_index, index);
dst[dst_idx++] = index1; min_index = std::min(min_index, index);
dst[dst_idx++] = index2;
// Second triangle
dst[dst_idx++] = index2;
dst[dst_idx++] = index3;
dst[dst_idx++] = index0;
src = src.subspan(4); if (set_size == 4)
{
// First triangle
dst[dst_idx++] = tmp_indices[0];
dst[dst_idx++] = tmp_indices[1];
dst[dst_idx++] = tmp_indices[2];
// Second triangle
dst[dst_idx++] = tmp_indices[2];
dst[dst_idx++] = tmp_indices[3];
dst[dst_idx++] = tmp_indices[0];
set_size = 0;
}
} }
return std::make_tuple(min_index, max_index);
return std::make_tuple(min_index, max_index, ::narrow<T>(dst_idx));
} }
} }
@ -714,7 +701,7 @@ namespace
// TODO: Unify indexed and non indexed primitive expansion ? // TODO: Unify indexed and non indexed primitive expansion ?
template<typename T> template<typename T>
std::tuple<T, T> write_index_array_data_to_buffer_impl(gsl::span<T> dst, std::tuple<T, T, T> write_index_array_data_to_buffer_impl(gsl::span<T> dst,
gsl::span<const be_t<T>> src, gsl::span<const be_t<T>> src,
rsx::primitive_type draw_mode, bool restart_index_enabled, u32 restart_index, const std::vector<std::pair<u32, u32> > &first_count_arguments, rsx::primitive_type draw_mode, bool restart_index_enabled, u32 restart_index, const std::vector<std::pair<u32, u32> > &first_count_arguments,
std::function<bool(rsx::primitive_type)> expands) std::function<bool(rsx::primitive_type)> expands)
@ -743,7 +730,7 @@ namespace
} }
} }
std::tuple<u32, u32> write_index_array_data_to_buffer(gsl::span<gsl::byte> dst, std::tuple<u32, u32, u32> write_index_array_data_to_buffer(gsl::span<gsl::byte> dst,
gsl::span<const gsl::byte> src, gsl::span<const gsl::byte> src,
rsx::index_array_type type, rsx::primitive_type draw_mode, bool restart_index_enabled, u32 restart_index, const std::vector<std::pair<u32, u32> > &first_count_arguments, rsx::index_array_type type, rsx::primitive_type draw_mode, bool restart_index_enabled, u32 restart_index, const std::vector<std::pair<u32, u32> > &first_count_arguments,
std::function<bool(rsx::primitive_type)> expands) std::function<bool(rsx::primitive_type)> expands)

View File

@ -29,10 +29,10 @@ u32 get_index_type_size(rsx::index_array_type type);
/** /**
* Write count indexes using (first, first + count) ranges. * Write count indexes using (first, first + count) ranges.
* Returns min/max index found during the process. * Returns min/max index found during the process and the number of valid indices written to the buffer.
* The function expands index buffer for non native primitive type if expands(draw_mode) return true. * The function expands index buffer for non native primitive type if expands(draw_mode) return true.
*/ */
std::tuple<u32, u32> write_index_array_data_to_buffer(gsl::span<gsl::byte> dst, gsl::span<const gsl::byte> src, std::tuple<u32, u32, u32> write_index_array_data_to_buffer(gsl::span<gsl::byte> dst, gsl::span<const gsl::byte> src,
rsx::index_array_type, rsx::primitive_type draw_mode, bool restart_index_enabled, u32 restart_index, const std::vector<std::pair<u32, u32> > &first_count_arguments, rsx::index_array_type, rsx::primitive_type draw_mode, bool restart_index_enabled, u32 restart_index, const std::vector<std::pair<u32, u32> > &first_count_arguments,
std::function<bool(rsx::primitive_type)> expands); std::function<bool(rsx::primitive_type)> expands);

View File

@ -410,7 +410,7 @@ namespace
gsl::span<gsl::byte> dst{ gsl::span<gsl::byte> dst{
reinterpret_cast<gsl::byte*>(mapped_buffer), ::narrow<u32>(buffer_size)}; reinterpret_cast<gsl::byte*>(mapped_buffer), ::narrow<u32>(buffer_size)};
std::tie(min_index, max_index) = std::tie(min_index, max_index, index_count) =
write_index_array_data_to_buffer(dst, command.raw_index_buffer, indexed_type, write_index_array_data_to_buffer(dst, command.raw_index_buffer, indexed_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(),

View File

@ -503,8 +503,9 @@ void GLGSRender::end()
{ {
const GLenum index_type = std::get<0>(indexed_draw_info.value()); const GLenum index_type = std::get<0>(indexed_draw_info.value());
const u32 index_offset = std::get<1>(indexed_draw_info.value()); const u32 index_offset = std::get<1>(indexed_draw_info.value());
const bool restarts_valid = gl::is_primitive_native(rsx::method_registers.current_draw_clause.primitive) && !rsx::method_registers.current_draw_clause.is_disjoint_primitive;
if (gl_state.enable(rsx::method_registers.restart_index_enabled(), GL_PRIMITIVE_RESTART)) if (gl_state.enable(restarts_valid && rsx::method_registers.restart_index_enabled(), GL_PRIMITIVE_RESTART))
{ {
glPrimitiveRestartIndex((index_type == GL_UNSIGNED_SHORT)? 0xffff: 0xffffffff); glPrimitiveRestartIndex((index_type == GL_UNSIGNED_SHORT)? 0xffff: 0xffffffff);
} }

View File

@ -51,7 +51,7 @@ namespace
u32 block_sz = vertex_draw_count * type_size; u32 block_sz = vertex_draw_count * type_size;
gsl::span<gsl::byte> dst{ reinterpret_cast<gsl::byte*>(ptr), ::narrow<u32>(block_sz) }; gsl::span<gsl::byte> dst{ reinterpret_cast<gsl::byte*>(ptr), ::narrow<u32>(block_sz) };
std::tie(min_index, max_index) = write_index_array_data_to_buffer(dst, raw_index_buffer, std::tie(min_index, max_index, vertex_draw_count) = write_index_array_data_to_buffer(dst, raw_index_buffer,
type, draw_mode, rsx::method_registers.restart_index_enabled(), rsx::method_registers.restart_index(), first_count_commands, type, draw_mode, rsx::method_registers.restart_index_enabled(), rsx::method_registers.restart_index(), first_count_commands,
[](auto prim) { return !gl::is_primitive_native(prim); }); [](auto prim) { return !gl::is_primitive_native(prim); });

View File

@ -1842,16 +1842,17 @@ bool VKGSRender::check_program_status()
vk::pipeline_props properties = {}; vk::pipeline_props properties = {};
bool unused; bool emulated_primitive_type;
bool update_blend_constants = false; bool update_blend_constants = false;
bool update_stencil_info_back = false; bool update_stencil_info_back = false;
bool update_stencil_info_front = false; bool update_stencil_info_front = false;
bool update_depth_bounds = false; bool update_depth_bounds = false;
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, emulated_primitive_type);
if (rsx::method_registers.current_draw_clause.command == rsx::draw_command::indexed && rsx::method_registers.restart_index_enabled() && !vk::emulate_primitive_restart()) const bool restarts_valid = rsx::method_registers.current_draw_clause.command == rsx::draw_command::indexed && !emulated_primitive_type && !rsx::method_registers.current_draw_clause.is_disjoint_primitive;
if (rsx::method_registers.restart_index_enabled() && !vk::emulate_primitive_restart() && restarts_valid)
properties.ia.primitiveRestartEnable = VK_TRUE; properties.ia.primitiveRestartEnable = VK_TRUE;
else else
properties.ia.primitiveRestartEnable = VK_FALSE; properties.ia.primitiveRestartEnable = VK_FALSE;

View File

@ -157,7 +157,7 @@ namespace
* 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, index_count) = write_index_array_data_to_buffer(
dst, 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,