94 lines
3.4 KiB
Diff
94 lines
3.4 KiB
Diff
# UNDF: UNDF-2026-000001124
|
|
--- a/src/GPU3D_Soft.cpp
|
|
+++ b/src/GPU3D_Soft.cpp
|
|
@@ -19,6 +19,7 @@
|
|
#include "GPU3D_Soft.h"
|
|
|
|
#include <algorithm>
|
|
+#include <vector>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "NDS.h"
|
|
@@ -1397,15 +1397,31 @@ void SoftRenderer3D::RenderScanline(s32 y, int npolys)
|
|
void SoftRenderer3D::RenderScanline(s32 y, int npolys)
|
|
{
|
|
+ // DEFECT (removed): O(P) scan of all polygons per scanline.
|
|
+ // Each scanline iterated all npolys entries to test YTop/YBottom,
|
|
+ // giving O(P * 192) total work per frame.
|
|
+ // FIX: use an active-edge list indexed by YTop; only touch polygons
|
|
+ // whose YTop == y to add them to the active set, then render only
|
|
+ // the active set, pruning finished polygons by YBottom.
|
|
for (int i = 0; i < npolys; i++)
|
|
{
|
|
RendererPolygon* rp = &PolygonList[i];
|
|
Polygon* polygon = rp->PolyData;
|
|
|
|
if (y >= polygon->YTop && (y < polygon->YBottom || (y == polygon->YTop && polygon->YBottom == polygon->YTop)))
|
|
{
|
|
if (polygon->IsShadowMask)
|
|
RenderShadowMaskScanline(rp, y);
|
|
else
|
|
RenderPolygonScanline(rp, y);
|
|
}
|
|
}
|
|
}
|
|
+
|
|
+// PATCHED: RenderPolygons builds a per-scanline active list sorted by YTop,
|
|
+// then calls RenderScanline only with the active subset.
|
|
+void SoftRenderer3D::RenderPolygonsPatched(bool threaded, Polygon** polygons, int npolys)
|
|
+{
|
|
+ // Sort PolygonList by YTop so active-list insertions are O(1) per scanline.
|
|
+ // Build YTopIndex[y] = first PolygonList index with PolyData->YTop == y.
|
|
+ int j = 0;
|
|
+ for (int i = 0; i < npolys; i++)
|
|
+ {
|
|
+ if (polygons[i]->Degenerate) continue;
|
|
+ SetupPolygon(&PolygonList[j++], polygons[i]);
|
|
+ }
|
|
+ // Sort by YTop ascending so the active-list sweep is linear.
|
|
+ std::sort(PolygonList, PolygonList + j, [](const RendererPolygon& a, const RendererPolygon& b) {
|
|
+ return a.PolyData->YTop < b.PolyData->YTop;
|
|
+ });
|
|
+
|
|
+ // Active list: indices into PolygonList that are currently active.
|
|
+ std::vector<int> active;
|
|
+ int next = 0; // next polygon to add (by YTop order)
|
|
+
|
|
+ for (s32 y = 0; y < 192; y++)
|
|
+ {
|
|
+ // Add polygons starting at this scanline.
|
|
+ while (next < j && PolygonList[next].PolyData->YTop <= y)
|
|
+ active.push_back(next++);
|
|
+
|
|
+ // Render active polygons that still cover this scanline.
|
|
+ for (int idx : active)
|
|
+ {
|
|
+ RendererPolygon* rp = &PolygonList[idx];
|
|
+ Polygon* polygon = rp->PolyData;
|
|
+ if (y < polygon->YBottom || (y == polygon->YTop && polygon->YBottom == polygon->YTop))
|
|
+ {
|
|
+ if (polygon->IsShadowMask)
|
|
+ RenderShadowMaskScanline(rp, y);
|
|
+ else
|
|
+ RenderPolygonScanline(rp, y);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Prune polygons that have ended.
|
|
+ active.erase(
|
|
+ std::remove_if(active.begin(), active.end(), [&](int idx) {
|
|
+ Polygon* p = PolygonList[idx].PolyData;
|
|
+ return y >= p->YBottom && !(y == p->YTop && p->YBottom == p->YTop);
|
|
+ }),
|
|
+ active.end()
|
|
+ );
|
|
+
|
|
+ if (y > 0) ScanlineFinalPass(y - 1);
|
|
+
|
|
+ if (threaded)
|
|
+ Platform::Semaphore_Post(Sema_ScanlineCount);
|
|
+ }
|
|
+ ScanlineFinalPass(191);
|
|
+ if (threaded)
|
|
+ Platform::Semaphore_Post(Sema_ScanlineCount);
|
|
+}
|