Skip to content

Commit 5d4f669

Browse files
fix(sortingrenderer): Prevent a crash when exceeding the 16-bit index buffer limit (TheSuperHackers#2783)
1 parent 0e7f686 commit 5d4f669

1 file changed

Lines changed: 45 additions & 53 deletions

File tree

Core/Libraries/Source/WWVegas/WW3D2/sortingrenderer.cpp

Lines changed: 45 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -508,51 +508,58 @@ void SortingRendererClass::Flush_Sorting_Pool()
508508

509509
Sort(tis, tis + overlapping_polygon_count);
510510

511-
/* ///@todo: Add code to break up rendering into multiple index buffer fills to allow more than 65536/3 triangles. -MW
512-
int total_overlapping_polygon_count = overlapping_polygon_count;
513-
while ( > 0)
511+
// TheSuperHackers @fix stephanmeesters 10/06/2026
512+
// Split rendering into chunks to prevent a crash when exceeding the 16-bit index buffer limit.
513+
constexpr const unsigned MAX_INDEX_CHUNK = 65535;
514+
unsigned chunkOffset = 0;
515+
while (chunkOffset < overlapping_polygon_count)
514516
{
515-
if ((total_overlapping_polygon_count*3) > 65535)
516-
{ //overflowed the index buffer, must break into multiple batches
517-
overlapping_polygon_count = 65535/3;
517+
unsigned chunkCount = overlapping_polygon_count - chunkOffset;
518+
if (chunkCount * 3 > MAX_INDEX_CHUNK) {
519+
chunkCount = MAX_INDEX_CHUNK / 3;
518520
}
519-
else
520-
overlapping_polygon_count = total_overlapping_polygon_count;
521+
const unsigned chunkEnd = chunkOffset + chunkCount;
521522

522-
//insert rendering code here!!
523+
DynamicIBAccessClass dyn_ib_access(BUFFER_TYPE_DYNAMIC_DX8,chunkCount*3);
524+
{
525+
DynamicIBAccessClass::WriteLockClass lock(&dyn_ib_access);
526+
ShortVectorIStruct* sorted_polygon_index_array=(ShortVectorIStruct*)lock.Get_Index_Array();
523527

524-
total_overlapping_polygon_count -= overlapping_polygon_count;
525-
}
526-
*/
527-
unsigned polygonAllocCount = overlapping_polygon_count;
528-
if ((unsigned)(DynamicIBAccessClass::Get_Default_Index_Count()/3) < DEFAULT_SORTING_POLY_COUNT)
529-
polygonAllocCount = DEFAULT_SORTING_POLY_COUNT; //make sure that we force the DX8 index buffer to maximum size
530-
if (overlapping_polygon_count > polygonAllocCount)
531-
polygonAllocCount = overlapping_polygon_count;
532-
WWASSERT(DEFAULT_SORTING_POLY_COUNT <= 1 || polygonAllocCount <= DEFAULT_SORTING_POLY_COUNT);
533-
534-
DynamicIBAccessClass dyn_ib_access(BUFFER_TYPE_DYNAMIC_DX8,polygonAllocCount*3);
535-
{
536-
DynamicIBAccessClass::WriteLockClass lock(&dyn_ib_access);
537-
ShortVectorIStruct* sorted_polygon_index_array=(ShortVectorIStruct*)lock.Get_Index_Array();
538-
539-
for (unsigned a=0;a<overlapping_polygon_count;++a) {
540-
sorted_polygon_index_array[a]=tis[a].tri;
528+
for (unsigned a=0;a<chunkCount;++a) {
529+
sorted_polygon_index_array[a]=tis[chunkOffset + a].tri;
530+
}
541531
}
542-
}
543532

544-
// Set index buffer and render!
533+
// Set index buffer and render!
534+
535+
DX8Wrapper::Set_Index_Buffer(dyn_ib_access,0); // Override with this buffer (do something to prevent need for this!)
536+
DX8Wrapper::Set_Vertex_Buffer(dyn_vb_access); // Override with this buffer (do something to prevent need for this!)
537+
538+
DX8Wrapper::Apply_Render_State_Changes();
545539

546-
DX8Wrapper::Set_Index_Buffer(dyn_ib_access,0); // Override with this buffer (do something to prevent need for this!)
547-
DX8Wrapper::Set_Vertex_Buffer(dyn_vb_access); // Override with this buffer (do something to prevent need for this!)
540+
unsigned count_to_render=1;
541+
unsigned start_index=0;
542+
unsigned node_id=tis[chunkOffset].idx;
543+
for (unsigned i=chunkOffset + 1;i<chunkEnd;++i) {
544+
if (node_id!=tis[i].idx) {
545+
SortingNodeStruct* state=overlapping_nodes[node_id];
546+
Apply_Render_State(state->sorting_state);
548547

549-
DX8Wrapper::Apply_Render_State_Changes();
548+
DX8Wrapper::Draw_Triangles(
549+
start_index*3,
550+
count_to_render,
551+
state->min_vertex_index,
552+
state->vertex_count);
550553

551-
unsigned count_to_render=1;
552-
unsigned start_index=0;
553-
unsigned node_id=tis[0].idx;
554-
for (unsigned i=1;i<overlapping_polygon_count;++i) {
555-
if (node_id!=tis[i].idx) {
554+
count_to_render=0;
555+
start_index=i - chunkOffset;
556+
node_id=tis[i].idx;
557+
}
558+
count_to_render++; //keep track of number of polygons of same kind
559+
}
560+
561+
// Render any remaining polygons...
562+
if (count_to_render) {
556563
SortingNodeStruct* state=overlapping_nodes[node_id];
557564
Apply_Render_State(state->sorting_state);
558565

@@ -561,28 +568,13 @@ void SortingRendererClass::Flush_Sorting_Pool()
561568
count_to_render,
562569
state->min_vertex_index,
563570
state->vertex_count);
564-
565-
count_to_render=0;
566-
start_index=i;
567-
node_id=tis[i].idx;
568571
}
569-
count_to_render++; //keep track of number of polygons of same kind
570-
}
571-
572-
// Render any remaining polygons...
573-
if (count_to_render) {
574-
SortingNodeStruct* state=overlapping_nodes[node_id];
575-
Apply_Render_State(state->sorting_state);
576572

577-
DX8Wrapper::Draw_Triangles(
578-
start_index*3,
579-
count_to_render,
580-
state->min_vertex_index,
581-
state->vertex_count);
573+
chunkOffset += chunkCount;
582574
}
583575

584576
// Release all references and return nodes back to the clean list for the frame...
585-
for (node_id=0;node_id<overlapping_node_count;++node_id) {
577+
for (unsigned node_id=0;node_id<overlapping_node_count;++node_id) {
586578
SortingNodeStruct* state=overlapping_nodes[node_id];
587579
Release_Refs(state);
588580
clean_list.Add_Head(state);

0 commit comments

Comments
 (0)