mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 19:45:20 +00:00
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:
parent
3d05e61f7e
commit
89dcafbe41
7 changed files with 89 additions and 100 deletions
|
@ -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;
|
||||
if (is_primitive_restart_enabled && src[src_idx] == primitive_restart_index)
|
||||
{
|
||||
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>
|
||||
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;
|
||||
}
|
||||
|
||||
// First triangle
|
||||
dst[dst_idx++] = index0;
|
||||
dst[dst_idx++] = index1;
|
||||
dst[dst_idx++] = index2;
|
||||
// Second triangle
|
||||
dst[dst_idx++] = index2;
|
||||
dst[dst_idx++] = index3;
|
||||
dst[dst_idx++] = index0;
|
||||
tmp_indices[set_size++] = index;
|
||||
max_index = std::max(max_index, index);
|
||||
min_index = std::min(min_index, index);
|
||||
|
||||
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 ?
|
||||
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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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); });
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Reference in a new issue