GBA Video: Implement green swap (fixes #1609)

This commit is contained in:
Vicki Pfau 2020-08-31 22:28:19 -07:00
parent 6a97b1dbf5
commit c825c57281
5 changed files with 45 additions and 11 deletions

View File

@ -42,6 +42,7 @@ Emulation fixes:
- GBA Video: Fix Hblank timing
- GBA Video: Invalidate map cache when modifying BGCNT (fixes mgba.io/i/1846)
- GBA Video: Don't draw sprites using unmapped VRAM in GL renderer (fixes mgba.io/i/1865)
- GBA Video: Implement green swap (fixes mgba.io/i/1609)
- SM83: Emulate HALT bug
Other fixes:
- 3DS: Redo video sync to be more precise

View File

@ -36,6 +36,23 @@ typedef uint32_t color_t;
#define M_RGB8_TO_BGR5(X) ((((X) & 0xF8) >> 3) | (((X) & 0xF800) >> 6) | (((X) & 0xF80000) >> 9))
#define M_RGB8_TO_RGB5(X) ((((X) & 0xF8) << 7) | (((X) & 0xF800) >> 6) | (((X) & 0xF80000) >> 19))
#ifndef COLOR_16_BIT
#define M_COLOR_RED 0x000000FF
#define M_COLOR_GREEN 0x0000FF00
#define M_COLOR_BLUE 0x00FF0000
#define M_COLOR_ALPHA 0xFF000000
#elif defined(COLOR_5_6_5)
#define M_COLOR_RED 0x001F
#define M_COLOR_GREEN 0x07E0
#define M_COLOR_BLUE 0xF800
#define M_COLOR_ALPHA 0x0000
#else
#define M_COLOR_RED 0x001F
#define M_COLOR_GREEN 0x03E0
#define M_COLOR_BLUE 0x7C00
#define M_COLOR_ALPHA 0x1000
#endif
#ifndef PYCPARSE
static inline color_t mColorFrom555(uint16_t value) {
#ifdef COLOR_16_BIT

View File

@ -114,6 +114,7 @@ struct GBAVideoSoftwareRenderer {
uint16_t bldy;
GBAMosaicControl mosaic;
bool greenswap;
struct WindowN {
struct GBAVideoWindowRegion h;

View File

@ -341,7 +341,7 @@ void GBAIOInit(struct GBA* gba) {
}
void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) {
if (address < REG_SOUND1CNT_LO && (address > REG_VCOUNT || address == REG_DISPCNT)) {
if (address < REG_SOUND1CNT_LO && (address > REG_VCOUNT || address < REG_DISPSTAT)) {
value = gba->video.renderer->writeVideoRegister(gba->video.renderer, address, value);
} else {
switch (address) {

View File

@ -122,6 +122,7 @@ static void GBAVideoSoftwareRendererReset(struct GBAVideoRenderer* renderer) {
softwareRenderer->oamMax = 0;
softwareRenderer->mosaic = 0;
softwareRenderer->greenswap = false;
softwareRenderer->nextY = 0;
softwareRenderer->objOffsetX = 0;
@ -179,6 +180,9 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender
softwareRenderer->dispcnt = value;
GBAVideoSoftwareRendererUpdateDISPCNT(softwareRenderer);
break;
case REG_GREENSWP:
softwareRenderer->greenswap = value & 1;
break;
case REG_BG0CNT:
value &= 0xDFFF;
GBAVideoSoftwareRendererWriteBGCNT(softwareRenderer, &softwareRenderer->bg[0], value);
@ -389,9 +393,6 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender
case REG_MOSAIC:
softwareRenderer->mosaic = value;
break;
case REG_GREENSWP:
mLOG(GBA_VIDEO, STUB, "Stub video register write: 0x%03X", address);
break;
default:
mLOG(GBA_VIDEO, GAME_ERROR, "Invalid video register: 0x%03X", address);
}
@ -675,16 +676,30 @@ static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* render
}
}
if (softwareRenderer->greenswap) {
for (x = 0; x < GBA_VIDEO_HORIZONTAL_PIXELS; x += 4) {
row[x] = softwareRenderer->row[x] & (M_COLOR_RED | M_COLOR_BLUE);
row[x] |= softwareRenderer->row[x + 1] & M_COLOR_GREEN;
row[x + 1] = softwareRenderer->row[x + 1] & (M_COLOR_RED | M_COLOR_BLUE);
row[x + 1] |= softwareRenderer->row[x] & M_COLOR_GREEN;
row[x + 2] = softwareRenderer->row[x + 2] & (M_COLOR_RED | M_COLOR_BLUE);
row[x + 2] |= softwareRenderer->row[x + 3] & M_COLOR_GREEN;
row[x + 3] = softwareRenderer->row[x + 3] & (M_COLOR_RED | M_COLOR_BLUE);
row[x + 3] |= softwareRenderer->row[x + 2] & M_COLOR_GREEN;
}
} else {
#ifdef COLOR_16_BIT
for (x = 0; x < GBA_VIDEO_HORIZONTAL_PIXELS; x += 4) {
row[x] = softwareRenderer->row[x];
row[x + 1] = softwareRenderer->row[x + 1];
row[x + 2] = softwareRenderer->row[x + 2];
row[x + 3] = softwareRenderer->row[x + 3];
}
for (x = 0; x < GBA_VIDEO_HORIZONTAL_PIXELS; x += 4) {
row[x] = softwareRenderer->row[x];
row[x + 1] = softwareRenderer->row[x + 1];
row[x + 2] = softwareRenderer->row[x + 2];
row[x + 3] = softwareRenderer->row[x + 3];
}
#else
memcpy(row, softwareRenderer->row, GBA_VIDEO_HORIZONTAL_PIXELS * sizeof(*row));
memcpy(row, softwareRenderer->row, GBA_VIDEO_HORIZONTAL_PIXELS * sizeof(*row));
#endif
}
}
static void GBAVideoSoftwareRendererFinishFrame(struct GBAVideoRenderer* renderer) {