java-topology/defects/melonds-0001/patch/melonds-0001.patch

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);
+}