diff --git a/include/mgba/internal/ds/renderers/software.h b/include/mgba/internal/ds/renderers/software.h index 6d7eb4673..6b591dbac 100644 --- a/include/mgba/internal/ds/renderers/software.h +++ b/include/mgba/internal/ds/renderers/software.h @@ -32,6 +32,10 @@ struct DSVideoSoftwareRenderer { color_t extPaletteB[16384]; color_t variantPaletteA[16384]; color_t variantPaletteB[16384]; + color_t objExtPaletteA[4096]; + color_t objExtPaletteB[4096]; + color_t objVariantPaletteA[4096]; + color_t objVariantPaletteB[4096]; }; void DSVideoSoftwareRendererCreate(struct DSVideoSoftwareRenderer* renderer); diff --git a/include/mgba/internal/ds/video.h b/include/mgba/internal/ds/video.h index 35cf9ba41..395114fc1 100644 --- a/include/mgba/internal/ds/video.h +++ b/include/mgba/internal/ds/video.h @@ -86,11 +86,11 @@ struct DSVideoRenderer { uint16_t* vramABG[32]; uint16_t* vramAOBJ[32]; uint16_t* vramABGExtPal[4]; - uint16_t* vramAOBJExtPal[4]; + uint16_t* vramAOBJExtPal; uint16_t* vramBBG[32]; uint16_t* vramBOBJ[32]; uint16_t* vramBBGExtPal[4]; - uint16_t* vramBOBJExtPal[4]; + uint16_t* vramBOBJExtPal; union DSOAM* oam; }; @@ -109,11 +109,11 @@ struct DSVideo { uint16_t* vramABG[32]; uint16_t* vramAOBJ[32]; uint16_t* vramABGExtPal[4]; - uint16_t* vramAOBJExtPal[4]; + uint16_t* vramAOBJExtPal; uint16_t* vramBBG[32]; uint16_t* vramBOBJ[32]; uint16_t* vramBBGExtPal[4]; - uint16_t* vramBOBJExtPal[4]; + uint16_t* vramBOBJExtPal; union DSOAM oam; int32_t frameCounter; diff --git a/include/mgba/internal/gba/renderers/video-software.h b/include/mgba/internal/gba/renderers/video-software.h index c4ed2d5cd..93729374e 100644 --- a/include/mgba/internal/gba/renderers/video-software.h +++ b/include/mgba/internal/gba/renderers/video-software.h @@ -132,6 +132,8 @@ struct GBAVideoSoftwareRenderer { enum BlendEffect blendEffect; color_t normalPalette[512]; color_t variantPalette[512]; + color_t* objExtPalette; + color_t* objExtVariantPalette; uint16_t blda; uint16_t bldb; diff --git a/src/ds/renderers/software.c b/src/ds/renderers/software.c index 93ebdf858..7b52c4537 100644 --- a/src/ds/renderers/software.c +++ b/src/ds/renderers/software.c @@ -21,21 +21,35 @@ static void DSVideoSoftwareRendererFinishFrame(struct DSVideoRenderer* renderer) static void DSVideoSoftwareRendererGetPixels(struct DSVideoRenderer* renderer, size_t* stride, const void** pixels); static void DSVideoSoftwareRendererPutPixels(struct DSVideoRenderer* renderer, size_t stride, const void* pixels); -static bool _regenerateExtPalette(struct DSVideoSoftwareRenderer* renderer, bool engB, int slot) { +static bool _regenerateExtPalette(struct DSVideoSoftwareRenderer* renderer, bool obj, bool engB, int slot) { color_t* palette; color_t* variantPalette; struct GBAVideoSoftwareRenderer* softwareRenderer; uint16_t* vram; - if (!engB) { - palette = &renderer->extPaletteA[slot * 4096]; - variantPalette = &renderer->variantPaletteA[slot * 4096]; - softwareRenderer = &renderer->engA; - vram = renderer->d.vramABGExtPal[slot]; + if (!obj) { + if (!engB) { + palette = &renderer->extPaletteA[slot * 4096]; + variantPalette = &renderer->variantPaletteA[slot * 4096]; + softwareRenderer = &renderer->engA; + vram = renderer->d.vramABGExtPal[slot]; + } else { + palette = &renderer->extPaletteB[slot * 4096]; + variantPalette = &renderer->variantPaletteB[slot * 4096]; + softwareRenderer = &renderer->engB; + vram = renderer->d.vramBBGExtPal[slot]; + } } else { - palette = &renderer->extPaletteB[slot * 4096]; - variantPalette = &renderer->variantPaletteB[slot * 4096]; - softwareRenderer = &renderer->engB; - vram = renderer->d.vramBBGExtPal[slot]; + if (!engB) { + palette = renderer->objExtPaletteA; + variantPalette = renderer->variantPaletteA; + softwareRenderer = &renderer->engA; + vram = renderer->d.vramAOBJExtPal; + } else { + palette = renderer->objExtPaletteB; + variantPalette = renderer->variantPaletteB; + softwareRenderer = &renderer->engB; + vram = renderer->d.vramBOBJExtPal; + } } if (!vram) { return false; @@ -154,7 +168,7 @@ static void DSVideoSoftwareRendererUpdateDISPCNT(struct DSVideoSoftwareRenderer* if (i < 2 && GBARegisterBGCNTIsExtPaletteSlot(eng->bg[i].control)) { slot += 2; } - if (eng->bg[i].extPalette != &extPalette[slot * 4096] && _regenerateExtPalette(softwareRenderer, engB, slot)) { + if (eng->bg[i].extPalette != &extPalette[slot * 4096] && _regenerateExtPalette(softwareRenderer, false, engB, slot)) { eng->bg[i].extPalette = &extPalette[slot * 4096]; } } @@ -164,6 +178,19 @@ static void DSVideoSoftwareRendererUpdateDISPCNT(struct DSVideoSoftwareRenderer* eng->bg[2].extPalette = NULL; eng->bg[3].extPalette = NULL; } + if (DSRegisterDISPCNTIsObjExtPalette(dispcnt)) { + if (!engB) { + softwareRenderer->engA.objExtPalette = softwareRenderer->objExtPaletteA; + } else { + softwareRenderer->engB.objExtPalette = softwareRenderer->objExtPaletteB; + } + } else { + if (!engB) { + softwareRenderer->engA.objExtPalette = NULL; + } else { + softwareRenderer->engB.objExtPalette = NULL; + } + } if (!engB) { uint32_t charBase = DSRegisterDISPCNTGetCharBase(softwareRenderer->dispcntA) << 16; uint32_t screenBase = DSRegisterDISPCNTGetScreenBase(softwareRenderer->dispcntA) << 16; @@ -251,7 +278,7 @@ static void DSVideoSoftwareRendererWriteOAM(struct DSVideoRenderer* renderer, ui static void DSVideoSoftwareRendererInvalidateExtPal(struct DSVideoRenderer* renderer, bool obj, bool engB, int slot) { struct DSVideoSoftwareRenderer* softwareRenderer = (struct DSVideoSoftwareRenderer*) renderer; - _regenerateExtPalette(softwareRenderer, engB, slot); + _regenerateExtPalette(softwareRenderer, obj, engB, slot); } static void DSVideoSoftwareRendererDrawGBAScanline(struct GBAVideoRenderer* renderer, int y) { diff --git a/src/ds/video.c b/src/ds/video.c index 4a9a968da..38ee90fdf 100644 --- a/src/ds/video.c +++ b/src/ds/video.c @@ -195,11 +195,11 @@ void DSVideoAssociateRenderer(struct DSVideo* video, struct DSVideoRenderer* ren memcpy(renderer->vramABG, video->vramABG, sizeof(renderer->vramABG)); memcpy(renderer->vramAOBJ, video->vramAOBJ, sizeof(renderer->vramAOBJ)); memcpy(renderer->vramABGExtPal, video->vramABGExtPal, sizeof(renderer->vramABGExtPal)); - memcpy(renderer->vramAOBJExtPal, video->vramAOBJExtPal, sizeof(renderer->vramAOBJExtPal)); + renderer->vramAOBJExtPal = video->vramAOBJExtPal; memcpy(renderer->vramBBG, video->vramBBG, sizeof(renderer->vramBBG)); memcpy(renderer->vramBOBJ, video->vramBOBJ, sizeof(renderer->vramBOBJ)); memcpy(renderer->vramBBGExtPal, video->vramBBGExtPal, sizeof(renderer->vramBBGExtPal)); - memcpy(renderer->vramBOBJExtPal, video->vramBOBJExtPal, sizeof(renderer->vramBOBJExtPal)); + renderer->vramBOBJExtPal = video->vramBOBJExtPal; renderer->oam = &video->oam; video->renderer->init(video->renderer); } @@ -395,6 +395,20 @@ void DSVideoConfigureVRAM(struct DS* ds, int index, uint8_t value, uint8_t oldVa } } break; + case MODE_A_OBJ_EXT_PAL: + if (ds->video.vramAOBJExtPal == memory->vramBank[index]) { + ds->video.vramAOBJExtPal = NULL; + ds->video.renderer->vramAOBJExtPal = NULL; + ds->video.renderer->invalidateExtPal(ds->video.renderer, true, false, 0); + } + break; + case MODE_B_OBJ_EXT_PAL: + if (ds->video.vramBOBJExtPal == memory->vramBank[index]) { + ds->video.vramBOBJExtPal = NULL; + ds->video.renderer->vramBOBJExtPal = NULL; + ds->video.renderer->invalidateExtPal(ds->video.renderer, true, true, 0); + } + break; case MODE_7_VRAM: for (i = 0; i < size; i += 16) { ds->memory.vram7[(offset + i) >> 4] = NULL; @@ -458,6 +472,16 @@ void DSVideoConfigureVRAM(struct DS* ds, int index, uint8_t value, uint8_t oldVa ds->video.renderer->invalidateExtPal(ds->video.renderer, false, true, offset + i); } break; + case MODE_A_OBJ_EXT_PAL: + ds->video.vramAOBJExtPal = memory->vramBank[index]; + ds->video.renderer->vramAOBJExtPal = ds->video.vramAOBJExtPal; + ds->video.renderer->invalidateExtPal(ds->video.renderer, true, false, 0); + break; + case MODE_B_OBJ_EXT_PAL: + ds->video.vramBOBJExtPal = memory->vramBank[index]; + ds->video.renderer->vramBOBJExtPal = ds->video.vramBOBJExtPal; + ds->video.renderer->invalidateExtPal(ds->video.renderer, true, true, 0); + break; case MODE_7_VRAM: for (i = 0; i < size; i += 16) { ds->memory.vram7[(offset + i) >> 4] = &memory->vramBank[index][i << (DS_VRAM_OFFSET - 5)]; diff --git a/src/gba/renderers/software-mode0.c b/src/gba/renderers/software-mode0.c index da8ff5e1f..7c35a8097 100644 --- a/src/gba/renderers/software-mode0.c +++ b/src/gba/renderers/software-mode0.c @@ -364,7 +364,7 @@ } \ } -#define DRAW_BACKGROUND_MODE_0_TILE_SUFFIX_256Ext(BLEND, OBJWIN) \ +#define DRAW_BACKGROUND_MODE_0_TILE_SUFFIX_256EXT(BLEND, OBJWIN) \ paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 8; \ palette = &mainPalette[paletteData]; \ charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \ @@ -414,7 +414,7 @@ pixel = &renderer->row[outX]; \ } -#define DRAW_BACKGROUND_MODE_0_TILE_PREFIX_256Ext(BLEND, OBJWIN) \ +#define DRAW_BACKGROUND_MODE_0_TILE_PREFIX_256EXT(BLEND, OBJWIN) \ charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \ vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \ if (UNLIKELY(!vram)) { \ @@ -463,7 +463,7 @@ } \ } -#define DRAW_BACKGROUND_MODE_0_TILES_256Ext(BLEND, OBJWIN) \ +#define DRAW_BACKGROUND_MODE_0_TILES_256EXT(BLEND, OBJWIN) \ for (; tileX < tileEnd; ++tileX) { \ BACKGROUND_TEXT_SELECT_CHARACTER; \ paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 8; \ @@ -511,7 +511,7 @@ } \ } -#define DRAW_BACKGROUND_MODE_0_MOSAIC_256Ext(BLEND, OBJWIN) \ +#define DRAW_BACKGROUND_MODE_0_MOSAIC_256EXT(BLEND, OBJWIN) \ for (; tileX < tileEnd; ++tileX) { \ BACKGROUND_TEXT_SELECT_CHARACTER; \ charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \ @@ -685,7 +685,7 @@ void GBAVideoSoftwareRendererDrawBackgroundMode0(struct GBAVideoSoftwareRenderer } else if (!background->extPalette) { DRAW_BACKGROUND_MODE_0(256, NoBlend, NO_OBJWIN); } else { - DRAW_BACKGROUND_MODE_0(256Ext, NoBlend, NO_OBJWIN); + DRAW_BACKGROUND_MODE_0(256EXT, NoBlend, NO_OBJWIN); } } else { if (!background->multipalette) { @@ -693,7 +693,7 @@ void GBAVideoSoftwareRendererDrawBackgroundMode0(struct GBAVideoSoftwareRenderer } else if (!background->extPalette) { DRAW_BACKGROUND_MODE_0(256, Blend, NO_OBJWIN); } else { - DRAW_BACKGROUND_MODE_0(256Ext, Blend, NO_OBJWIN); + DRAW_BACKGROUND_MODE_0(256EXT, Blend, NO_OBJWIN); } } } else { @@ -703,7 +703,7 @@ void GBAVideoSoftwareRendererDrawBackgroundMode0(struct GBAVideoSoftwareRenderer } else if (!background->extPalette) { DRAW_BACKGROUND_MODE_0(256, NoBlend, OBJWIN); } else { - DRAW_BACKGROUND_MODE_0(256Ext, NoBlend, OBJWIN); + DRAW_BACKGROUND_MODE_0(256EXT, NoBlend, OBJWIN); } } else { if (!background->multipalette) { @@ -711,7 +711,7 @@ void GBAVideoSoftwareRendererDrawBackgroundMode0(struct GBAVideoSoftwareRenderer } else if (!background->extPalette) { DRAW_BACKGROUND_MODE_0(256, Blend, OBJWIN); } else { - DRAW_BACKGROUND_MODE_0(256Ext, Blend, OBJWIN); + DRAW_BACKGROUND_MODE_0(256EXT, Blend, OBJWIN); } } } diff --git a/src/gba/renderers/software-obj.c b/src/gba/renderers/software-obj.c index 2555e8d94..be79c6dfb 100644 --- a/src/gba/renderers/software-obj.c +++ b/src/gba/renderers/software-obj.c @@ -178,7 +178,7 @@ int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* re int32_t x = (uint32_t) GBAObjAttributesBGetX(sprite->b) << 23; x >>= 23; unsigned charBase = GBAObjAttributesCGetTile(sprite->c) * renderer->tileStride; - if (GBARegisterDISPCNTGetMode(renderer->dispcnt) >= 3 && GBAObjAttributesCGetTile(sprite->c) < 512) { + if (!renderer->d.vramOBJ[charBase >> VRAM_BLOCK_OFFSET]) { return 0; } if (renderer->spriteCyclesRemaining <= 0) { @@ -202,7 +202,9 @@ int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* re color_t* objwinPalette = palette; int objwinSlowPath = GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt) && GBAWindowControlGetBlendEnable(renderer->objwin.packed) != GBAWindowControlIsBlendEnable(renderer->currentWindow.packed); - if (variant) { + if (GBAObjAttributesAIs256Color(sprite->a) && renderer->objExtPalette) { + palette = renderer->objExtPalette; + } else if (variant) { palette = &renderer->variantPalette[0x100]; if (GBAWindowControlIsBlendEnable(renderer->objwin.packed)) { objwinPalette = palette; diff --git a/src/gba/renderers/video-software.c b/src/gba/renderers/video-software.c index f434f7e66..d446ed5be 100644 --- a/src/gba/renderers/video-software.c +++ b/src/gba/renderers/video-software.c @@ -100,6 +100,8 @@ static void GBAVideoSoftwareRendererReset(struct GBAVideoRenderer* renderer) { LOAD_16(entry, i, softwareRenderer->d.palette); GBAVideoSoftwareRendererWritePalette(renderer, i, entry); } + softwareRenderer->objExtPalette = NULL; + softwareRenderer->objExtVariantPalette = NULL; _updatePalettes(softwareRenderer); softwareRenderer->blda = 0; @@ -497,8 +499,14 @@ static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* render return; } + uint16_t* objVramBase = softwareRenderer->d.vramOBJ[0]; + if (GBARegisterDISPCNTGetMode(softwareRenderer->dispcnt) >= 3) { + softwareRenderer->d.vramOBJ[0] = NULL; // OBJ VRAM bottom is blocked in bitmap modes + } + GBAVideoSoftwareRendererPreprocessBuffer(softwareRenderer, y); int spriteLayers = GBAVideoSoftwareRendererPreprocessSpriteLayer(softwareRenderer, y); + softwareRenderer->d.vramOBJ[0] = objVramBase; int w; unsigned priority;