GBA Video: Refactor rendering pipeline

This commit is contained in:
Vicki Pfau 2017-02-24 16:05:37 -08:00
parent 9639d7ad49
commit 242e3c6ec5
2 changed files with 159 additions and 142 deletions

View File

@ -29,6 +29,10 @@ void GBAVideoSoftwareRendererDrawBackgroundMode5(struct GBAVideoSoftwareRenderer
int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* renderer, struct GBAObj* sprite, int y); int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* renderer, struct GBAObj* sprite, int y);
void GBAVideoSoftwareRendererPostprocessSprite(struct GBAVideoSoftwareRenderer* renderer, unsigned priority); void GBAVideoSoftwareRendererPostprocessSprite(struct GBAVideoSoftwareRenderer* renderer, unsigned priority);
void GBAVideoSoftwareRendererPreprocessBuffer(struct GBAVideoSoftwareRenderer* renderer, int y);
void GBAVideoSoftwareRendererPostprocessBuffer(struct GBAVideoSoftwareRenderer* renderer);
int GBAVideoSoftwareRendererPreprocessSpriteLayer(struct GBAVideoSoftwareRenderer* renderer, int y);
static inline unsigned _brighten(unsigned color, int y); static inline unsigned _brighten(unsigned color, int y);
static inline unsigned _darken(unsigned color, int y); static inline unsigned _darken(unsigned color, int y);
static unsigned _mix(int weightA, unsigned colorA, int weightB, unsigned colorB); static unsigned _mix(int weightA, unsigned colorA, int weightB, unsigned colorB);
@ -217,6 +221,12 @@ static inline void _compositeNoBlendNoObjwin(struct GBAVideoSoftwareRenderer* re
localY = y; \ localY = y; \
} }
#define TEST_LAYER_ENABLED(X) \
(softwareRenderer->bg[X].enabled && \
(GBAWindowControlIsBg ## X ## Enable(softwareRenderer->currentWindow.packed) || \
(GBARegisterDISPCNTIsObjwinEnable(softwareRenderer->dispcnt) && GBAWindowControlIsBg ## X ## Enable (softwareRenderer->objwin.packed))) && \
softwareRenderer->bg[X].priority == priority)
static inline unsigned _brighten(unsigned color, int y) { static inline unsigned _brighten(unsigned color, int y) {
unsigned c = 0; unsigned c = 0;
unsigned a; unsigned a;

View File

@ -37,7 +37,6 @@ static void GBAVideoSoftwareRendererWriteBGY_HI(struct GBAVideoSoftwareBackgroun
static void GBAVideoSoftwareRendererWriteBLDCNT(struct GBAVideoSoftwareRenderer* renderer, uint16_t value); static void GBAVideoSoftwareRendererWriteBLDCNT(struct GBAVideoSoftwareRenderer* renderer, uint16_t value);
static void _cleanOAM(struct GBAVideoSoftwareRenderer* renderer); static void _cleanOAM(struct GBAVideoSoftwareRenderer* renderer);
static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y);
static void _updatePalettes(struct GBAVideoSoftwareRenderer* renderer); static void _updatePalettes(struct GBAVideoSoftwareRenderer* renderer);
@ -494,96 +493,64 @@ static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* render
return; return;
} }
int x; GBAVideoSoftwareRendererPreprocessBuffer(softwareRenderer, y);
for (x = 0; x < softwareRenderer->masterEnd; x += 4) { int spriteLayers = GBAVideoSoftwareRendererPreprocessSpriteLayer(softwareRenderer, y);
softwareRenderer->spriteLayer[x] = FLAG_UNWRITTEN;
softwareRenderer->spriteLayer[x + 1] = FLAG_UNWRITTEN;
softwareRenderer->spriteLayer[x + 2] = FLAG_UNWRITTEN;
softwareRenderer->spriteLayer[x + 3] = FLAG_UNWRITTEN;
}
softwareRenderer->windows[0].endX = softwareRenderer->masterEnd;
softwareRenderer->nWindows = 1;
if (GBARegisterDISPCNTIsWin0Enable(softwareRenderer->dispcnt) || GBARegisterDISPCNTIsWin1Enable(softwareRenderer->dispcnt) || GBARegisterDISPCNTIsObjwinEnable(softwareRenderer->dispcnt)) {
softwareRenderer->windows[0].control = softwareRenderer->winout;
if (GBARegisterDISPCNTIsWin1Enable(softwareRenderer->dispcnt)) {
_breakWindow(softwareRenderer, &softwareRenderer->winN[1], y);
}
if (GBARegisterDISPCNTIsWin0Enable(softwareRenderer->dispcnt)) {
_breakWindow(softwareRenderer, &softwareRenderer->winN[0], y);
}
} else {
softwareRenderer->windows[0].control.packed = 0xFF;
}
GBAVideoSoftwareRendererUpdateDISPCNT(softwareRenderer);
int w; int w;
x = 0; unsigned priority;
for (priority = 0; priority < 4; ++priority) {
softwareRenderer->end = 0;
for (w = 0; w < softwareRenderer->nWindows; ++w) { for (w = 0; w < softwareRenderer->nWindows; ++w) {
// TOOD: handle objwin on backdrop softwareRenderer->start = softwareRenderer->end;
uint32_t backdrop = FLAG_UNWRITTEN | FLAG_PRIORITY | FLAG_IS_BACKGROUND; softwareRenderer->end = softwareRenderer->windows[w].endX;
if (!softwareRenderer->target1Bd || softwareRenderer->blendEffect == BLEND_NONE || softwareRenderer->blendEffect == BLEND_ALPHA || !GBAWindowControlIsBlendEnable(softwareRenderer->windows[w].control.packed)) { softwareRenderer->currentWindow = softwareRenderer->windows[w].control;
backdrop |= softwareRenderer->normalPalette[0]; if (spriteLayers & (1 << priority)) {
} else { GBAVideoSoftwareRendererPostprocessSprite(softwareRenderer, priority);
backdrop |= softwareRenderer->variantPalette[0];
} }
int end = softwareRenderer->windows[w].endX; if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(softwareRenderer->dispcnt) < 2) {
for (; x < end - 3; x += 4) { GBAVideoSoftwareRendererDrawBackgroundMode0(softwareRenderer, &softwareRenderer->bg[0], y);
softwareRenderer->row[x] = backdrop;
softwareRenderer->row[x + 1] = backdrop;
softwareRenderer->row[x + 2] = backdrop;
softwareRenderer->row[x + 3] = backdrop;
} }
for (; x < end; ++x) { if (TEST_LAYER_ENABLED(1) && GBARegisterDISPCNTGetMode(softwareRenderer->dispcnt) < 2) {
softwareRenderer->row[x] = backdrop; GBAVideoSoftwareRendererDrawBackgroundMode0(softwareRenderer, &softwareRenderer->bg[1], y);
}
if (TEST_LAYER_ENABLED(2)) {
switch (GBARegisterDISPCNTGetMode(softwareRenderer->dispcnt)) {
case 0:
GBAVideoSoftwareRendererDrawBackgroundMode0(softwareRenderer, &softwareRenderer->bg[2], y);
break;
case 1:
case 2:
GBAVideoSoftwareRendererDrawBackgroundMode2(softwareRenderer, &softwareRenderer->bg[2], y);
break;
case 3:
GBAVideoSoftwareRendererDrawBackgroundMode3(softwareRenderer, &softwareRenderer->bg[2], y);
break;
case 4:
GBAVideoSoftwareRendererDrawBackgroundMode4(softwareRenderer, &softwareRenderer->bg[2], y);
break;
case 5:
GBAVideoSoftwareRendererDrawBackgroundMode5(softwareRenderer, &softwareRenderer->bg[2], y);
break;
} }
} }
if (TEST_LAYER_ENABLED(3)) {
switch (GBARegisterDISPCNTGetMode(softwareRenderer->dispcnt)) {
case 0:
GBAVideoSoftwareRendererDrawBackgroundMode0(softwareRenderer, &softwareRenderer->bg[3], y);
break;
case 2:
GBAVideoSoftwareRendererDrawBackgroundMode2(softwareRenderer, &softwareRenderer->bg[3], y);
break;
}
}
}
}
softwareRenderer->bg[2].sx += softwareRenderer->bg[2].dmx;
softwareRenderer->bg[2].sy += softwareRenderer->bg[2].dmy;
softwareRenderer->bg[3].sx += softwareRenderer->bg[3].dmx;
softwareRenderer->bg[3].sy += softwareRenderer->bg[3].dmy;
_drawScanline(softwareRenderer, y); GBAVideoSoftwareRendererPostprocessBuffer(softwareRenderer);
if (softwareRenderer->target2Bd) {
x = 0;
for (w = 0; w < softwareRenderer->nWindows; ++w) {
uint32_t backdrop = 0;
if (!softwareRenderer->target1Bd || softwareRenderer->blendEffect == BLEND_NONE || softwareRenderer->blendEffect == BLEND_ALPHA || !GBAWindowControlIsBlendEnable(softwareRenderer->windows[w].control.packed)) {
backdrop |= softwareRenderer->normalPalette[0];
} else {
backdrop |= softwareRenderer->variantPalette[0];
}
int end = softwareRenderer->windows[w].endX;
for (; x < end; ++x) {
uint32_t color = softwareRenderer->row[x];
if (color & FLAG_TARGET_1) {
softwareRenderer->row[x] = _mix(softwareRenderer->bldb, backdrop, softwareRenderer->blda, color);
}
}
}
}
if (softwareRenderer->target1Obj && (softwareRenderer->blendEffect == BLEND_DARKEN || softwareRenderer->blendEffect == BLEND_BRIGHTEN)) {
x = 0;
for (w = 0; w < softwareRenderer->nWindows; ++w) {
if (!GBAWindowControlIsBlendEnable(softwareRenderer->windows[w].control.packed)) {
continue;
}
int end = softwareRenderer->windows[w].endX;
if (softwareRenderer->blendEffect == BLEND_DARKEN) {
for (; x < end; ++x) {
uint32_t color = softwareRenderer->row[x];
if ((color & 0xFF000000) == FLAG_REBLEND) {
softwareRenderer->row[x] = _darken(color, softwareRenderer->bldy);
}
}
} else if (softwareRenderer->blendEffect == BLEND_BRIGHTEN) {
for (; x < end; ++x) {
uint32_t color = softwareRenderer->row[x];
if ((color & 0xFF000000) == FLAG_REBLEND) {
softwareRenderer->row[x] = _brighten(color, softwareRenderer->bldy);
}
}
}
}
}
#ifdef COLOR_16_BIT #ifdef COLOR_16_BIT
#if defined(__ARM_NEON) && !defined(__APPLE__) #if defined(__ARM_NEON) && !defined(__APPLE__)
@ -713,13 +680,105 @@ static void GBAVideoSoftwareRendererWriteBLDCNT(struct GBAVideoSoftwareRenderer*
} }
} }
#define TEST_LAYER_ENABLED(X) \ void GBAVideoSoftwareRendererPreprocessBuffer(struct GBAVideoSoftwareRenderer* softwareRenderer, int y) {
(renderer->bg[X].enabled && \ int x;
(GBAWindowControlIsBg ## X ## Enable(renderer->currentWindow.packed) || \ int masterEnd = softwareRenderer->masterEnd;
(GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt) && GBAWindowControlIsBg ## X ## Enable (renderer->objwin.packed))) && \ for (x = 0; x < masterEnd; x += 4) {
renderer->bg[X].priority == priority) softwareRenderer->spriteLayer[x] = FLAG_UNWRITTEN;
softwareRenderer->spriteLayer[x + 1] = FLAG_UNWRITTEN;
softwareRenderer->spriteLayer[x + 2] = FLAG_UNWRITTEN;
softwareRenderer->spriteLayer[x + 3] = FLAG_UNWRITTEN;
}
static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y) { softwareRenderer->windows[0].endX = softwareRenderer->masterEnd;
softwareRenderer->nWindows = 1;
if (GBARegisterDISPCNTIsWin0Enable(softwareRenderer->dispcnt) || GBARegisterDISPCNTIsWin1Enable(softwareRenderer->dispcnt) || GBARegisterDISPCNTIsObjwinEnable(softwareRenderer->dispcnt)) {
softwareRenderer->windows[0].control = softwareRenderer->winout;
if (GBARegisterDISPCNTIsWin1Enable(softwareRenderer->dispcnt)) {
_breakWindow(softwareRenderer, &softwareRenderer->winN[1], y);
}
if (GBARegisterDISPCNTIsWin0Enable(softwareRenderer->dispcnt)) {
_breakWindow(softwareRenderer, &softwareRenderer->winN[0], y);
}
} else {
softwareRenderer->windows[0].control.packed = 0xFF;
}
GBAVideoSoftwareRendererUpdateDISPCNT(softwareRenderer);
int w;
x = 0;
for (w = 0; w < softwareRenderer->nWindows; ++w) {
// TOOD: handle objwin on backdrop
uint32_t backdrop = FLAG_UNWRITTEN | FLAG_PRIORITY | FLAG_IS_BACKGROUND;
if (!softwareRenderer->target1Bd || softwareRenderer->blendEffect == BLEND_NONE || softwareRenderer->blendEffect == BLEND_ALPHA || !GBAWindowControlIsBlendEnable(softwareRenderer->windows[w].control.packed)) {
backdrop |= softwareRenderer->normalPalette[0];
} else {
backdrop |= softwareRenderer->variantPalette[0];
}
int end = softwareRenderer->windows[w].endX;
for (; x & 3; ++x) {
softwareRenderer->row[x] = backdrop;
}
for (; x < end - 3; x += 4) {
softwareRenderer->row[x] = backdrop;
softwareRenderer->row[x + 1] = backdrop;
softwareRenderer->row[x + 2] = backdrop;
softwareRenderer->row[x + 3] = backdrop;
}
for (; x < end; ++x) {
softwareRenderer->row[x] = backdrop;
}
}
}
void GBAVideoSoftwareRendererPostprocessBuffer(struct GBAVideoSoftwareRenderer* softwareRenderer) {
int x, w;
if (softwareRenderer->target2Bd) {
x = 0;
for (w = 0; w < softwareRenderer->nWindows; ++w) {
uint32_t backdrop = 0;
if (!softwareRenderer->target1Bd || softwareRenderer->blendEffect == BLEND_NONE || softwareRenderer->blendEffect == BLEND_ALPHA || !GBAWindowControlIsBlendEnable(softwareRenderer->windows[w].control.packed)) {
backdrop |= softwareRenderer->normalPalette[0];
} else {
backdrop |= softwareRenderer->variantPalette[0];
}
int end = softwareRenderer->windows[w].endX;
for (; x < end; ++x) {
uint32_t color = softwareRenderer->row[x];
if (color & FLAG_TARGET_1) {
softwareRenderer->row[x] = _mix(softwareRenderer->bldb, backdrop, softwareRenderer->blda, color);
}
}
}
}
if (softwareRenderer->target1Obj && (softwareRenderer->blendEffect == BLEND_DARKEN || softwareRenderer->blendEffect == BLEND_BRIGHTEN)) {
x = 0;
for (w = 0; w < softwareRenderer->nWindows; ++w) {
if (!GBAWindowControlIsBlendEnable(softwareRenderer->windows[w].control.packed)) {
continue;
}
int end = softwareRenderer->windows[w].endX;
if (softwareRenderer->blendEffect == BLEND_DARKEN) {
for (; x < end; ++x) {
uint32_t color = softwareRenderer->row[x];
if ((color & 0xFF000000) == FLAG_REBLEND) {
softwareRenderer->row[x] = _darken(color, softwareRenderer->bldy);
}
}
} else if (softwareRenderer->blendEffect == BLEND_BRIGHTEN) {
for (; x < end; ++x) {
uint32_t color = softwareRenderer->row[x];
if ((color & 0xFF000000) == FLAG_REBLEND) {
softwareRenderer->row[x] = _brighten(color, softwareRenderer->bldy);
}
}
}
}
}
}
int GBAVideoSoftwareRendererPreprocessSpriteLayer(struct GBAVideoSoftwareRenderer* renderer, int y) {
int w; int w;
renderer->end = 0; renderer->end = 0;
int spriteLayers = 0; int spriteLayers = 0;
@ -757,59 +816,7 @@ static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y) {
} }
} }
} }
return spriteLayers;
unsigned priority;
for (priority = 0; priority < 4; ++priority) {
renderer->end = 0;
for (w = 0; w < renderer->nWindows; ++w) {
renderer->start = renderer->end;
renderer->end = renderer->windows[w].endX;
renderer->currentWindow = renderer->windows[w].control;
if (spriteLayers & (1 << priority)) {
GBAVideoSoftwareRendererPostprocessSprite(renderer, priority);
}
if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(renderer->dispcnt) < 2) {
GBAVideoSoftwareRendererDrawBackgroundMode0(renderer, &renderer->bg[0], y);
}
if (TEST_LAYER_ENABLED(1) && GBARegisterDISPCNTGetMode(renderer->dispcnt) < 2) {
GBAVideoSoftwareRendererDrawBackgroundMode0(renderer, &renderer->bg[1], y);
}
if (TEST_LAYER_ENABLED(2)) {
switch (GBARegisterDISPCNTGetMode(renderer->dispcnt)) {
case 0:
GBAVideoSoftwareRendererDrawBackgroundMode0(renderer, &renderer->bg[2], y);
break;
case 1:
case 2:
GBAVideoSoftwareRendererDrawBackgroundMode2(renderer, &renderer->bg[2], y);
break;
case 3:
GBAVideoSoftwareRendererDrawBackgroundMode3(renderer, &renderer->bg[2], y);
break;
case 4:
GBAVideoSoftwareRendererDrawBackgroundMode4(renderer, &renderer->bg[2], y);
break;
case 5:
GBAVideoSoftwareRendererDrawBackgroundMode5(renderer, &renderer->bg[2], y);
break;
}
}
if (TEST_LAYER_ENABLED(3)) {
switch (GBARegisterDISPCNTGetMode(renderer->dispcnt)) {
case 0:
GBAVideoSoftwareRendererDrawBackgroundMode0(renderer, &renderer->bg[3], y);
break;
case 2:
GBAVideoSoftwareRendererDrawBackgroundMode2(renderer, &renderer->bg[3], y);
break;
}
}
}
}
renderer->bg[2].sx += renderer->bg[2].dmx;
renderer->bg[2].sy += renderer->bg[2].dmy;
renderer->bg[3].sx += renderer->bg[3].dmx;
renderer->bg[3].sy += renderer->bg[3].dmy;
} }
static void _updatePalettes(struct GBAVideoSoftwareRenderer* renderer) { static void _updatePalettes(struct GBAVideoSoftwareRenderer* renderer) {