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
{
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 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)
{
// 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;
}
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;
}
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>
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;
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;
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);
T index1 = tri_indexes[0];
if (is_primitive_restart_enabled && index1 == primitive_restart_index)
if (needs_anchor)
{
index1 = -1;
}
else
{
min_index = std::min(min_index, index1);
max_index = std::max(max_index, index1);
}
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);
if (is_primitive_restart_enabled && src[src_idx] == primitive_restart_index)
continue;
anchor = src[src_idx];
needs_anchor = false;
continue;
}
dst[dst_idx++] = index0;
dst[dst_idx++] = index1;
dst[dst_idx++] = index2;
src = src.subspan(2);
}
return std::make_tuple(min_index, max_index);
if (is_primitive_restart_enabled && src[src_idx] == primitive_restart_index)
{
needs_anchor = true;
last_index = invalid_index;
continue;
}
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, ::narrow<T>(dst_idx));
}
// FIXME: expanded primitive type may not support primitive restart correctly
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 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());
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 index0 = quad_indexes[0];
if (is_primitive_restart_enabled && index0 == primitive_restart_index)
T index = src[src_idx];
if (is_primitive_restart_enabled && index == primitive_restart_index)
{
index0 = -1;
}
else
{
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);
//empty temp buffer
set_size = 0;
continue;
}
tmp_indices[set_size++] = index;
max_index = std::max(max_index, index);
min_index = std::min(min_index, index);
if (set_size == 4)
{
// First triangle
dst[dst_idx++] = index0;
dst[dst_idx++] = index1;
dst[dst_idx++] = index2;
dst[dst_idx++] = tmp_indices[0];
dst[dst_idx++] = tmp_indices[1];
dst[dst_idx++] = tmp_indices[2];
// Second triangle
dst[dst_idx++] = index2;
dst[dst_idx++] = index3;
dst[dst_idx++] = index0;
dst[dst_idx++] = tmp_indices[2];
dst[dst_idx++] = tmp_indices[3];
dst[dst_idx++] = tmp_indices[0];
src = src.subspan(4);
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 ?
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,
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)
@ -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,
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)

View File

@ -29,10 +29,10 @@ u32 get_index_type_size(rsx::index_array_type type);
/**
* 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.
*/
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,
std::function<bool(rsx::primitive_type)> expands);

View File

@ -410,7 +410,7 @@ namespace
gsl::span<gsl::byte> dst{
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,
rsx::method_registers.current_draw_clause.primitive,
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 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);
}

View File

@ -51,7 +51,7 @@ namespace
u32 block_sz = vertex_draw_count * type_size;
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,
[](auto prim) { return !gl::is_primitive_native(prim); });

View File

@ -1842,16 +1842,17 @@ bool VKGSRender::check_program_status()
vk::pipeline_props properties = {};
bool unused;
bool emulated_primitive_type;
bool update_blend_constants = false;
bool update_stencil_info_back = false;
bool update_stencil_info_front = false;
bool update_depth_bounds = false;
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;
else
properties.ia.primitiveRestartEnable = VK_FALSE;

View File

@ -157,7 +157,7 @@ namespace
* 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(
std::tie(min_index, max_index, index_count) = write_index_array_data_to_buffer(
dst,
command.raw_index_buffer, index_type,
rsx::method_registers.current_draw_clause.primitive,