Core: Still quite buggy map cache

This commit is contained in:
Vicki Pfau 2017-09-17 10:03:30 -07:00
parent df9616c15c
commit c6f0d6c5db
3 changed files with 102 additions and 31 deletions

View File

@ -11,6 +11,7 @@
CXX_GUARD_START
#include <mgba/core/interface.h>
#include <mgba/core/tile-cache.h>
DECL_BITFIELD(mMapCacheConfiguration, uint32_t);
DECL_BIT(mMapCacheConfiguration, ShouldStore, 0);
@ -28,11 +29,13 @@ DECL_BITS(mMapCacheEntryFlags, PaletteId, 0, 4);
DECL_BIT(mMapCacheEntryFlags, VramClean, 4);
DECL_BIT(mMapCacheEntryFlags, HMirror, 5);
DECL_BIT(mMapCacheEntryFlags, VMirror, 6);
DECL_BITS(mMapCacheEntryFlags, Mirror, 5, 2);
struct mMapCacheEntry {
uint32_t vramVersion;
uint16_t tileId;
mMapCacheEntryFlags flags;
struct mTileCacheEntry tileStatus[16];
};
struct mTileCache;
@ -40,7 +43,6 @@ struct mTileCacheEntry;
struct mMapCache {
color_t* cache;
struct mTileCache* tileCache;
struct mTileCacheEntry* tileEntries;
struct mMapCacheEntry* status;
uint8_t* vram;
@ -66,6 +68,8 @@ void mMapCacheWriteVRAM(struct mMapCache* cache, uint32_t address);
bool mMapCacheCheckTile(struct mMapCache* cache, const struct mMapCacheEntry* entry, unsigned x, unsigned y);
void mMapCacheCleanTile(struct mMapCache* cache, struct mMapCacheEntry* entry, unsigned x, unsigned y);
const color_t* mMapCacheGetRow(struct mMapCache* cache, unsigned y);
CXX_GUARD_END
#endif

View File

@ -5,7 +5,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba/core/map-cache.h>
#include <mgba/core/tile-cache.h>
#include <mgba-util/memory.h>
void mMapCacheInit(struct mMapCache* cache) {
@ -34,12 +33,18 @@ static void _redoCacheSize(struct mMapCache* cache) {
}
void mMapCacheConfigure(struct mMapCache* cache, mMapCacheConfiguration config) {
if (config == cache->config) {
return;
}
_freeCache(cache);
cache->config = config;
_redoCacheSize(cache);
}
void mMapCacheConfigureSystem(struct mMapCache* cache, mMapCacheSystemInfo config) {
if (config == cache->sysConfig) {
return;
}
_freeCache(cache);
cache->sysConfig = config;
_redoCacheSize(cache);
@ -60,37 +65,94 @@ void mMapCacheDeinit(struct mMapCache* cache) {
void mMapCacheWriteVRAM(struct mMapCache* cache, uint32_t address) {
if (address >= cache->mapStart && address < cache->mapStart + cache->mapSize) {
address >>= mMapCacheSystemInfoGetMapAlign(cache->sysConfig);
++cache->status[address].vramVersion;
cache->status[address].flags = mMapCacheEntryFlagsClearVramClean(cache->status[address].flags);
address -= cache->mapStart;
struct mMapCacheEntry* status = &cache->status[address >> mMapCacheSystemInfoGetMapAlign(cache->sysConfig)];
++status->vramVersion;
status->flags = mMapCacheEntryFlagsClearVramClean(status->flags);
status->tileStatus[mMapCacheEntryFlagsGetPaletteId(status->flags)].vramClean = 0;
}
}
bool mMapCacheCheckTile(struct mMapCache* cache, const struct mMapCacheEntry* entry, unsigned x, unsigned y) {
size_t location = (1 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig)) * y + x;
const struct mMapCacheEntry* status = &cache->status[location];
return memcmp(status, &entry[location], sizeof(*entry)) == 0;
static inline void _cleanTile(struct mMapCache* cache, const color_t* tile, color_t* mapOut, const struct mMapCacheEntry* status) {
size_t stride = 8 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
int x, y;
switch (mMapCacheEntryFlagsGetMirror(status->flags)) {
case 0:
memcpy(mapOut, tile, sizeof(color_t) * 8);
memcpy(&mapOut[stride], &tile[0x08], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 2], &tile[0x10], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 3], &tile[0x18], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 4], &tile[0x20], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 5], &tile[0x28], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 6], &tile[0x30], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 7], &tile[0x38], sizeof(color_t) * 8);
break;
case 1:
for (y = 0; y < 8; ++y) {
for (x = 0; x < 8; ++x) {
mapOut[y * stride + (7 - x)] = tile[y * 8 + x];
}
}
break;
case 2:
memcpy(&mapOut[stride * 7], tile, sizeof(color_t) * 8);
memcpy(&mapOut[stride * 6], &tile[0x08], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 5], &tile[0x10], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 4], &tile[0x18], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 3], &tile[0x20], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 2], &tile[0x28], sizeof(color_t) * 8);
memcpy(&mapOut[stride], &tile[0x30], sizeof(color_t) * 8);
memcpy(mapOut, &tile[0x38], sizeof(color_t) * 8);
break;
case 3:
for (y = 0; y < 8; ++y) {
for (x = 0; x < 8; ++x) {
mapOut[(7 - y) * stride + (7 - x)] = tile[y * 8 + x];
}
}
break;
}
}
void mMapCacheCleanTile(struct mMapCache* cache, struct mMapCacheEntry* entry, unsigned x, unsigned y) {
size_t location = (1 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig)) * y + x;
struct mMapCacheEntry* status = &cache->status[location];
status->flags = mMapCacheEntryFlagsFillVramClean(status->flags);
int align = mMapCacheSystemInfoGetMapAlign(cache->sysConfig);
cache->mapParser(cache, status, &cache->vram[(location << align) + cache->mapStart]);
int paletteId = mMapCacheEntryFlagsGetPaletteId(status->flags);
const color_t* tile = NULL;
if (!mMapCacheEntryFlagsIsVramClean(status->flags)) {
status->flags = mMapCacheEntryFlagsFillVramClean(status->flags);
cache->mapParser(cache, status, &cache->vram[cache->mapStart + (location << mMapCacheSystemInfoGetMapAlign(cache->sysConfig))]);
tile = mTileCacheGetTileIfDirty(cache->tileCache, &status->tileStatus[paletteId], status->tileId + cache->tileStart, mMapCacheEntryFlagsGetPaletteId(status->flags));
if (!tile) {
tile = mTileCacheGetTile(cache->tileCache, status->tileId + cache->tileStart, mMapCacheEntryFlagsGetPaletteId(status->flags));
}
} else {
tile = mTileCacheGetTileIfDirty(cache->tileCache, &status->tileStatus[paletteId], status->tileId + cache->tileStart, mMapCacheEntryFlagsGetPaletteId(status->flags));
if (!tile && memcmp(status, &entry[location], sizeof(*entry)) == 0) {
return;
}
tile = mTileCacheGetTile(cache->tileCache, status->tileId + cache->tileStart, mMapCacheEntryFlagsGetPaletteId(status->flags));
}
int bytesPerPixel = 1 << mMapCacheSystemInfoGetPaletteBPP(cache->sysConfig);
size_t stride = bytesPerPixel * (1 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig));
size_t stride = 8 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
color_t* mapOut = &cache->cache[(y * stride + x) * 8];
const color_t* tile = mTileCacheGetTileIfDirty(cache->tileCache, cache->tileEntries, status->tileId + cache->tileStart, mMapCacheEntryFlagsGetPaletteId(status->flags));
memcpy(mapOut, tile, sizeof(color_t) * 8);
memcpy(&mapOut[stride], &tile[0x08], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 2], &tile[0x10], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 3], &tile[0x18], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 4], &tile[0x20], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 5], &tile[0x28], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 6], &tile[0x30], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 7], &tile[0x38], sizeof(color_t) * 8);
_cleanTile(cache, tile, mapOut, status);
entry[location] = *status;
}
bool mMapCacheCheckTile(struct mMapCache* cache, const struct mMapCacheEntry* entry, unsigned x, unsigned y) {
size_t location = (1 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig)) * y + x;
struct mMapCacheEntry* status = &cache->status[location];
int paletteId = mMapCacheEntryFlagsGetPaletteId(status->flags);
const color_t* tile = NULL;
if (mMapCacheEntryFlagsIsVramClean(status->flags) && memcmp(status, &entry[location], sizeof(*entry)) == 0) {
tile = mTileCacheGetTileIfDirty(cache->tileCache, &status->tileStatus[paletteId], status->tileId + cache->tileStart, mMapCacheEntryFlagsGetPaletteId(status->flags));
return !tile;
}
return false;
}
const color_t* mMapCacheGetRow(struct mMapCache* cache, unsigned y) {
size_t stride = 8 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
return &cache->cache[y * stride];
}

View File

@ -49,14 +49,19 @@ void GBAVideoCacheAssociate(struct mCacheSet* cache, struct GBAVideo* video) {
for (i = 0; i < SIZE_PALETTE_RAM / 2; ++i) {
mCacheSetWritePalette(cache, i, mColorFrom555(video->palette[i]));
}
GBAVideoCacheWriteVideoRegister(cache, REG_DISPCNT, video->p->memory.io[REG_DISPCNT >> 1]);
GBAVideoCacheWriteVideoRegister(cache, REG_BG0CNT, video->p->memory.io[REG_BG0CNT >> 1]);
GBAVideoCacheWriteVideoRegister(cache, REG_BG1CNT, video->p->memory.io[REG_BG1CNT >> 1]);
GBAVideoCacheWriteVideoRegister(cache, REG_BG2CNT, video->p->memory.io[REG_BG2CNT >> 1]);
GBAVideoCacheWriteVideoRegister(cache, REG_BG3CNT, video->p->memory.io[REG_BG3CNT >> 1]);
}
static void mapParser0(struct mMapCache* cache, struct mMapCacheEntry* entry, void* vram) {
UNUSED(cache);
uint16_t map = *(uint16_t*) vram;
entry->tileId = GBA_TEXT_MAP_TILE(map);
entry->flags = mMapCacheEntryFlagsSetHMirror(entry->flags, GBA_TEXT_MAP_HFLIP(map));
entry->flags = mMapCacheEntryFlagsSetHMirror(entry->flags, GBA_TEXT_MAP_VFLIP(map));
entry->flags = mMapCacheEntryFlagsSetHMirror(entry->flags, !!GBA_TEXT_MAP_HFLIP(map));
entry->flags = mMapCacheEntryFlagsSetVMirror(entry->flags, !!GBA_TEXT_MAP_VFLIP(map));
entry->flags = mMapCacheEntryFlagsSetPaletteId(entry->flags, GBA_TEXT_MAP_PALETTE(map));
}
@ -64,7 +69,7 @@ static void mapParser2(struct mMapCache* cache, struct mMapCacheEntry* entry, vo
UNUSED(cache);
entry->tileId = *(uint8_t*) vram;
entry->flags = mMapCacheEntryFlagsClearHMirror(entry->flags);
entry->flags = mMapCacheEntryFlagsClearHMirror(entry->flags);
entry->flags = mMapCacheEntryFlagsClearVMirror(entry->flags);
entry->flags = mMapCacheEntryFlagsClearPaletteId(entry->flags);
}
@ -89,8 +94,8 @@ static void GBAVideoCacheWriteDISPCNT(struct mCacheSet* cache, uint16_t value) {
mMapCacheSetGetPointer(&cache->maps, 2)->mapParser = mapParser2;
mMapCacheSetGetPointer(&cache->maps, 3)->mapParser = mapParser2;
mMapCacheSetGetPointer(&cache->maps, 0)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 1);
mMapCacheSetGetPointer(&cache->maps, 1)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 1);
mMapCacheSetGetPointer(&cache->maps, 0)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0);
mMapCacheSetGetPointer(&cache->maps, 1)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0);
mMapCacheSetGetPointer(&cache->maps, 2)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 1);
mMapCacheSetGetPointer(&cache->maps, 3)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 1);
break;
@ -100,9 +105,8 @@ static void GBAVideoCacheWriteDISPCNT(struct mCacheSet* cache, uint16_t value) {
static void GBAVideoCacheWriteBGCNT(struct mCacheSet* cache, size_t bg, uint16_t value) {
struct mMapCache* map = mMapCacheSetGetPointer(&cache->maps, bg);
int tileStart = GBARegisterBGCNTGetCharBase(value) * 128;
int tileStart = GBARegisterBGCNTGetCharBase(value) * 256;
bool p = GBARegisterBGCNTGet256Color(value);
mMapCacheConfigureMap(map, GBARegisterBGCNTGetScreenBase(value) << 11);
int size = GBARegisterBGCNTGetSize(value);
int tilesWide = 0;
int tilesHigh = 0;
@ -134,6 +138,7 @@ static void GBAVideoCacheWriteBGCNT(struct mCacheSet* cache, size_t bg, uint16_t
sysconfig = mMapCacheSystemInfoSetTilesHigh(sysconfig, tilesHigh);
sysconfig = mMapCacheSystemInfoSetTilesWide(sysconfig, tilesWide);
mMapCacheConfigureSystem(map, sysconfig);
mMapCacheConfigureMap(map, GBARegisterBGCNTGetScreenBase(value) << 11);
}
void GBAVideoCacheWriteVideoRegister(struct mCacheSet* cache, uint32_t address, uint16_t value) {