mirror of
https://github.com/izzy2lost/xenia-edge.git
synced 2026-07-06 00:20:26 -07:00
[GPU/Debug] Add logic and cvar to convert triangle strips to lists
This commit is contained in:
@@ -45,6 +45,11 @@ DEFINE_bool(
|
||||
"May also be useful for graphics debugging when the debugger doesn't "
|
||||
"display the geometry generated by geometry shaders properly.",
|
||||
"GPU");
|
||||
DEFINE_bool(
|
||||
force_convert_triangle_strips_to_lists, false,
|
||||
"Force CPU conversion of triangle strips to triangle lists. This may help "
|
||||
"diagnose rendering issues related to triangle strip handling.",
|
||||
"GPU");
|
||||
DEFINE_bool(
|
||||
ignore_32bit_vertex_index_support, false,
|
||||
"For host graphics API downlevel testing only (useful only for Qualcomm "
|
||||
@@ -115,6 +120,10 @@ bool PrimitiveProcessor::InitializeCommon(
|
||||
convert_quad_lists_to_triangle_lists_ =
|
||||
!quad_lists_supported ||
|
||||
cvars::force_convert_quad_lists_to_triangle_lists;
|
||||
// Triangle strips are supported natively on all backends, but can be forced
|
||||
// to convert to lists for debugging purposes.
|
||||
convert_triangle_strips_to_lists_ =
|
||||
cvars::force_convert_triangle_strips_to_lists;
|
||||
// No override cvars as hosts are not required to support the fallback paths
|
||||
// since they require different vertex shader structure (for the fallback
|
||||
// HostVertexShaderTypes).
|
||||
@@ -170,6 +179,13 @@ bool PrimitiveProcessor::InitializeCommon(
|
||||
} else {
|
||||
builtin_ib_offset_quad_lists_to_triangle_lists_ = SIZE_MAX;
|
||||
}
|
||||
if (convert_triangle_strips_to_lists_) {
|
||||
builtin_ib_offset_triangle_strips_to_lists_ = builtin_index_buffer_size;
|
||||
builtin_index_buffer_size +=
|
||||
sizeof(uint16_t) * GetTriangleStripListIndexCount(UINT16_MAX);
|
||||
} else {
|
||||
builtin_ib_offset_triangle_strips_to_lists_ = SIZE_MAX;
|
||||
}
|
||||
if (builtin_index_buffer_size) {
|
||||
if (!InitializeBuiltinIndexBuffer(
|
||||
builtin_index_buffer_size,
|
||||
@@ -228,6 +244,28 @@ bool PrimitiveProcessor::InitializeCommon(
|
||||
*(triangle_list_ptr++) = quad_first_index + 3;
|
||||
}
|
||||
}
|
||||
if (builtin_ib_offset_triangle_strips_to_lists_ != SIZE_MAX) {
|
||||
// Triangle strip to triangle list conversion.
|
||||
// For each triangle in the strip (starting at vertex 2), emit
|
||||
// 3 indices. Winding order alternates for each triangle.
|
||||
uint16_t* triangle_list_ptr =
|
||||
mapping_16bit +
|
||||
builtin_ib_offset_triangle_strips_to_lists_ /
|
||||
sizeof(uint16_t);
|
||||
for (uint32_t i = 2; i < UINT16_MAX; ++i) {
|
||||
if ((i & 1) == 0) {
|
||||
// Even triangle: v0, v1, v2
|
||||
*(triangle_list_ptr++) = uint16_t(i - 2);
|
||||
*(triangle_list_ptr++) = uint16_t(i - 1);
|
||||
*(triangle_list_ptr++) = uint16_t(i);
|
||||
} else {
|
||||
// Odd triangle: v1, v0, v2 (swapped to maintain winding)
|
||||
*(triangle_list_ptr++) = uint16_t(i - 1);
|
||||
*(triangle_list_ptr++) = uint16_t(i - 2);
|
||||
*(triangle_list_ptr++) = uint16_t(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
})) {
|
||||
ShutdownCommon();
|
||||
return false;
|
||||
@@ -383,9 +421,13 @@ bool PrimitiveProcessor::Process(ProcessingResult& result_out) {
|
||||
case xenos::PrimitiveType::kLineList:
|
||||
case xenos::PrimitiveType::kLineStrip:
|
||||
case xenos::PrimitiveType::kTriangleList:
|
||||
case xenos::PrimitiveType::kTriangleStrip:
|
||||
// Supported natively on all backends.
|
||||
break;
|
||||
case xenos::PrimitiveType::kTriangleStrip:
|
||||
if (convert_triangle_strips_to_lists_) {
|
||||
host_primitive_type = xenos::PrimitiveType::kTriangleList;
|
||||
}
|
||||
break;
|
||||
case xenos::PrimitiveType::kRectangleList:
|
||||
if (expand_rectangle_lists_in_vs_) {
|
||||
host_primitive_type = xenos::PrimitiveType::kTriangleStrip;
|
||||
@@ -563,6 +605,17 @@ bool PrimitiveProcessor::Process(ProcessingResult& result_out) {
|
||||
cacheable.host_index_buffer_handle =
|
||||
builtin_ib_offset_quad_lists_to_triangle_lists_;
|
||||
break;
|
||||
case xenos::PrimitiveType::kTriangleStrip:
|
||||
assert_true(host_primitive_type ==
|
||||
xenos::PrimitiveType::kTriangleList);
|
||||
cacheable.host_draw_vertex_count =
|
||||
GetTriangleStripListIndexCount(cacheable.host_draw_vertex_count);
|
||||
cacheable.index_buffer_type =
|
||||
ProcessedIndexBufferType::kHostBuiltinForAuto;
|
||||
assert_true(builtin_ib_offset_triangle_strips_to_lists_ != SIZE_MAX);
|
||||
cacheable.host_index_buffer_handle =
|
||||
builtin_ib_offset_triangle_strips_to_lists_;
|
||||
break;
|
||||
default:
|
||||
assert_always();
|
||||
return false;
|
||||
@@ -701,6 +754,9 @@ bool PrimitiveProcessor::Process(ProcessingResult& result_out) {
|
||||
case xenos::PrimitiveType::kQuadList:
|
||||
host_index_count_getter = GetQuadListTriangleListIndexCount;
|
||||
break;
|
||||
case xenos::PrimitiveType::kTriangleStrip:
|
||||
host_index_count_getter = GetTriangleStripListIndexCount;
|
||||
break;
|
||||
default:
|
||||
assert_unhandled_case(guest_primitive_type);
|
||||
return false;
|
||||
|
||||
@@ -170,6 +170,9 @@ class PrimitiveProcessor {
|
||||
bool IsConvertingQuadListsToTriangleLists() const {
|
||||
return convert_quad_lists_to_triangle_lists_;
|
||||
}
|
||||
bool IsConvertingTriangleStripsToLists() const {
|
||||
return convert_triangle_strips_to_lists_;
|
||||
}
|
||||
bool IsExpandingPointSpritesInVS() const {
|
||||
return expand_point_sprites_in_vs_;
|
||||
}
|
||||
@@ -623,6 +626,43 @@ class PrimitiveProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
// Triangle strip to triangle list conversion.
|
||||
// A strip with N vertices produces (N-2) triangles, each needing 3 indices.
|
||||
static constexpr uint32_t GetTriangleStripListIndexCount(
|
||||
uint32_t strip_index_count) {
|
||||
return strip_index_count > 2 ? (strip_index_count - 2) * 3 : 0;
|
||||
}
|
||||
template <typename Index, typename IndexTransform>
|
||||
static void TriangleStripToList(Index* dest, const Index* source,
|
||||
uint32_t source_index_count,
|
||||
const IndexTransform& index_transform) {
|
||||
if (source_index_count <= 2) {
|
||||
// To match GetTriangleStripListIndexCount.
|
||||
return;
|
||||
}
|
||||
// For triangle strips, the winding order alternates for each triangle.
|
||||
// Even triangles: v0, v1, v2
|
||||
// Odd triangles: v1, v0, v2 (swapped to maintain consistent winding)
|
||||
Index v0 = index_transform(source[0]);
|
||||
Index v1 = index_transform(source[1]);
|
||||
for (uint32_t i = 2; i < source_index_count; ++i) {
|
||||
Index v2 = index_transform(source[i]);
|
||||
if ((i & 1) == 0) {
|
||||
// Even triangle (0, 2, 4, ...): v0, v1, v2
|
||||
*(dest++) = v0;
|
||||
*(dest++) = v1;
|
||||
*(dest++) = v2;
|
||||
} else {
|
||||
// Odd triangle (1, 3, 5, ...): v1, v0, v2 to maintain winding
|
||||
*(dest++) = v1;
|
||||
*(dest++) = v0;
|
||||
*(dest++) = v2;
|
||||
}
|
||||
v0 = v1;
|
||||
v1 = v2;
|
||||
}
|
||||
}
|
||||
|
||||
// Pre-gathering the ranges allows for usage of the same functions for
|
||||
// conversion with and without reset. In addition, this increases safety in
|
||||
// weird cases - there won't be mismatch between the pre-calculation of the
|
||||
@@ -685,6 +725,14 @@ class PrimitiveProcessor {
|
||||
dest_write_ptr += range_it->host_index_count;
|
||||
}
|
||||
break;
|
||||
case xenos::PrimitiveType::kTriangleStrip:
|
||||
for (PrimitiveRangeIterator range_it = ranges_beginning;
|
||||
range_it != ranges_end; ++range_it) {
|
||||
TriangleStripToList(dest_write_ptr, source + range_it->guest_offset,
|
||||
range_it->guest_index_count, index_transform);
|
||||
dest_write_ptr += range_it->host_index_count;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert_unhandled_case(source_primitive_type);
|
||||
}
|
||||
@@ -699,6 +747,7 @@ class PrimitiveProcessor {
|
||||
bool convert_triangle_fans_to_lists_ = false;
|
||||
bool convert_line_loops_to_strips_ = false;
|
||||
bool convert_quad_lists_to_triangle_lists_ = false;
|
||||
bool convert_triangle_strips_to_lists_ = false;
|
||||
bool expand_point_sprites_in_vs_ = false;
|
||||
bool expand_rectangle_lists_in_vs_ = false;
|
||||
|
||||
@@ -706,6 +755,7 @@ class PrimitiveProcessor {
|
||||
size_t builtin_ib_offset_two_triangle_strips_ = SIZE_MAX;
|
||||
size_t builtin_ib_offset_triangle_fans_to_lists_ = SIZE_MAX;
|
||||
size_t builtin_ib_offset_quad_lists_to_triangle_lists_ = SIZE_MAX;
|
||||
size_t builtin_ib_offset_triangle_strips_to_lists_ = SIZE_MAX;
|
||||
|
||||
std::deque<SinglePrimitiveRange> single_primitive_ranges_;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user