GB Video: Draw SGB border pieces that overlap GB graphics (fixes #1339)

This commit is contained in:
Vicki Pfau 2022-01-13 17:19:05 -08:00
parent ca0cfa077e
commit 70f75bba49
3 changed files with 77 additions and 13 deletions

View File

@ -14,6 +14,7 @@ Features:
Emulation fixes:
- ARM7: Fix unsigned multiply timing
- GB Memory: Add cursory cartridge open bus emulation (fixes mgba.io/i/2032)
- GB Video: Draw SGB border pieces that overlap GB graphics (fixes mgba.io/i/1339)
- GBA: Improve timing when not booting from BIOS
- GBA BIOS: Work around IRQ handling hiccup in Mario & Luigi (fixes mgba.io/i/1059)
- GBA I/O: Redo internal key input, enabling edge-based key IRQs

View File

@ -60,6 +60,7 @@ struct GBVideoSoftwareRenderer {
uint8_t sgbPacket[128];
uint8_t sgbCommandHeader;
bool sgbBorders;
uint32_t sgbBorderMask[18];
uint8_t lastHighlightAmount;
};

View File

@ -64,37 +64,58 @@ static void _regenerateSGBBorder(struct GBVideoSoftwareRenderer* renderer) {
}
int x, y;
for (y = 0; y < 224; ++y) {
for (x = 0; x < 256; x += 8) {
if (x >= 48 && x < 208 && y >= 40 && y < 184) {
continue;
int localY = y & 0x7;
if (!localY && y >= 40 && y < 184) {
renderer->sgbBorderMask[(y - 40) >> 3] = 0;
}
for (x = 0; x < 256; x += 8) {
uint16_t mapData;
LOAD_16LE(mapData, (x >> 2) + (y & ~7) * 8, renderer->d.sgbMapRam);
if (UNLIKELY(SGBBgAttributesGetTile(mapData) >= 0x100)) {
continue;
}
int localY = y & 0x7;
if (SGBBgAttributesIsYFlip(mapData)) {
localY = 7 - localY;
if (x >= 48 && x < 208 && y >= 40 && y < 184) {
if (!localY) {
unsigned tileBase = SGBBgAttributesGetTile(mapData) * 8;
uint32_t bits = 0;
bits |= ((uint32_t*) renderer->d.sgbCharRam)[tileBase + 0];
bits |= ((uint32_t*) renderer->d.sgbCharRam)[tileBase + 1];
bits |= ((uint32_t*) renderer->d.sgbCharRam)[tileBase + 2];
bits |= ((uint32_t*) renderer->d.sgbCharRam)[tileBase + 3];
bits |= ((uint32_t*) renderer->d.sgbCharRam)[tileBase + 4];
bits |= ((uint32_t*) renderer->d.sgbCharRam)[tileBase + 5];
bits |= ((uint32_t*) renderer->d.sgbCharRam)[tileBase + 6];
bits |= ((uint32_t*) renderer->d.sgbCharRam)[tileBase + 7];
if (bits) {
renderer->sgbBorderMask[(y - 40) >> 3] |= 1 << ((x - 48) >> 3);
}
}
continue;
}
int yFlip = 0;
if (SGBBgAttributesIsYFlip(mapData)) {
yFlip = 7;
}
unsigned tileBase = (SGBBgAttributesGetTile(mapData) * 16 + (localY ^ yFlip)) * 2;
uint8_t tileData[4];
tileData[0] = renderer->d.sgbCharRam[(SGBBgAttributesGetTile(mapData) * 16 + localY) * 2 + 0x00];
tileData[1] = renderer->d.sgbCharRam[(SGBBgAttributesGetTile(mapData) * 16 + localY) * 2 + 0x01];
tileData[2] = renderer->d.sgbCharRam[(SGBBgAttributesGetTile(mapData) * 16 + localY) * 2 + 0x10];
tileData[3] = renderer->d.sgbCharRam[(SGBBgAttributesGetTile(mapData) * 16 + localY) * 2 + 0x11];
tileData[0] = renderer->d.sgbCharRam[tileBase + 0x00];
tileData[1] = renderer->d.sgbCharRam[tileBase + 0x01];
tileData[2] = renderer->d.sgbCharRam[tileBase + 0x10];
tileData[3] = renderer->d.sgbCharRam[tileBase + 0x11];
size_t base = y * renderer->outputBufferStride + x;
int paletteBase = SGBBgAttributesGetPalette(mapData) * 0x10;
int colorSelector;
int flip = 0;
int xFlip = 0;
if (SGBBgAttributesIsXFlip(mapData)) {
flip = 7;
xFlip = 7;
}
for (i = 7; i >= 0; --i) {
colorSelector = (tileData[0] >> i & 0x1) << 0 | (tileData[1] >> i & 0x1) << 1 | (tileData[2] >> i & 0x1) << 2 | (tileData[3] >> i & 0x1) << 3;
renderer->outputBuffer[(base + 7 - i) ^ flip] = renderer->palette[paletteBase | colorSelector];
renderer->outputBuffer[(base + 7 - i) ^ xFlip] = renderer->palette[paletteBase | colorSelector];
}
}
}
@ -233,6 +254,7 @@ static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer, enum G
}
memset(softwareRenderer->palette, 0, sizeof(softwareRenderer->palette));
memset(softwareRenderer->sgbBorderMask, 0, sizeof(softwareRenderer->sgbBorderMask));
softwareRenderer->lastHighlightAmount = 0;
}
@ -667,6 +689,46 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
for (; x < endX; ++x) {
row[x] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x] & OBJ_PRIO_MASK]];
}
if (softwareRenderer->sgbBorderMask[y >> 3]) {
uint32_t borderMask = softwareRenderer->sgbBorderMask[y >> 3];
int localY = y & 0x7;
for (x = startX; x < endX; x += 8) {
if (!(borderMask & (1 << (x >> 3)))) {
continue;
}
uint16_t mapData;
LOAD_16LE(mapData, (x >> 2) + 12 + (y & ~7) * 8 + 320, softwareRenderer->d.sgbMapRam);
if (UNLIKELY(SGBBgAttributesGetTile(mapData) >= 0x100)) {
continue;
}
int yFlip = 0;
if (SGBBgAttributesIsYFlip(mapData)) {
yFlip = 7;
}
unsigned tileBase = (SGBBgAttributesGetTile(mapData) * 16 + (localY ^ yFlip)) * 2;
uint8_t tileData[4];
tileData[0] = softwareRenderer->d.sgbCharRam[tileBase + 0x00];
tileData[1] = softwareRenderer->d.sgbCharRam[tileBase + 0x01];
tileData[2] = softwareRenderer->d.sgbCharRam[tileBase + 0x10];
tileData[3] = softwareRenderer->d.sgbCharRam[tileBase + 0x11];
int paletteBase = SGBBgAttributesGetPalette(mapData) * 0x10;
int colorSelector;
int flip = 0;
if (SGBBgAttributesIsXFlip(mapData)) {
flip = 7;
}
int i;
for (i = 7; i >= 0; --i) {
colorSelector = (tileData[0] >> i & 0x1) << 0 | (tileData[1] >> i & 0x1) << 1 | (tileData[2] >> i & 0x1) << 2 | (tileData[3] >> i & 0x1) << 3;
if (colorSelector) {
row[(x + 7 - i) ^ flip] = softwareRenderer->palette[paletteBase | colorSelector];
}
}
}
}
break;
case 1:
break;