src/ds/gx/software.c (view raw)
1/* Copyright (c) 2013-2017 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include <mgba/internal/ds/gx/software.h>
7
8#include <mgba-util/memory.h>
9#include "gba/renderers/software-private.h"
10
11DEFINE_VECTOR(DSGXSoftwarePolygonList, struct DSGXSoftwarePolygon);
12DEFINE_VECTOR(DSGXSoftwareEdgeList, struct DSGXSoftwareEdge);
13DEFINE_VECTOR(DSGXSoftwareSpanList, struct DSGXSoftwareSpan);
14
15static void DSGXSoftwareRendererInit(struct DSGXRenderer* renderer);
16static void DSGXSoftwareRendererReset(struct DSGXRenderer* renderer);
17static void DSGXSoftwareRendererDeinit(struct DSGXRenderer* renderer);
18static void DSGXSoftwareRendererInvalidateTex(struct DSGXRenderer* renderer, int slot);
19static void DSGXSoftwareRendererSetRAM(struct DSGXRenderer* renderer, struct DSGXVertex* verts, struct DSGXPolygon* polys, unsigned polyCount, bool wSort);
20static void DSGXSoftwareRendererDrawScanline(struct DSGXRenderer* renderer, int y);
21static void DSGXSoftwareRendererGetScanline(struct DSGXRenderer* renderer, int y, const color_t** output);
22
23static void _expandColor(uint16_t c15, uint8_t* r, uint8_t* g, uint8_t* b) {
24 *r = ((c15 << 1) & 0x3E) | 1;
25 *g = ((c15 >> 4) & 0x3E) | 1;
26 *b = ((c15 >> 9) & 0x3E) | 1;
27}
28
29static color_t _finishColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
30#ifndef COLOR_16_BIT
31 color_t rgba = (r << 2) & 0xFC;
32 rgba |= (g << 10) & 0xFC00;
33 rgba |= (b << 18) & 0xFC0000;
34 rgba |= (a << 26) & 0xF8000000;
35 return rgba;
36#else
37#error Unsupported color depth
38#endif
39}
40
41static unsigned _mix32(int weightA, unsigned colorA, int weightB, unsigned colorB) {
42 unsigned c = 0;
43 unsigned a, b;
44#ifdef COLOR_16_BIT
45#error Unsupported color depth
46#else
47 a = colorA & 0xFF;
48 b = colorB & 0xFF;
49 c |= ((a * weightA + b * weightB) / 32) & 0x1FF;
50 if (c & 0x00000100) {
51 c = 0x000000FF;
52 }
53
54 a = colorA & 0xFF00;
55 b = colorB & 0xFF00;
56 c |= ((a * weightA + b * weightB) / 32) & 0x1FF00;
57 if (c & 0x00010000) {
58 c = (c & 0x000000FF) | 0x0000FF00;
59 }
60
61 a = colorA & 0xFF0000;
62 b = colorB & 0xFF0000;
63 c |= ((a * weightA + b * weightB) / 32) & 0x1FF0000;
64 if (c & 0x01000000) {
65 c = (c & 0x0000FFFF) | 0x00FF0000;
66 }
67#endif
68 return c;
69}
70
71static unsigned _mixTexels(int weightA, unsigned colorA, int weightB, unsigned colorB) {
72 unsigned c = 0;
73 unsigned a, b;
74 a = colorA & 0x7C1F;
75 b = colorB & 0x7C1F;
76 a |= (colorA & 0x3E0) << 16;
77 b |= (colorB & 0x3E0) << 16;
78 c = ((a * weightA + b * weightB) / 8);
79 if (c & 0x04000000) {
80 c = (c & ~0x07E00000) | 0x03E00000;
81 }
82 if (c & 0x0020) {
83 c = (c & ~0x003F) | 0x001F;
84 }
85 if (c & 0x8000) {
86 c = (c & ~0xF800) | 0x7C00;
87 }
88 c = (c & 0x7C1F) | ((c >> 16) & 0x03E0);
89 return c;
90}
91
92static color_t _lookupColor(struct DSGXSoftwareRenderer* renderer, struct DSGXSoftwareEndpoint* ep, struct DSGXSoftwarePolygon* poly) {
93 if (!poly->texBase && poly->texFormat) {
94 return 0;
95 }
96 // TODO: Optimize
97 uint16_t texel;
98
99 int16_t s = ep->s >> 4;
100 int16_t t = ep->t >> 4;
101 if (!DSGXTexParamsIsSRepeat(poly->poly->texParams)) {
102 if (s < 0) {
103 s = 0;
104 } else if (s >= poly->texW) {
105 s = poly->texW - 1;
106 }
107 } else if (DSGXTexParamsIsSMirror(poly->poly->texParams)) {
108 if (s & poly->texW) {
109 s = poly->texW - s - 1;
110 }
111 s &= poly->texW - 1;
112 } else {
113 s &= poly->texW - 1;
114 }
115 if (!DSGXTexParamsIsTRepeat(poly->poly->texParams)) {
116 if (t < 0) {
117 t = 0;
118 } else if (t >= poly->texH) {
119 t = poly->texW - 1;
120 }
121 } else if (DSGXTexParamsIsTMirror(poly->poly->texParams)) {
122 if (t & poly->texH) {
123 t = poly->texH - t - 1;
124 }
125 t &= poly->texH - 1;
126 } else {
127 t &= poly->texH - 1;
128 }
129
130 uint16_t texelCoord = s + t * poly->texW;
131 uint8_t ta = 0x1F;
132 uint8_t pa = DSGXPolygonAttrsGetAlpha(poly->poly->polyParams);
133 if (pa) {
134 pa = (pa << 1) + 1;
135 }
136 switch (poly->texFormat) {
137 case 0:
138 default:
139 return _finishColor(ep->cr, ep->cg, ep->cb, pa);
140 case 1:
141 texel = ((uint8_t*) poly->texBase)[texelCoord];
142 ta = (texel >> 5) & 0x7;
143 ta = (ta << 2) + (ta >> 1);
144 texel &= 0x1F;
145 break;
146 case 2:
147 texel = ((uint8_t*) poly->texBase)[texelCoord >> 2];
148 if (texelCoord & 0x3) {
149 texel >>= 2 * texel & 3;
150 }
151 texel &= 0x3;
152 break;
153 case 3:
154 texel = ((uint8_t*) poly->texBase)[texelCoord >> 1];
155 if (texelCoord & 0x1) {
156 texel >>= 4;
157 }
158 texel &= 0xF;
159 break;
160 case 4:
161 texel = ((uint8_t*) poly->texBase)[texelCoord];
162 break;
163 case 5:
164 texelCoord = (s & ~3) + (t & 3) + (t >> 2) * poly->texW;
165 texel = ((uint8_t*) poly->texBase)[texelCoord];
166 texel >>= (s & 3) * 2;
167 texel &= 3;
168 break;
169 case 6:
170 texel = ((uint8_t*) poly->texBase)[texelCoord];
171 ta = (texel >> 3) & 0x1F;
172 texel &= 0x7;
173 break;
174 case 7:
175 return _finishColor(0x3F, 0x3F, 0x3F, pa);
176 }
177 uint8_t r, g, b;
178 unsigned wr, wg, wb, wa;
179 if (poly->texFormat == 5) {
180 if (!renderer->d.tex[1]) {
181 return 0;
182 }
183 uint16_t half = DSGXTexParamsGetVRAMBase(poly->poly->texParams) & 0x8000;
184 uint32_t slot1Base = (DSGXTexParamsGetVRAMBase(poly->poly->texParams) << 1) + (texelCoord >> 2) + half;
185 uint16_t texel2 = renderer->d.tex[1][slot1Base];
186 uint16_t texel2Base = (texel2 & 0x3FFF) << 1;
187 int a = 0x8;
188 int b = 0;
189 switch (texel2 >> 14) {
190 case 0:
191 if (texel == 3) {
192 ta = 0;
193 }
194 texel = poly->palBase[texel + texel2Base];
195 break;
196 case 1:
197 if (texel == 3) {
198 ta = 0;
199 }
200 if (texel != 2) {
201 texel = poly->palBase[texel + texel2Base];
202 } else {
203 texel = poly->palBase[texel2Base];
204 texel2 = poly->palBase[texel2Base + 1];
205 a = 4;
206 b = 4;
207 }
208 break;
209 case 2:
210 texel = poly->palBase[texel + texel2Base];
211 break;
212 case 3:
213 switch (texel) {
214 case 0:
215 case 1:
216 texel = poly->palBase[texel + texel2Base];
217 break;
218 case 2:
219 texel = poly->palBase[texel2Base];
220 texel2 = poly->palBase[texel2Base + 1];
221 a = 5;
222 b = 3;
223 break;
224 case 3:
225 texel = poly->palBase[texel2Base];
226 texel2 = poly->palBase[texel2Base + 1];
227 a = 3;
228 b = 5;
229 break;
230 }
231 break;
232 }
233 if (b) {
234 texel = _mixTexels(a, texel, b, texel2);
235 }
236 } else {
237 if (poly->texFormat < 5 && poly->texFormat > 1 && DSGXTexParamsIs0Transparent(poly->poly->texParams) && !texel) {
238 return 0;
239 }
240 texel = poly->palBase[texel];
241 }
242 _expandColor(texel, &r, &g, &b);
243 if (ta) {
244 ta = (ta << 1) + 1;
245 }
246 switch (poly->blendFormat) {
247 default:
248 return _finishColor(r, g, b, pa);
249 case 0:
250 wr = ((r + 1) * (ep->cr + 1) - 1) >> 6;
251 wg = ((g + 1) * (ep->cg + 1) - 1) >> 6;
252 wb = ((b + 1) * (ep->cb + 1) - 1) >> 6;
253 wa = ((ta + 1) * (pa + 1) - 1) >> 6;
254 return _finishColor(wr, wg, wb, wa);
255 case 1:
256 wr = (r * ta + ep->cr * (63 - ta)) >> 6;
257 wg = (g * ta + ep->cg * (63 - ta)) >> 6;
258 wb = (b * ta + ep->cb * (63 - ta)) >> 6;
259 return _finishColor(wr, wg, wb, pa);
260 case 3:
261 return _finishColor(r, g, b, pa);
262 }
263}
264
265static inline int32_t _interpolate(int32_t x0, int32_t x1, int64_t w0, int64_t w1, int64_t w, int32_t qr) {
266 // 32-bit -> 96-bit
267 int64_t x0b = (w0 & 0xFFFFFFFF) * x0;
268 int64_t x0t = (w0 >> 32) * x0;
269 int64_t x1b = (w1 & 0xFFFFFFFF) * x1;
270 int64_t x1t = (w1 >> 32) * x1;
271 // 96-bit -> 64-bit
272 int64_t xx0 = (x0t << 32) + x0b;
273 int64_t xx1 = (x1t << 32) + x1b;
274 xx1 -= xx0;
275 xx1 >>= 12;
276
277 int64_t qrb = xx1 * qr;
278 qrb += xx0;
279
280 return qrb / w;
281}
282
283static inline int32_t _divideBy(int64_t x, int32_t recip) {
284 int64_t x0 = (x & 0xFFFFFFFF) * recip;
285 int64_t x1 = (x >> 32) * recip;
286 x1 += x0 >> 32;
287 return x1 >> 31;
288}
289
290static bool _edgeToSpan(struct DSGXSoftwareSpan* span, const struct DSGXSoftwareEdge* edge, int index, int32_t y) {
291 int32_t height = edge->y1 - edge->y0;
292 int64_t yw = y - edge->y0;
293 if (!height) {
294 return false;
295 }
296 // Clamp to bounds
297 if (yw < 0) {
298 return false;
299 } else if (yw > height) {
300 return false;
301 }
302
303 span->ep[index].coord[0] = (((int64_t) (edge->x1 - edge->x0) * yw) / height) + edge->x0;
304
305 if (index) {
306 if (span->ep[0].coord[0] == span->ep[index].coord[0]) {
307 return false;
308 }
309 if (span->ep[0].coord[0] > span->ep[index].coord[0]) {
310 int32_t temp = span->ep[index].coord[0];
311 span->ep[index] = span->ep[0];
312 span->ep[0].coord[0] = temp;
313 index = 0;
314 }
315 }
316
317 int64_t w0 = 0x7FFFFFFFFFFFFFFF / edge->w0;
318 int64_t w1 = 0x7FFFFFFFFFFFFFFF / edge->w1;
319 int64_t w = w1 - w0;
320
321 // Losslessly interpolate two 64-bit values
322 int64_t wb = (w & 0xFFFFFFFF) * yw;
323 int64_t wt = (w >> 32) * yw;
324 int64_t div = wt / height;
325 int64_t rem = wt % height;
326 w = div << 32;
327 wb += rem << 32;
328 div = wb / height;
329 w += div;
330 w += w0;
331
332 span->ep[index].coord[3] = 0x7FFFFFFFFFFFFFFF / w;
333 span->ep[index].wRecip = w;
334 int32_t qr = (yw << 12) / height;
335
336 span->ep[index].coord[2] = _interpolate(edge->z0, edge->z1, w0, w1, w, qr);
337 span->ep[index].cr = _interpolate(edge->cr0, edge->cr1, w0, w1, w, qr);
338 span->ep[index].cg = _interpolate(edge->cg0, edge->cg1, w0, w1, w, qr);
339 span->ep[index].cb = _interpolate(edge->cb0, edge->cb1, w0, w1, w, qr);
340 span->ep[index].s = _interpolate(edge->s0, edge->s1, w0, w1, w, qr);
341 span->ep[index].t = _interpolate(edge->t0, edge->t1, w0, w1, w, qr);
342
343 return true;
344}
345
346static void _createStep(struct DSGXSoftwareSpan* span) {
347 int32_t width = (span->ep[1].coord[0] - span->ep[0].coord[0]) >> 7;
348
349 span->ep[0].stepW = span->ep[0].wRecip;
350 span->ep[0].stepZ = span->ep[0].coord[2] * span->ep[0].wRecip;
351 span->ep[0].stepR = span->ep[0].cr * span->ep[0].wRecip;
352 span->ep[0].stepG = span->ep[0].cg * span->ep[0].wRecip;
353 span->ep[0].stepB = span->ep[0].cb * span->ep[0].wRecip;
354 span->ep[0].stepS = span->ep[0].s * span->ep[0].wRecip;
355 span->ep[0].stepT = span->ep[0].t * span->ep[0].wRecip;
356
357 span->ep[1].stepW = span->ep[1].wRecip;
358 span->ep[1].stepZ = span->ep[1].coord[2] * span->ep[1].wRecip;
359 span->ep[1].stepR = span->ep[1].cr * span->ep[1].wRecip;
360 span->ep[1].stepG = span->ep[1].cg * span->ep[1].wRecip;
361 span->ep[1].stepB = span->ep[1].cb * span->ep[1].wRecip;
362 span->ep[1].stepS = span->ep[1].s * span->ep[1].wRecip;
363 span->ep[1].stepT = span->ep[1].t * span->ep[1].wRecip;
364
365 if (!width) {
366 return;
367 }
368 span->step.coord[0] = span->ep[1].coord[0] - span->ep[0].coord[0];
369 span->step.stepW = (span->ep[1].stepW - span->ep[0].stepW) / width;
370 span->step.stepZ = (span->ep[1].stepZ - span->ep[0].stepZ) / width;
371 span->step.stepR = (span->ep[1].stepR - span->ep[0].stepR) / width;
372 span->step.stepG = (span->ep[1].stepG - span->ep[0].stepG) / width;
373 span->step.stepB = (span->ep[1].stepB - span->ep[0].stepB) / width;
374 span->step.stepS = (span->ep[1].stepS - span->ep[0].stepS) / width;
375 span->step.stepT = (span->ep[1].stepT - span->ep[0].stepT) / width;
376}
377
378static void _stepEndpoint(struct DSGXSoftwareSpan* span) {
379 int i = 28;
380 int32_t nextX = (span->ep[0].coord[0] & ~0xFFF) + 0x1000;
381 span->ep[0].coord[0] += 0x80 * i;
382 while (span->ep[0].coord[0] < nextX) {
383 span->ep[0].coord[0] += 0x80;
384 ++i;
385 }
386 span->ep[0].wRecip += span->step.stepW * i;
387 span->ep[0].coord[3] = (0x7FFFFFFFFFFFFFFF / span->ep[0].wRecip) + 1;
388
389 span->ep[0].stepZ += span->step.stepZ * i;
390 span->ep[0].coord[2] = _divideBy(span->ep[0].stepZ, span->ep[0].coord[3]);
391
392 span->ep[0].stepR += span->step.stepR * i;
393 span->ep[0].cr = _divideBy(span->ep[0].stepR, span->ep[0].coord[3]);
394
395 span->ep[0].stepG += span->step.stepG * i;
396 span->ep[0].cg = _divideBy(span->ep[0].stepG, span->ep[0].coord[3]);
397
398 span->ep[0].stepB += span->step.stepB * i;
399 span->ep[0].cb = _divideBy(span->ep[0].stepB, span->ep[0].coord[3]);
400
401 span->ep[0].stepS += span->step.stepS * i;
402 span->ep[0].s = _divideBy(span->ep[0].stepS, span->ep[0].coord[3]);
403
404 span->ep[0].stepT += span->step.stepT * i;
405 span->ep[0].t = _divideBy(span->ep[0].stepT, span->ep[0].coord[3]);
406}
407
408void DSGXSoftwareRendererCreate(struct DSGXSoftwareRenderer* renderer) {
409 renderer->d.init = DSGXSoftwareRendererInit;
410 renderer->d.reset = DSGXSoftwareRendererReset;
411 renderer->d.deinit = DSGXSoftwareRendererDeinit;
412 renderer->d.invalidateTex = DSGXSoftwareRendererInvalidateTex;
413 renderer->d.setRAM = DSGXSoftwareRendererSetRAM;
414 renderer->d.drawScanline = DSGXSoftwareRendererDrawScanline;
415 renderer->d.getScanline = DSGXSoftwareRendererGetScanline;
416}
417
418static void DSGXSoftwareRendererInit(struct DSGXRenderer* renderer) {
419 struct DSGXSoftwareRenderer* softwareRenderer = (struct DSGXSoftwareRenderer*) renderer;
420 DSGXSoftwarePolygonListInit(&softwareRenderer->activePolys, DS_GX_POLYGON_BUFFER_SIZE / 4);
421 DSGXSoftwareEdgeListInit(&softwareRenderer->activeEdges, DS_GX_POLYGON_BUFFER_SIZE);
422 DSGXSoftwareSpanListInit(&softwareRenderer->activeSpans, DS_GX_POLYGON_BUFFER_SIZE / 2);
423 softwareRenderer->bucket = anonymousMemoryMap(sizeof(*softwareRenderer->bucket) * DS_GX_POLYGON_BUFFER_SIZE);
424 softwareRenderer->scanlineCache = anonymousMemoryMap(sizeof(color_t) * DS_VIDEO_VERTICAL_PIXELS * DS_VIDEO_HORIZONTAL_PIXELS);
425}
426
427static void DSGXSoftwareRendererReset(struct DSGXRenderer* renderer) {
428 struct DSGXSoftwareRenderer* softwareRenderer = (struct DSGXSoftwareRenderer*) renderer;
429 softwareRenderer->flushPending = false;
430}
431
432static void DSGXSoftwareRendererDeinit(struct DSGXRenderer* renderer) {
433 struct DSGXSoftwareRenderer* softwareRenderer = (struct DSGXSoftwareRenderer*) renderer;
434 DSGXSoftwarePolygonListDeinit(&softwareRenderer->activePolys);
435 DSGXSoftwareEdgeListDeinit(&softwareRenderer->activeEdges);
436 DSGXSoftwareSpanListDeinit(&softwareRenderer->activeSpans);
437 mappedMemoryFree(softwareRenderer->bucket, sizeof(*softwareRenderer->bucket) * DS_GX_POLYGON_BUFFER_SIZE);
438 mappedMemoryFree(softwareRenderer->scanlineCache, sizeof(color_t) * DS_VIDEO_VERTICAL_PIXELS * DS_VIDEO_HORIZONTAL_PIXELS);
439}
440
441static void DSGXSoftwareRendererInvalidateTex(struct DSGXRenderer* renderer, int slot) {
442 struct DSGXSoftwareRenderer* softwareRenderer = (struct DSGXSoftwareRenderer*) renderer;
443 // TODO
444}
445
446static void _preparePoly(struct DSGXRenderer* renderer, struct DSGXVertex* verts, struct DSGXSoftwarePolygon* poly, int polyId) {
447 struct DSGXSoftwareRenderer* softwareRenderer = (struct DSGXSoftwareRenderer*) renderer;
448 struct DSGXSoftwareEdge* edge = DSGXSoftwareEdgeListAppend(&softwareRenderer->activeEdges);
449 poly->texFormat = DSGXTexParamsGetFormat(poly->poly->texParams);
450 poly->blendFormat = DSGXPolygonAttrsGetMode(poly->poly->polyParams);
451 poly->texW = 8 << DSGXTexParamsGetSSize(poly->poly->texParams);
452 poly->texH = 8 << DSGXTexParamsGetTSize(poly->poly->texParams);
453 if (!renderer->tex[DSGXTexParamsGetVRAMBase(poly->poly->texParams) >> VRAM_BLOCK_OFFSET]) {
454 poly->texBase = NULL;
455 poly->palBase = NULL;
456 } else {
457 switch (poly->texFormat) {
458 case 0:
459 case 7:
460 poly->texBase = NULL;
461 poly->palBase = NULL;
462 break;
463 case 2:
464 poly->texBase = &renderer->tex[DSGXTexParamsGetVRAMBase(poly->poly->texParams) >> VRAM_BLOCK_OFFSET][(DSGXTexParamsGetVRAMBase(poly->poly->texParams) << 2) & 0xFFFF];
465 poly->palBase = &renderer->texPal[poly->poly->palBase >> 11][(poly->poly->palBase << 2) & 0x1FFF];
466 break;
467 default:
468 poly->texBase = &renderer->tex[DSGXTexParamsGetVRAMBase(poly->poly->texParams) >> VRAM_BLOCK_OFFSET][(DSGXTexParamsGetVRAMBase(poly->poly->texParams) << 2) & 0xFFFF];
469 poly->palBase = &renderer->texPal[poly->poly->palBase >> 10][(poly->poly->palBase << 3) & 0x1FFF];
470 break;
471 }
472 }
473 edge->polyId = polyId;
474
475 struct DSGXVertex* v0 = &verts[poly->poly->vertIds[0]];
476 struct DSGXVertex* v1;
477
478 int32_t v0x = (v0->viewCoord[0] + v0->viewCoord[3]) * (int64_t) (renderer->viewportWidth << 12) / (v0->viewCoord[3] * 2) + (renderer->viewportX << 12);
479 int32_t v0y = (-v0->viewCoord[1] + v0->viewCoord[3]) * (int64_t) (renderer->viewportHeight << 12) / (v0->viewCoord[3] * 2) + (renderer->viewportY << 12);
480
481 int v;
482 for (v = 1; v < poly->poly->verts; ++v) {
483 v1 = &verts[poly->poly->vertIds[v]];
484 int32_t v1x = (v1->viewCoord[0] + v1->viewCoord[3]) * (int64_t) (renderer->viewportWidth << 12) / (v1->viewCoord[3] * 2) + (renderer->viewportX << 12);
485 int32_t v1y = (-v1->viewCoord[1] + v1->viewCoord[3]) * (int64_t) (renderer->viewportHeight << 12) / (v1->viewCoord[3] * 2) + (renderer->viewportY << 12);
486
487 if (v0y <= v1y) {
488 edge->y0 = v0y;
489 edge->x0 = v0x;
490 edge->z0 = v0->viewCoord[2];
491 edge->w0 = v0->viewCoord[3];
492 _expandColor(v0->color, &edge->cr0, &edge->cg0, &edge->cb0);
493 edge->s0 = v0->vs;
494 edge->t0 = v0->vt;
495
496 edge->y1 = v1y;
497 edge->x1 = v1x;
498 edge->z1 = v1->viewCoord[2];
499 edge->w1 = v1->viewCoord[3];
500 _expandColor(v1->color, &edge->cr1, &edge->cg1, &edge->cb1);
501 edge->s1 = v1->vs;
502 edge->t1 = v1->vt;
503 } else {
504 edge->y0 = v1y;
505 edge->x0 = v1x;
506 edge->z0 = v1->viewCoord[2];
507 edge->w0 = v1->viewCoord[3];
508 _expandColor(v1->color, &edge->cr0, &edge->cg0, &edge->cb0);
509 edge->s0 = v1->vs;
510 edge->t0 = v1->vt;
511
512 edge->y1 = v0y;
513 edge->x1 = v0x;
514 edge->z1 = v0->viewCoord[2];
515 edge->w1 = v0->viewCoord[3];
516 _expandColor(v0->color, &edge->cr1, &edge->cg1, &edge->cb1);
517 edge->s1 = v0->vs;
518 edge->t1 = v0->vt;
519 }
520
521 edge = DSGXSoftwareEdgeListAppend(&softwareRenderer->activeEdges);
522 edge->polyId = polyId;
523 v0 = v1;
524 v0x = v1x;
525 v0y = v1y;
526 }
527
528 v1 = &verts[poly->poly->vertIds[0]];
529 int32_t v1x = (v1->viewCoord[0] + v1->viewCoord[3]) * (int64_t) (renderer->viewportWidth << 12) / (v1->viewCoord[3] * 2) + (renderer->viewportX << 12);
530 int32_t v1y = (-v1->viewCoord[1] + v1->viewCoord[3]) * (int64_t) (renderer->viewportHeight << 12) / (v1->viewCoord[3] * 2) + (renderer->viewportY << 12);
531
532 if (v0y <= v1y) {
533 edge->y0 = v0y;
534 edge->x0 = v0x;
535 edge->z0 = v0->viewCoord[2];
536 edge->w0 = v0->viewCoord[3];
537 _expandColor(v0->color, &edge->cr0, &edge->cg0, &edge->cb0);
538 edge->s0 = v0->vs;
539 edge->t0 = v0->vt;
540
541 edge->y1 = v1y;
542 edge->x1 = v1x;
543 edge->z1 = v1->viewCoord[2];
544 edge->w1 = v1->viewCoord[3];
545 _expandColor(v1->color, &edge->cr1, &edge->cg1, &edge->cb1);
546 edge->s1 = v1->vs;
547 edge->t1 = v1->vt;
548 } else {
549 edge->y0 = v1y;
550 edge->x0 = v1x;
551 edge->z0 = v1->viewCoord[2];
552 edge->w0 = v1->viewCoord[3];
553 _expandColor(v1->color, &edge->cr0, &edge->cg0, &edge->cb0);
554 edge->s0 = v1->vs;
555 edge->t0 = v1->vt;
556
557 edge->y1 = v0y;
558 edge->x1 = v0x;
559 edge->z1 = v0->viewCoord[2];
560 edge->w1 = v0->viewCoord[3];
561 _expandColor(v0->color, &edge->cr1, &edge->cg1, &edge->cb1);
562 edge->s1 = v0->vs;
563 edge->t1 = v0->vt;
564 }
565}
566
567static void DSGXSoftwareRendererSetRAM(struct DSGXRenderer* renderer, struct DSGXVertex* verts, struct DSGXPolygon* polys, unsigned polyCount, bool wSort) {
568 struct DSGXSoftwareRenderer* softwareRenderer = (struct DSGXSoftwareRenderer*) renderer;
569
570 softwareRenderer->flushPending = true;
571 softwareRenderer->sort = wSort ? 3 : 2;
572 softwareRenderer->verts = verts;
573 DSGXSoftwarePolygonListClear(&softwareRenderer->activePolys);
574 DSGXSoftwareEdgeListClear(&softwareRenderer->activeEdges);
575 unsigned i;
576 // Pass 1: Opaque
577 for (i = 0; i < polyCount; ++i) {
578 struct DSGXSoftwarePolygon* poly = NULL;
579 switch (DSGXTexParamsGetFormat(polys[i].texParams)) {
580 default:
581 if (DSGXPolygonAttrsGetAlpha(polys[i].polyParams) == 0x1F) {
582 poly = DSGXSoftwarePolygonListAppend(&softwareRenderer->activePolys);
583 break;
584 }
585 case 1:
586 case 6:
587 break;
588 }
589 if (!poly) {
590 continue;
591 }
592 poly->poly = &polys[i];
593 _preparePoly(renderer, verts, poly, DSGXSoftwarePolygonListSize(&softwareRenderer->activePolys) - 1);
594 }
595 // Pass 2: Translucent
596 for (i = 0; i < polyCount; ++i) {
597 struct DSGXSoftwarePolygon* poly = NULL;
598 switch (DSGXTexParamsGetFormat(polys[i].texParams)) {
599 default:
600 if (DSGXPolygonAttrsGetAlpha(polys[i].polyParams) == 0x1F) {
601 break;
602 }
603 case 1:
604 case 6:
605 poly = DSGXSoftwarePolygonListAppend(&softwareRenderer->activePolys);
606 break;
607 }
608 if (!poly) {
609 continue;
610 }
611 poly->poly = &polys[i];
612 _preparePoly(renderer, verts, poly, DSGXSoftwarePolygonListSize(&softwareRenderer->activePolys) - 1);
613 }
614}
615
616static void DSGXSoftwareRendererDrawScanline(struct DSGXRenderer* renderer, int y) {
617 struct DSGXSoftwareRenderer* softwareRenderer = (struct DSGXSoftwareRenderer*) renderer;
618 if (!softwareRenderer->flushPending) {
619 return;
620 }
621 DSGXSoftwareSpanListClear(&softwareRenderer->activeSpans);
622 memset(softwareRenderer->bucket, 0, sizeof(*softwareRenderer->bucket) * DS_GX_POLYGON_BUFFER_SIZE);
623 size_t i;
624 for (i = 0; i < DSGXSoftwareEdgeListSize(&softwareRenderer->activeEdges); ++i) {
625 struct DSGXSoftwareEdge* edge = DSGXSoftwareEdgeListGetPointer(&softwareRenderer->activeEdges, i);
626 if (edge->y1 < (y << 12)) {
627 continue;
628 } else if (edge->y0 > (y << 12)) {
629 continue;
630 }
631
632 unsigned poly = edge->polyId;
633 struct DSGXSoftwareSpan* span = softwareRenderer->bucket[poly];
634 if (span && !span->ep[1].coord[3]) {
635 if (_edgeToSpan(span, edge, 1, y << 12)) {
636 _createStep(span);
637 softwareRenderer->bucket[poly] = NULL;
638 }
639 } else if (!span) {
640 span = DSGXSoftwareSpanListAppend(&softwareRenderer->activeSpans);
641 memset(&span->ep[1], 0, sizeof(span->ep[1]));
642 span->poly = DSGXSoftwarePolygonListGetPointer(&softwareRenderer->activePolys, poly);
643 span->polyId = DSGXPolygonAttrsGetId(span->poly->poly->polyParams);
644 if (!_edgeToSpan(span, edge, 0, y << 12)) {
645 // Horizontal line
646 DSGXSoftwareSpanListShift(&softwareRenderer->activeSpans, DSGXSoftwareSpanListSize(&softwareRenderer->activeSpans) - 1, 1);
647 } else {
648 softwareRenderer->bucket[poly] = span;
649 }
650 }
651 }
652
653 color_t* scanline = &softwareRenderer->scanlineCache[DS_VIDEO_HORIZONTAL_PIXELS * y];
654 memset(scanline, 0, sizeof(color_t) * DS_VIDEO_HORIZONTAL_PIXELS);
655 memset(softwareRenderer->stencilBuffer, 0, sizeof(softwareRenderer->stencilBuffer[0]) * DS_VIDEO_HORIZONTAL_PIXELS);
656 for (i = 0; i < DS_VIDEO_HORIZONTAL_PIXELS; i += 4) {
657 softwareRenderer->depthBuffer[i] = INT32_MAX;
658 softwareRenderer->depthBuffer[i + 1] = INT32_MAX;
659 softwareRenderer->depthBuffer[i + 2] = INT32_MAX;
660 softwareRenderer->depthBuffer[i + 3] = INT32_MAX;
661 }
662
663 for (i = 0; i < DSGXSoftwareSpanListSize(&softwareRenderer->activeSpans); ++i) {
664 struct DSGXSoftwareSpan* span = DSGXSoftwareSpanListGetPointer(&softwareRenderer->activeSpans, i);
665
666 int32_t x = span->ep[0].coord[0] >> 12;
667 if (x < 0) {
668 x = 0;
669 }
670 for (; x < (span->ep[1].coord[0] >> 12) && x < DS_VIDEO_HORIZONTAL_PIXELS; ++x) {
671 color_t color = _lookupColor(softwareRenderer, &span->ep[0], span->poly);
672 _stepEndpoint(span);
673 unsigned a = color >> 27;
674 unsigned current = scanline[x];
675 unsigned b = current >> 27;
676 unsigned ab = a;
677 unsigned s = span->polyId;
678 if (b > ab) {
679 ab = b;
680 }
681 if (span->poly->blendFormat == 3) {
682 s |= 0x40;
683 }
684 if (a == 0x1F) {
685 if (span->ep[0].coord[softwareRenderer->sort] < softwareRenderer->depthBuffer[x]) {
686 if (s != 0x40 && !(softwareRenderer->stencilBuffer[x] & 0x40)) {
687 softwareRenderer->depthBuffer[x] = span->ep[0].coord[softwareRenderer->sort];
688 scanline[x] = color;
689 s &= ~0x40;
690 }
691 softwareRenderer->stencilBuffer[x] = s;
692 }
693 } else if (a) {
694 // TODO: Disable alpha?
695 if (b) {
696 color = _mix32(a, color, 0x1F - a, current);
697 color |= ab << 27;
698 }
699 if (softwareRenderer->stencilBuffer[x] != s) {
700 if (span->ep[0].coord[softwareRenderer->sort] < softwareRenderer->depthBuffer[x]) {
701 if (s != 0x40 && !(softwareRenderer->stencilBuffer[x] & 0x40)) {
702 if (DSGXPolygonAttrsIsUpdateDepth(span->poly->poly->polyParams)) {
703 softwareRenderer->depthBuffer[x] = span->ep[0].coord[softwareRenderer->sort];
704 }
705 scanline[x] = color;
706 s &= ~0x40;
707 }
708 softwareRenderer->stencilBuffer[x] = s;
709 }
710 }
711 }
712 }
713 }
714
715 if (y == DS_VIDEO_VERTICAL_PIXELS - 1) {
716 softwareRenderer->flushPending = false;
717 }
718}
719
720static void DSGXSoftwareRendererGetScanline(struct DSGXRenderer* renderer, int y, const color_t** output) {
721 struct DSGXSoftwareRenderer* softwareRenderer = (struct DSGXSoftwareRenderer*) renderer;
722 *output = &softwareRenderer->scanlineCache[DS_VIDEO_HORIZONTAL_PIXELS * y];
723}