DS GX: Avoid sorting spans

This commit is contained in:
Vicki Pfau 2017-03-04 15:04:24 -08:00
parent 2da8c63ec2
commit 1ed7db5c9c
2 changed files with 32 additions and 69 deletions

View File

@ -76,7 +76,7 @@ struct DSGXSoftwareRenderer {
struct DSGXSoftwareSpanList activeSpans; struct DSGXSoftwareSpanList activeSpans;
struct DSGXSoftwareSpan** bucket; struct DSGXSoftwareSpan** bucket;
uint16_t depthBuffer[DS_VIDEO_HORIZONTAL_PIXELS]; int32_t depthBuffer[DS_VIDEO_HORIZONTAL_PIXELS];
color_t* scanlineCache; color_t* scanlineCache;
bool flushPending; bool flushPending;
bool wSort; bool wSort;

View File

@ -195,26 +195,6 @@ static bool _edgeToSpan(struct DSGXSoftwareSpan* span, const struct DSGXSoftware
return true; return true;
} }
static int _spanSort(const void* a, const void* b) {
const struct DSGXSoftwareSpan* sa = a;
const struct DSGXSoftwareSpan* sb = b;
// Sort backwards
if (sa->ep[0].x < sb->ep[0].x) {
return 1;
}
if (sa->ep[0].x > sb->ep[0].x) {
return -1;
}
if (sa->ep[0].w < sb->ep[0].w) {
return 1;
}
if (sa->ep[0].w > sb->ep[0].w) {
return -1;
}
return 0;
}
static void _lerpEndpoint(const struct DSGXSoftwareSpan* span, struct DSGXSoftwareEndpoint* ep, unsigned x) { static void _lerpEndpoint(const struct DSGXSoftwareSpan* span, struct DSGXSoftwareEndpoint* ep, unsigned x) {
int64_t width = span->ep[1].x - span->ep[0].x; int64_t width = span->ep[1].x - span->ep[0].x;
int64_t xw = ((uint64_t) x << 12) - span->ep[0].x; int64_t xw = ((uint64_t) x << 12) - span->ep[0].x;
@ -415,7 +395,7 @@ static void DSGXSoftwareRendererDrawScanline(struct DSGXRenderer* renderer, int
} }
DSGXSoftwareSpanListClear(&softwareRenderer->activeSpans); DSGXSoftwareSpanListClear(&softwareRenderer->activeSpans);
memset(softwareRenderer->bucket, 0, sizeof(*softwareRenderer->bucket) * DS_GX_POLYGON_BUFFER_SIZE); memset(softwareRenderer->bucket, 0, sizeof(*softwareRenderer->bucket) * DS_GX_POLYGON_BUFFER_SIZE);
int i; size_t i;
for (i = DSGXSoftwareEdgeListSize(&softwareRenderer->activeEdges); i; --i) { for (i = DSGXSoftwareEdgeListSize(&softwareRenderer->activeEdges); i; --i) {
size_t idx = i - 1; size_t idx = i - 1;
struct DSGXSoftwareEdge* edge = DSGXSoftwareEdgeListGetPointer(&softwareRenderer->activeEdges, idx); struct DSGXSoftwareEdge* edge = DSGXSoftwareEdgeListGetPointer(&softwareRenderer->activeEdges, idx);
@ -443,61 +423,44 @@ static void DSGXSoftwareRendererDrawScanline(struct DSGXRenderer* renderer, int
} }
} }
} }
qsort(DSGXSoftwareSpanListGetPointer(&softwareRenderer->activeSpans, 0), DSGXSoftwareSpanListSize(&softwareRenderer->activeSpans), sizeof(struct DSGXSoftwareSpan), _spanSort);
color_t* scanline = &softwareRenderer->scanlineCache[DS_VIDEO_HORIZONTAL_PIXELS * y]; color_t* scanline = &softwareRenderer->scanlineCache[DS_VIDEO_HORIZONTAL_PIXELS * y];
memset(scanline, 0, sizeof(color_t) * DS_VIDEO_HORIZONTAL_PIXELS);
for (i = 0; i < DS_VIDEO_HORIZONTAL_PIXELS; i += 4) {
softwareRenderer->depthBuffer[i] = INT32_MAX;
softwareRenderer->depthBuffer[i + 1] = INT32_MAX;
softwareRenderer->depthBuffer[i + 2] = INT32_MAX;
softwareRenderer->depthBuffer[i + 3] = INT32_MAX;
}
int nextSpanX = DS_VIDEO_HORIZONTAL_PIXELS; for (i = 0; i < DSGXSoftwareSpanListSize(&softwareRenderer->activeSpans); ++i) {
if (DSGXSoftwareSpanListSize(&softwareRenderer->activeSpans)) { struct DSGXSoftwareSpan* span = DSGXSoftwareSpanListGetPointer(&softwareRenderer->activeSpans, i);
nextSpanX = DSGXSoftwareSpanListGetPointer(&softwareRenderer->activeSpans, DSGXSoftwareSpanListSize(&softwareRenderer->activeSpans) - 1)->ep[0].x;
nextSpanX >>= 12; int32_t x = span->ep[0].x >> 12;
if (x < 0) {
x = 0;
} }
for (i = 0; i < DS_VIDEO_HORIZONTAL_PIXELS; ++i) { for (; x < span->ep[1].x >> 12 && x < DS_VIDEO_HORIZONTAL_PIXELS; ++x) {
struct DSGXSoftwareSpan* span = NULL;
struct DSGXSoftwareEndpoint ep; struct DSGXSoftwareEndpoint ep;
int32_t depth = INT32_MAX; _lerpEndpoint(span, &ep, x);
scanline[i] = 0;
if (i >= nextSpanX) {
size_t nextSpanId = DSGXSoftwareSpanListSize(&softwareRenderer->activeSpans);
span = DSGXSoftwareSpanListGetPointer(&softwareRenderer->activeSpans, nextSpanId - 1);
while (i > (span->ep[1].x >> 12) || !span->ep[1].x) {
DSGXSoftwareSpanListShift(&softwareRenderer->activeSpans, nextSpanId - 1, 1);
--nextSpanId;
if (!nextSpanId) {
nextSpanX = DS_VIDEO_HORIZONTAL_PIXELS;
span = NULL;
break;
}
span = DSGXSoftwareSpanListGetPointer(&softwareRenderer->activeSpans, nextSpanId - 1);
nextSpanX = span->ep[0].x >> 12;
}
while (span && i > (span->ep[0].x >> 12)) {
if (i <= (span->ep[1].x >> 12)) {
_lerpEndpoint(span, &ep, i);
color_t color = _lookupColor(&ep, span->poly); color_t color = _lookupColor(&ep, span->poly);
if (color & 0xF8000000) { if (color & 0xF8000000) {
// TODO: Alpha // TODO: Alpha
if (softwareRenderer->wSort) { if (softwareRenderer->wSort) {
if (ep.w < depth) { if (ep.w < softwareRenderer->depthBuffer[x]) {
depth = ep.w; softwareRenderer->depthBuffer[x] = ep.w;
scanline[i] = color; scanline[x] = color;
} }
} else { } else {
if (ep.z < depth) { if (ep.z < softwareRenderer->depthBuffer[x]) {
depth = ep.z; softwareRenderer->depthBuffer[x] = ep.z;
scanline[i] = color; scanline[x] = color;
} }
} }
} }
} }
--nextSpanId;
if (!nextSpanId) {
break;
}
span = DSGXSoftwareSpanListGetPointer(&softwareRenderer->activeSpans, nextSpanId - 1);
}
}
} }
if (y == DS_VIDEO_VERTICAL_PIXELS - 1) { if (y == DS_VIDEO_VERTICAL_PIXELS - 1) {
softwareRenderer->flushPending = false; softwareRenderer->flushPending = false;
} }