all repos — mgba @ d462b4dd7f512de20b6ccb60969049ca727d0121

mGBA Game Boy Advance Emulator

Core: Generic tile cache, usable with Game Boy core
Jeffrey Pfau jeffrey@endrift.com
Mon, 17 Oct 2016 11:59:31 -0700
commit

d462b4dd7f512de20b6ccb60969049ca727d0121

parent

9bef681c7d15ab97afdc306709ea2160ab649d82

M CHANGESCHANGES

@@ -2,6 +2,7 @@ 0.6.0: (Future)

Features: - GBA: Support printing debug strings from inside a game - GBA: Better cheat type autodetection + - GB: Tile viewer Bugfixes: - LR35902: Fix core never exiting with certain event patterns - GB Timer: Improve DIV reset behavior
A src/core/tile-cache.c

@@ -0,0 +1,274 @@

+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "tile-cache.h" + +#include "util/memory.h" + +void mTileCacheInit(struct mTileCache* cache) { + // TODO: Reconfigurable cache for space savings + cache->cache = NULL; + cache->config = mTileCacheConfigurationFillShouldStore(0); + cache->status = NULL; + cache->activePalette = 0; + memset(cache->globalPaletteVersion, 0, sizeof(cache->globalPaletteVersion)); +} + +static void _freeCache(struct mTileCache* cache) { + unsigned count0; + count0 = 1 << mTileCacheSystemInfoGetPalette0Count(cache->sysConfig); + unsigned count1; + count1 = 1 << mTileCacheSystemInfoGetPalette1Count(cache->sysConfig); + unsigned tiles = mTileCacheSystemInfoGetMaxTiles(cache->sysConfig); + unsigned size = count0 > count1 ? count0 : count1; + if (cache->cache) { + mappedMemoryFree(cache->cache, 8 * 8 * 2 * tiles * size); + cache->cache = NULL; + } + if (cache->status) { + mappedMemoryFree(cache->status, tiles * size * sizeof(*cache->status)); + cache->status = NULL; + } + free(cache->globalPaletteVersion[0]); + free(cache->globalPaletteVersion[1]); + memset(cache->globalPaletteVersion, 0, sizeof(cache->globalPaletteVersion)); +} + +static void _redoCacheSize(struct mTileCache* cache) { + if (!mTileCacheConfigurationIsShouldStore(cache->config)) { + return; + } + unsigned count0 = mTileCacheSystemInfoGetPalette0Count(cache->sysConfig); + unsigned bpp0 = mTileCacheSystemInfoGetPalette0BPP(cache->sysConfig); + bpp0 = 1 << (1 << bpp0); + if (count0) { + count0 = 1 << count0; + } + unsigned count1 = mTileCacheSystemInfoGetPalette1Count(cache->sysConfig); + unsigned bpp1 = mTileCacheSystemInfoGetPalette1BPP(cache->sysConfig); + bpp1 = 1 << (1 << bpp1); + if (count1) { + count1 = 1 << count1; + } + unsigned size = count0 > count1 ? count0 : count1; + if (!size) { + return; + } + unsigned tiles = mTileCacheSystemInfoGetMaxTiles(cache->sysConfig); + cache->cache = anonymousMemoryMap(8 * 8 * 2 * tiles * size); + cache->status = anonymousMemoryMap(tiles * size * sizeof(*cache->status)); + if (count0) { + cache->globalPaletteVersion[0] = malloc(count0 * bpp0 * sizeof(*cache->globalPaletteVersion[0])); + } + if (count1) { + cache->globalPaletteVersion[1] = malloc(count1 * bpp1 * sizeof(*cache->globalPaletteVersion[1])); + } +} + +void mTileCacheConfigure(struct mTileCache* cache, mTileCacheConfiguration config) { + _freeCache(cache); + cache->config = config; + _redoCacheSize(cache); +} + +void mTileCacheConfigureSystem(struct mTileCache* cache, mTileCacheSystemInfo config) { + _freeCache(cache); + cache->sysConfig = config; + _redoCacheSize(cache); +} + +void mTileCacheDeinit(struct mTileCache* cache) { + _freeCache(cache); +} + +void mTileCacheWriteVRAM(struct mTileCache* cache, uint32_t address) { + unsigned bpp = cache->bpp + 3; + unsigned count = cache->count; + size_t i; + for (i = 0; i < count; ++i) { + ++cache->status[(address >> bpp) * count + i].vramVersion; + cache->status[(address >> bpp) * count + i].vramClean = 0; + } +} + +void mTileCacheWritePalette(struct mTileCache* cache, uint32_t address) { + if (cache->globalPaletteVersion[0]) { + ++cache->globalPaletteVersion[0][address >> 1]; + } + if (cache->globalPaletteVersion[1]) { + ++cache->globalPaletteVersion[1][address >> 1]; + } +} + +void mTileCacheSetPalette(struct mTileCache* cache, int palette) { + cache->activePalette = palette; + if (palette == 0) { + cache->bpp = mTileCacheSystemInfoGetPalette0BPP(cache->sysConfig); + cache->count = 1 << mTileCacheSystemInfoGetPalette0Count(cache->sysConfig); + } else { + cache->bpp = mTileCacheSystemInfoGetPalette1BPP(cache->sysConfig); + cache->count = 1 << mTileCacheSystemInfoGetPalette1Count(cache->sysConfig); + } + cache->entries = 1 << (1 << cache->bpp); +} + +static void _regenerateTile4(struct mTileCache* cache, uint16_t* tile, unsigned tileId, unsigned paletteId) { + uint8_t* start = (uint8_t*) &cache->vram[tileId << 3]; + paletteId <<= 2; + uint16_t* palette = &cache->palette[paletteId]; + int i; + for (i = 0; i < 8; ++i) { + uint8_t tileDataLower = start[0]; + uint8_t tileDataUpper = start[1]; + start += 2; + int pixel; + pixel = ((tileDataUpper & 128) >> 6) | ((tileDataLower & 128) >> 7); + tile[0] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = ((tileDataUpper & 64) >> 5) | ((tileDataLower & 64) >> 6); + tile[1] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = ((tileDataUpper & 32) >> 4) | ((tileDataLower & 32) >> 5); + tile[2] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = ((tileDataUpper & 16) >> 3) | ((tileDataLower & 16) >> 4); + tile[3] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = ((tileDataUpper & 8) >> 2) | ((tileDataLower & 8) >> 3); + tile[4] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = ((tileDataUpper & 4) >> 1) | ((tileDataLower & 4) >> 2); + tile[5] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (tileDataUpper & 2) | ((tileDataLower & 2) >> 1); + tile[6] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = ((tileDataUpper & 1) << 1) | (tileDataLower & 1); + tile[7] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + tile += 8; + } +} + +static void _regenerateTile16(struct mTileCache* cache, uint16_t* tile, unsigned tileId, unsigned paletteId) { + uint32_t* start = (uint32_t*) &cache->vram[tileId << 4]; + paletteId <<= 4; + uint16_t* palette = &cache->palette[paletteId]; + int i; + for (i = 0; i < 8; ++i) { + uint32_t line = *start; + ++start; + int pixel; + pixel = line & 0xF; + tile[0] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 4) & 0xF; + tile[1] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 8) & 0xF; + tile[2] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 12) & 0xF; + tile[3] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 16) & 0xF; + tile[4] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 20) & 0xF; + tile[5] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 24) & 0xF; + tile[6] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 28) & 0xF; + tile[7] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + tile += 8; + } +} + +static void _regenerateTile256(struct mTileCache* cache, uint16_t* tile, unsigned tileId, unsigned paletteId) { + uint32_t* start = (uint32_t*) &cache->vram[tileId << 5]; + paletteId <<= 8; + uint16_t* palette = &cache->palette[paletteId * 16]; + int i; + for (i = 0; i < 8; ++i) { + uint32_t line = *start; + ++start; + int pixel; + pixel = line & 0xFF; + tile[0] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 8) & 0xFF; + tile[1] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 16) & 0xFF; + tile[2] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 24) & 0xFF; + tile[3] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + + line = *start; + ++start; + pixel = line & 0xFF; + tile[4] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 8) & 0xFF; + tile[5] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 16) & 0xFF; + tile[6] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 24) & 0xFF; + tile[7] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + tile += 8; + } +} + +static inline uint16_t* _tileLookup(struct mTileCache* cache, unsigned tileId, unsigned paletteId) { + if (mTileCacheConfigurationIsShouldStore(cache->config)) { + unsigned tiles = mTileCacheSystemInfoGetMaxTiles(cache->sysConfig); + return &cache->cache[(tileId + paletteId * tiles) << 6]; + } else { + return cache->temporaryTile; + } +} + +const uint16_t* mTileCacheGetTile(struct mTileCache* cache, unsigned tileId, unsigned paletteId) { + unsigned cPaletteId = cache->activePalette; + unsigned count = cache->count; + unsigned bpp = cache->bpp; + struct mTileCacheEntry* status = &cache->status[tileId * count + paletteId]; + uint16_t* tile = _tileLookup(cache, tileId, paletteId); + if (!mTileCacheConfigurationIsShouldStore(cache->config) || !status->vramClean || status->paletteId != cPaletteId || status->paletteVersion != cache->globalPaletteVersion[cPaletteId][paletteId]) { + switch (bpp) { + case 0: + return NULL; + case 1: + _regenerateTile4(cache, tile, tileId, paletteId); + break; + case 2: + _regenerateTile16(cache, tile, tileId, paletteId); + break; + case 3: + _regenerateTile256(cache, tile, tileId, paletteId); + break; + } + status->paletteVersion = cache->globalPaletteVersion[cPaletteId][paletteId]; + status->paletteId = cPaletteId; + status->vramClean = 1; + } + return tile; +} + +const uint16_t* mTileCacheGetTileIfDirty(struct mTileCache* cache, struct mTileCacheEntry* entry, unsigned tileId, unsigned paletteId) { + unsigned cPaletteId = cache->activePalette; + unsigned count = cache->count; + unsigned bpp = cache->bpp; + struct mTileCacheEntry* status = &cache->status[tileId * count + paletteId]; + uint16_t* tile = NULL; + if (!status->vramClean || status->paletteId != cPaletteId || status->paletteVersion != cache->globalPaletteVersion[cPaletteId][paletteId]) { + tile = _tileLookup(cache, tileId, paletteId); + switch (bpp) { + case 0: + return NULL; + case 1: + _regenerateTile4(cache, tile, tileId, paletteId); + break; + case 2: + _regenerateTile16(cache, tile, tileId, paletteId); + break; + case 3: + _regenerateTile256(cache, tile, tileId, paletteId); + break; + } + status->paletteVersion = cache->globalPaletteVersion[cPaletteId][paletteId]; + status->paletteId = cPaletteId; + status->vramClean = 1; + } + if (memcmp(status, &entry[paletteId], sizeof(*status))) { + tile = _tileLookup(cache, tileId, paletteId); + entry[paletteId] = *status; + } + return tile; +}
A src/core/tile-cache.h

@@ -0,0 +1,57 @@

+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_TILE_CACHE_H +#define M_TILE_CACHE_H + +#include "util/common.h" + +DECL_BITFIELD(mTileCacheConfiguration, uint32_t); +DECL_BIT(mTileCacheConfiguration, ShouldStore, 0); + +DECL_BITFIELD(mTileCacheSystemInfo, uint32_t); +DECL_BITS(mTileCacheSystemInfo, Palette0BPP, 0, 2); +DECL_BITS(mTileCacheSystemInfo, Palette0Count, 2, 4); +DECL_BITS(mTileCacheSystemInfo, Palette1BPP, 8, 2); +DECL_BITS(mTileCacheSystemInfo, Palette1Count, 10, 4); +DECL_BITS(mTileCacheSystemInfo, MaxTiles, 16, 13); + +struct mTileCacheEntry { + uint32_t paletteVersion; + uint32_t vramVersion; + uint8_t vramClean; + uint8_t paletteId; +}; + +struct mTileCache { + uint16_t* cache; + struct mTileCacheEntry* status; + uint32_t* globalPaletteVersion[2]; + + int activePalette; + unsigned entries; + unsigned count; + unsigned bpp; + + uint16_t* vram; + uint16_t* palette; + uint16_t temporaryTile[64]; + + mTileCacheConfiguration config; + mTileCacheSystemInfo sysConfig; +}; + +void mTileCacheInit(struct mTileCache* cache); +void mTileCacheDeinit(struct mTileCache* cache); +void mTileCacheConfigure(struct mTileCache* cache, mTileCacheConfiguration config); +void mTileCacheConfigureSystem(struct mTileCache* cache, mTileCacheSystemInfo config); +void mTileCacheWriteVRAM(struct mTileCache* cache, uint32_t address); +void mTileCacheWritePalette(struct mTileCache* cache, uint32_t address); +void mTileCacheSetPalette(struct mTileCache* cache, int palette); + +const uint16_t* mTileCacheGetTile(struct mTileCache* cache, unsigned tileId, unsigned paletteId); +const uint16_t* mTileCacheGetTileIfDirty(struct mTileCache* cache, struct mTileCacheEntry* entry, unsigned tileId, unsigned paletteId); + +#endif
M src/gb/memory.csrc/gb/memory.c

@@ -222,7 +222,7 @@ cpu->memory.setActiveRegion(cpu, cpu->pc);

return; case GB_REGION_VRAM: case GB_REGION_VRAM + 1: - // TODO: Block access in wrong modes + gb->video.renderer->writeVRAM(gb->video.renderer, (address & (GB_SIZE_VRAM_BANK0 - 1)) | (GB_SIZE_VRAM_BANK0 * gb->video.vramCurrentBank)); gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)] = value; return; case GB_REGION_EXTERNAL_RAM:

@@ -531,9 +531,11 @@ case GB_REGION_VRAM + 1:

if (segment < 0) { oldValue = gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)]; gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)] = value; + gb->video.renderer->writeVRAM(gb->video.renderer, (address & (GB_SIZE_VRAM_BANK0 - 1)) + GB_SIZE_VRAM_BANK0 * gb->video.vramCurrentBank); } else if (segment < 2) { oldValue = gb->video.vram[(address & (GB_SIZE_VRAM_BANK0 - 1)) + segment * GB_SIZE_VRAM_BANK0]; gb->video.vramBank[(address & (GB_SIZE_VRAM_BANK0 - 1)) + segment * GB_SIZE_VRAM_BANK0] = value; + gb->video.renderer->writeVRAM(gb->video.renderer, (address & (GB_SIZE_VRAM_BANK0 - 1)) + segment * GB_SIZE_VRAM_BANK0); } else { return; }
M src/gb/renderers/software.csrc/gb/renderers/software.c

@@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this

* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "software.h" +#include "core/tile-cache.h" #include "gb/io.h" #include "util/memory.h"

@@ -12,6 +13,7 @@ static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer, enum GBModel model);

static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer); static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value); static void GBVideoSoftwareRendererWritePalette(struct GBVideoRenderer* renderer, int index, uint16_t value); +static void GBVideoSoftwareRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address); static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj* obj, size_t oamMax); static void GBVideoSoftwareRendererFinishScanline(struct GBVideoRenderer* renderer, int y); static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer);

@@ -50,7 +52,8 @@ void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer* renderer) {

renderer->d.init = GBVideoSoftwareRendererInit; renderer->d.deinit = GBVideoSoftwareRendererDeinit; renderer->d.writeVideoRegister = GBVideoSoftwareRendererWriteVideoRegister; - renderer->d.writePalette = GBVideoSoftwareRendererWritePalette, + renderer->d.writePalette = GBVideoSoftwareRendererWritePalette; + renderer->d.writeVRAM = GBVideoSoftwareRendererWriteVRAM; renderer->d.drawRange = GBVideoSoftwareRendererDrawRange; renderer->d.finishScanline = GBVideoSoftwareRendererFinishScanline; renderer->d.finishFrame = GBVideoSoftwareRendererFinishFrame;

@@ -120,6 +123,15 @@ color |= (value << 6) & 0xF800;

color |= (value << 9) & 0xF80000; #endif softwareRenderer->palette[index] = color; + if (renderer->cache) { + mTileCacheWritePalette(renderer->cache, index << 1); + } +} + +static void GBVideoSoftwareRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address) { + if (renderer->cache) { + mTileCacheWriteVRAM(renderer->cache, address); + } } static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj* obj, size_t oamMax) {
A src/gb/renderers/tile-cache.c

@@ -0,0 +1,27 @@

+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "tile-cache.h" + +#include "core/tile-cache.h" +#include "gb/video.h" +#include "gb/renderers/tile-cache.h" + +void GBVideoTileCacheInit(struct mTileCache* cache) { + mTileCacheInit(cache); + mTileCacheConfiguration config = 0; + config = mTileCacheSystemInfoSetPalette0BPP(config, 1); // 2^(2^2) = 4 entries + config = mTileCacheSystemInfoSetPalette0Count(config, 4); // 16 palettes + config = mTileCacheSystemInfoSetPalette1BPP(config, 0); // Disable + config = mTileCacheSystemInfoSetPalette1Count(config, 0); // Disable + config = mTileCacheSystemInfoSetMaxTiles(config, 1024); + mTileCacheConfigureSystem(cache, config); +} + +void GBVideoTileCacheAssociate(struct mTileCache* cache, struct GBVideo* video) { + cache->vram = (uint16_t*) video->vram; + cache->palette = video->palette; + video->renderer->cache = cache; +}
A src/gb/renderers/tile-cache.h

@@ -0,0 +1,17 @@

+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_TILE_CACHE_H +#define GB_TILE_CACHE_H + +#include "util/common.h" + +struct GBVideo; +struct mTileCache; + +void GBVideoTileCacheInit(struct mTileCache* cache); +void GBVideoTileCacheAssociate(struct mTileCache* cache, struct GBVideo* video); + +#endif
M src/gb/video.csrc/gb/video.c

@@ -7,6 +7,7 @@ #include "video.h"

#include "core/sync.h" #include "core/thread.h" +#include "core/tile-cache.h" #include "gb/gb.h" #include "gb/io.h" #include "gb/serialize.h"

@@ -17,6 +18,7 @@ static void GBVideoDummyRendererInit(struct GBVideoRenderer* renderer, enum GBModel model);

static void GBVideoDummyRendererDeinit(struct GBVideoRenderer* renderer); static uint8_t GBVideoDummyRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value); static void GBVideoDummyRendererWritePalette(struct GBVideoRenderer* renderer, int index, uint16_t value); +static void GBVideoDummyRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address); static void GBVideoDummyRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj* obj, size_t oamMax); static void GBVideoDummyRendererFinishScanline(struct GBVideoRenderer* renderer, int y); static void GBVideoDummyRendererFinishFrame(struct GBVideoRenderer* renderer);

@@ -29,6 +31,7 @@ static struct GBVideoRenderer dummyRenderer = {

.init = GBVideoDummyRendererInit, .deinit = GBVideoDummyRendererDeinit, .writeVideoRegister = GBVideoDummyRendererWriteVideoRegister, + .writeVRAM = GBVideoDummyRendererWriteVRAM, .writePalette = GBVideoDummyRendererWritePalette, .drawRange = GBVideoDummyRendererDrawRange, .finishScanline = GBVideoDummyRendererFinishScanline,

@@ -39,6 +42,7 @@ };

void GBVideoInit(struct GBVideo* video) { video->renderer = &dummyRenderer; + video->renderer->cache = NULL; video->vram = 0; video->frameskip = 0; }

@@ -80,6 +84,7 @@ }

void GBVideoAssociateRenderer(struct GBVideo* video, struct GBVideoRenderer* renderer) { video->renderer->deinit(video->renderer); + renderer->cache = video->renderer->cache; video->renderer = renderer; renderer->vram = video->vram; video->renderer->init(video->renderer, video->p->model);

@@ -426,10 +431,17 @@ UNUSED(address);

return value; } +static void GBVideoDummyRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address) { + if (renderer->cache) { + mTileCacheWriteVRAM(renderer->cache, address); + } +} + static void GBVideoDummyRendererWritePalette(struct GBVideoRenderer* renderer, int index, uint16_t value) { - UNUSED(renderer); - UNUSED(index); UNUSED(value); + if (renderer->cache) { + mTileCacheWritePalette(renderer->cache, index << 1); + } } static void GBVideoDummyRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj* obj, size_t oamMax) {
M src/gb/video.hsrc/gb/video.h

@@ -53,11 +53,13 @@ uint8_t raw[160];

}; enum GBModel; +struct mTileCache; struct GBVideoRenderer { void (*init)(struct GBVideoRenderer* renderer, enum GBModel model); void (*deinit)(struct GBVideoRenderer* renderer); uint8_t (*writeVideoRegister)(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value); + void (*writeVRAM)(struct GBVideoRenderer* renderer, uint16_t address); void (*writePalette)(struct GBVideoRenderer* renderer, int index, uint16_t value); void (*drawRange)(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj* objOnLine, size_t nObj); void (*finishScanline)(struct GBVideoRenderer* renderer, int y);

@@ -68,6 +70,7 @@ void (*putPixels)(struct GBVideoRenderer* renderer, size_t stride, const void* pixels);

uint8_t* vram; union GBOAM* oam; + struct mTileCache* cache; }; DECL_BITFIELD(GBRegisterLCDC, uint8_t);
M src/gba/renderers/thread-proxy.csrc/gba/renderers/thread-proxy.c

@@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this

* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "thread-proxy.h" +#include "core/tile-cache.h" #include "gba/io.h" #include "gba/renderers/tile-cache.h"

@@ -194,6 +195,9 @@ if (proxyRenderer->vramDirtyBitmap & bit) {

return; } proxyRenderer->vramDirtyBitmap |= bit; + if (renderer->cache) { + mTileCacheWriteVRAM(renderer->cache, address); + } } void GBAVideoThreadProxyRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {

@@ -206,7 +210,7 @@ 0xDEADBEEF,

}; _writeData(proxyRenderer, &dirty, sizeof(dirty)); if (renderer->cache) { - GBAVideoTileCacheWritePalette(renderer->cache, address); + mTileCacheWritePalette(renderer->cache, address); } }
M src/gba/renderers/tile-cache.csrc/gba/renderers/tile-cache.c

@@ -5,180 +5,23 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this

* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "tile-cache.h" +#include "core/tile-cache.h" #include "gba/video.h" -#include "util/memory.h" - -#define CACHE_SIZE (8 * 8 * 2 * 1024 * 3 * 16) - -void GBAVideoTileCacheInit(struct GBAVideoTileCache* cache) { - // TODO: Reconfigurable cache for space savings - cache->cache = anonymousMemoryMap(CACHE_SIZE); - cache->config = GBAVideoTileCacheConfigurationFillShouldStore(0); - memset(cache->status, 0, sizeof(cache->status)); - memset(cache->globalPaletteVersion, 0, sizeof(cache->globalPaletteVersion)); - memset(cache->globalPalette256Version, 0, sizeof(cache->globalPalette256Version)); -} - -void GBAVideoTileCacheConfigure(struct GBAVideoTileCache* cache, GBAVideoTileCacheConfiguration config) { - if (GBAVideoTileCacheConfigurationIsShouldStore(cache->config) || !GBAVideoTileCacheConfigurationIsShouldStore(config)) { - mappedMemoryFree(cache->cache, CACHE_SIZE); - cache->cache = NULL; - } else if (!GBAVideoTileCacheConfigurationIsShouldStore(cache->config) || GBAVideoTileCacheConfigurationIsShouldStore(config)) { - cache->cache = anonymousMemoryMap(CACHE_SIZE); - } - cache->config = config; -} - +#include "gba/renderers/tile-cache.h" -void GBAVideoTileCacheDeinit(struct GBAVideoTileCache* cache) { - if (GBAVideoTileCacheConfigurationIsShouldStore(cache->config)) { - mappedMemoryFree(cache->cache, CACHE_SIZE); - cache->cache = NULL; - } +void GBAVideoTileCacheInit(struct mTileCache* cache) { + mTileCacheInit(cache); + mTileCacheConfiguration config = 0; + config = mTileCacheSystemInfoSetPalette0BPP(config, 2); // 2^(2^2) = 16 entries + config = mTileCacheSystemInfoSetPalette0Count(config, 5); // 32 palettes + config = mTileCacheSystemInfoSetPalette1BPP(config, 3); // 2^(2^3) = 256 entries + config = mTileCacheSystemInfoSetPalette1Count(config, 1); // 2 palettes + config = mTileCacheSystemInfoSetMaxTiles(config, 3072); + mTileCacheConfigureSystem(cache, config); } -void GBAVideoTileCacheAssociate(struct GBAVideoTileCache* cache, struct GBAVideo* video) { +void GBAVideoTileCacheAssociate(struct mTileCache* cache, struct GBAVideo* video) { cache->vram = video->vram; cache->palette = video->palette; video->renderer->cache = cache; } - -void GBAVideoTileCacheWriteVRAM(struct GBAVideoTileCache* cache, uint32_t address) { - size_t i; - for (i = 0; i < 16; ++i) { - ++cache->status[address >> 5][i].vramVersion; - cache->status[address >> 5][i].vramClean = 0; - } -} - -void GBAVideoTileCacheWritePalette(struct GBAVideoTileCache* cache, uint32_t address) { - ++cache->globalPaletteVersion[address >> 5]; - ++cache->globalPalette256Version[address >> 9]; -} - -static void _regenerateTile16(struct GBAVideoTileCache* cache, uint16_t* tile, unsigned tileId, unsigned paletteId) { - uint32_t* start = (uint32_t*) &cache->vram[tileId << 4]; - paletteId <<= 4; - uint16_t* palette = &cache->palette[paletteId]; - int i; - for (i = 0; i < 8; ++i) { - uint32_t line = *start; - ++start; - int pixel; - pixel = line & 0xF; - tile[0] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; - pixel = (line >> 4) & 0xF; - tile[1] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; - pixel = (line >> 8) & 0xF; - tile[2] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; - pixel = (line >> 12) & 0xF; - tile[3] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; - pixel = (line >> 16) & 0xF; - tile[4] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; - pixel = (line >> 20) & 0xF; - tile[5] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; - pixel = (line >> 24) & 0xF; - tile[6] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; - pixel = (line >> 28) & 0xF; - tile[7] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; - tile += 8; - } -} - -static void _regenerateTile256(struct GBAVideoTileCache* cache, uint16_t* tile, unsigned tileId, unsigned paletteId) { - uint32_t* start = (uint32_t*) &cache->vram[tileId << 5]; - paletteId <<= 8; - uint16_t* palette = &cache->palette[paletteId * 16]; - int i; - for (i = 0; i < 8; ++i) { - uint32_t line = *start; - ++start; - int pixel; - pixel = line & 0xFF; - tile[0] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; - pixel = (line >> 8) & 0xFF; - tile[1] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; - pixel = (line >> 16) & 0xFF; - tile[2] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; - pixel = (line >> 24) & 0xFF; - tile[3] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; - - line = *start; - ++start; - pixel = line & 0xFF; - tile[4] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; - pixel = (line >> 8) & 0xFF; - tile[5] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; - pixel = (line >> 16) & 0xFF; - tile[6] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; - pixel = (line >> 24) & 0xFF; - tile[7] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; - tile += 8; - } -} - -static inline uint16_t* _tileLookup(struct GBAVideoTileCache* cache, unsigned tileId, unsigned paletteId) { - if (GBAVideoTileCacheConfigurationIsShouldStore(cache->config)) { - return &cache->cache[((tileId << 4) + (paletteId & 0xF)) << 6]; - } else { - return cache->temporaryTile; - } -} - -const uint16_t* GBAVideoTileCacheGetTile16(struct GBAVideoTileCache* cache, unsigned tileId, unsigned paletteId) { - struct GBAVideoTileCacheEntry* status = &cache->status[tileId][paletteId & 0xF]; - uint16_t* tile = _tileLookup(cache, tileId, paletteId); - if (!GBAVideoTileCacheConfigurationIsShouldStore(cache->config) || !status->vramClean || status->palette256 || status->paletteVersion != cache->globalPaletteVersion[paletteId]) { - _regenerateTile16(cache, tile, tileId, paletteId); - status->paletteVersion = cache->globalPaletteVersion[paletteId]; - status->palette256 = 0; - status->vramClean = 1; - } - return tile; -} - -const uint16_t* GBAVideoTileCacheGetTile16IfDirty(struct GBAVideoTileCache* cache, GBAVideoTileCacheStatus handle, unsigned tileId, unsigned paletteId) { - struct GBAVideoTileCacheEntry* status = &cache->status[tileId][paletteId & 0xF]; - uint16_t* tile = NULL; - if (!status->vramClean || status->palette256 || status->paletteVersion != cache->globalPaletteVersion[paletteId]) { - tile = _tileLookup(cache, tileId, paletteId); - _regenerateTile16(cache, tile, tileId, paletteId); - status->paletteVersion = cache->globalPaletteVersion[paletteId]; - status->palette256 = 0; - status->vramClean = 1; - } - if (memcmp(status, &handle[tileId][paletteId & 0xF], sizeof(*status))) { - tile = _tileLookup(cache, tileId, paletteId); - handle[tileId][paletteId & 0xF] = *status; - } - return tile; -} - -const uint16_t* GBAVideoTileCacheGetTile256(struct GBAVideoTileCache* cache, unsigned tileId, unsigned paletteId) { - struct GBAVideoTileCacheEntry* status = &cache->status[tileId][paletteId]; - uint16_t* tile = _tileLookup(cache, tileId, paletteId); - if (!GBAVideoTileCacheConfigurationIsShouldStore(cache->config) || !status->vramClean || !status->palette256 || status->paletteVersion != cache->globalPalette256Version[paletteId]) { - _regenerateTile256(cache, tile, tileId, paletteId); - status->paletteVersion = cache->globalPalette256Version[paletteId]; - status->palette256 = 1; - status->vramClean = 1; - } - return tile; -} - -const uint16_t* GBAVideoTileCacheGetTile256IfDirty(struct GBAVideoTileCache* cache, GBAVideoTileCacheStatus handle, unsigned tileId, unsigned paletteId) { - struct GBAVideoTileCacheEntry* status = &cache->status[tileId][paletteId]; - uint16_t* tile = NULL; - if (!status->vramClean || !status->palette256 || status->paletteVersion != cache->globalPalette256Version[paletteId]) { - tile = _tileLookup(cache, tileId, paletteId); - _regenerateTile256(cache, tile, tileId, paletteId); - status->paletteVersion = cache->globalPalette256Version[paletteId]; - status->palette256 = 1; - status->vramClean = 1; - } - if (memcmp(status, &handle[tileId][paletteId], sizeof(*status))) { - tile = _tileLookup(cache, tileId, paletteId); - handle[tileId][paletteId] = *status; - } - return tile; -}
M src/gba/renderers/tile-cache.hsrc/gba/renderers/tile-cache.h

@@ -9,41 +9,9 @@

#include "util/common.h" struct GBAVideo; - -DECL_BITFIELD(GBAVideoTileCacheConfiguration, uint32_t); -DECL_BIT(GBAVideoTileCacheConfiguration, ShouldStore, 0); - -struct GBAVideoTileCacheEntry { - uint32_t paletteVersion; - uint32_t vramVersion; - uint8_t vramClean; - uint8_t palette256; -}; - -typedef struct GBAVideoTileCacheEntry GBAVideoTileCacheStatus[1024 * 3][16]; - -struct GBAVideoTileCache { - uint16_t* cache; - GBAVideoTileCacheStatus status; - uint32_t globalPaletteVersion[32]; - uint32_t globalPalette256Version[2]; - - uint16_t* vram; - uint16_t* palette; - uint16_t temporaryTile[64]; - - GBAVideoTileCacheConfiguration config; -}; +struct mTileCache; -void GBAVideoTileCacheInit(struct GBAVideoTileCache* cache); -void GBAVideoTileCacheDeinit(struct GBAVideoTileCache* cache); -void GBAVideoTileCacheConfigure(struct GBAVideoTileCache* cache, GBAVideoTileCacheConfiguration config); -void GBAVideoTileCacheAssociate(struct GBAVideoTileCache* cache, struct GBAVideo* video); -void GBAVideoTileCacheWriteVRAM(struct GBAVideoTileCache* cache, uint32_t address); -void GBAVideoTileCacheWritePalette(struct GBAVideoTileCache* cache, uint32_t address); -const uint16_t* GBAVideoTileCacheGetTile16(struct GBAVideoTileCache* cache, unsigned tileId, unsigned paletteId); -const uint16_t* GBAVideoTileCacheGetTile16IfDirty(struct GBAVideoTileCache* cache, GBAVideoTileCacheStatus handle, unsigned tileId, unsigned paletteId); -const uint16_t* GBAVideoTileCacheGetTile256(struct GBAVideoTileCache* cache, unsigned tileId, unsigned paletteId); -const uint16_t* GBAVideoTileCacheGetTile256IfDirty(struct GBAVideoTileCache* cache, GBAVideoTileCacheStatus handle, unsigned tileId, unsigned paletteId); +void GBAVideoTileCacheInit(struct mTileCache* cache); +void GBAVideoTileCacheAssociate(struct mTileCache* cache, struct GBAVideo* video); #endif
M src/gba/renderers/video-software.csrc/gba/renderers/video-software.c

@@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this

* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "software-private.h" +#include "core/tile-cache.h" #include "gba/gba.h" #include "gba/io.h" #include "gba/renderers/tile-cache.h"

@@ -343,7 +344,7 @@ }

static void GBAVideoSoftwareRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) { if (renderer->cache) { - GBAVideoTileCacheWriteVRAM(renderer->cache, address); + mTileCacheWriteVRAM(renderer->cache, address); } }

@@ -377,7 +378,7 @@ } else if (softwareRenderer->blendEffect == BLEND_DARKEN) {

softwareRenderer->variantPalette[address >> 1] = _darken(color, softwareRenderer->bldy); } if (renderer->cache) { - GBAVideoTileCacheWritePalette(renderer->cache, address); + mTileCacheWritePalette(renderer->cache, address); } }
M src/gba/video.csrc/gba/video.c

@@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "video.h" #include "core/sync.h" +#include "core/tile-cache.h" #include "gba/gba.h" #include "gba/io.h" #include "gba/renderers/tile-cache.h"

@@ -59,11 +60,11 @@ .drawScanline = GBAVideoDummyRendererDrawScanline,

.finishFrame = GBAVideoDummyRendererFinishFrame, .getPixels = GBAVideoDummyRendererGetPixels, .putPixels = GBAVideoDummyRendererPutPixels, - .cache = NULL }; void GBAVideoInit(struct GBAVideo* video) { video->renderer = &dummyRenderer; + video->renderer->cache = NULL; video->vram = 0; video->frameskip = 0; }

@@ -250,14 +251,14 @@ }

static void GBAVideoDummyRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) { if (renderer->cache) { - GBAVideoTileCacheWriteVRAM(renderer->cache, address); + mTileCacheWriteVRAM(renderer->cache, address); } } static void GBAVideoDummyRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) { UNUSED(value); if (renderer->cache) { - GBAVideoTileCacheWritePalette(renderer->cache, address); + mTileCacheWritePalette(renderer->cache, address); } }
M src/gba/video.hsrc/gba/video.h

@@ -170,7 +170,7 @@

uint16_t* palette; uint16_t* vram; union GBAOAM* oam; - struct GBAVideoTileCache* cache; + struct mTileCache* cache; bool disableBG[4]; bool disableOBJ;
M src/platform/qt/GameController.cppsrc/platform/qt/GameController.cpp

@@ -21,6 +21,7 @@ extern "C" {

#include "core/config.h" #include "core/directories.h" #include "core/serialize.h" +#include "core/tile-cache.h" #ifdef M_CORE_GBA #include "gba/bios.h" #include "gba/core.h"

@@ -30,6 +31,7 @@ #include "gba/renderers/tile-cache.h"

#endif #ifdef M_CORE_GB #include "gb/gb.h" +#include "gb/renderers/tile-cache.h" #endif #include "util/vfs.h" }

@@ -177,6 +179,31 @@ unsigned width, height;

controller->m_threadContext.core->desiredVideoDimensions(controller->m_threadContext.core, &width, &height); memcpy(controller->m_frontBuffer, controller->m_drawContext, width * height * BYTES_PER_PIXEL); QMetaObject::invokeMethod(controller, "frameAvailable", Q_ARG(const uint32_t*, controller->m_frontBuffer)); + + // If no one is using the tile cache, disable it + if (controller->m_tileCache && controller->m_tileCache.unique()) { + switch (controller->platform()) { +#ifdef M_CORE_GBA + case PLATFORM_GBA: { + GBA* gba = static_cast<GBA*>(context->core->board); + gba->video.renderer->cache = nullptr; + break; + } +#endif +#ifdef M_CORE_GB + case PLATFORM_GB: { + GB* gb = static_cast<GB*>(context->core->board); + gb->video.renderer->cache = nullptr; + break; + } +#endif + default: + break; + } + controller->m_tileCache.reset(); + } + + if (controller->m_pauseAfterFrame.testAndSetAcquire(true, false)) { mCoreThreadPauseFromThread(context); QMetaObject::invokeMethod(controller, "gamePaused", Q_ARG(mCoreThread*, context));

@@ -587,12 +614,10 @@ return;

} mCoreThreadJoin(&m_threadContext); -#ifdef M_CORE_GBA if (m_tileCache) { - GBAVideoTileCacheDeinit(m_tileCache.get()); + mTileCacheDeinit(m_tileCache.get()); m_tileCache.reset(); } -#endif delete[] m_drawContext; delete[] m_frontBuffer;

@@ -1201,20 +1226,37 @@ }

} } +std::shared_ptr<mTileCache> GameController::tileCache() { + if (m_tileCache) { + return m_tileCache; + } + switch (platform()) { #ifdef M_CORE_GBA -struct GBAVideoTileCache* GameController::tileCache() { - if (platform() != PLATFORM_GBA) { + case PLATFORM_GBA: { + threadInterrupt(); + GBA* gba = static_cast<GBA*>(m_threadContext.core->board); + m_tileCache = std::make_shared<mTileCache>(); + GBAVideoTileCacheInit(m_tileCache.get()); + GBAVideoTileCacheAssociate(m_tileCache.get(), &gba->video); + mTileCacheSetPalette(m_tileCache.get(), 0); + threadContinue(); + break; + } +#endif +#ifdef M_CORE_GB + case PLATFORM_GB: { + threadInterrupt(); + GB* gb = static_cast<GB*>(m_threadContext.core->board); + m_tileCache = std::make_shared<mTileCache>(); + GBVideoTileCacheInit(m_tileCache.get()); + GBVideoTileCacheAssociate(m_tileCache.get(), &gb->video); + mTileCacheSetPalette(m_tileCache.get(), 0); + threadContinue(); + break; + } +#endif + default: return nullptr; } - if (m_tileCache) { - return m_tileCache.get(); - } - threadInterrupt(); - GBA* gba = static_cast<GBA*>(m_threadContext.core->board); - m_tileCache = std::unique_ptr<GBAVideoTileCache>(new GBAVideoTileCache); - GBAVideoTileCacheInit(m_tileCache.get()); - GBAVideoTileCacheAssociate(m_tileCache.get(), &gba->video); - threadContinue(); - return m_tileCache.get(); + return m_tileCache; } -#endif
M src/platform/qt/GameController.hsrc/platform/qt/GameController.h

@@ -27,11 +27,11 @@ #include "platform/sdl/sdl-events.h"

#endif } +struct Configuration; struct GBAAudio; -struct GBAVideoTileCache; struct mCoreConfig; -struct Configuration; struct mDebugger; +struct mTileCache; class QThread;

@@ -86,9 +86,7 @@ mDebugger* debugger();

void setDebugger(mDebugger*); #endif -#ifdef M_CORE_GBA - GBAVideoTileCache* tileCache(); -#endif + std::shared_ptr<mTileCache> tileCache(); signals: void frameAvailable(const uint32_t*);

@@ -215,9 +213,7 @@ bool m_turboForced;

float m_turboSpeed; bool m_wasPaused; -#ifdef M_CORE_GBA - std::unique_ptr<GBAVideoTileCache> m_tileCache; -#endif + std::shared_ptr<mTileCache> m_tileCache; bool m_audioChannels[6]; bool m_videoLayers[5];
M src/platform/qt/TileView.cppsrc/platform/qt/TileView.cpp

@@ -53,16 +53,16 @@ m_ui.tileId->setText(QString::number(index));

if (m_ui.palette256->isChecked()) { m_ui.address->setText(tr("0x%0").arg(index * 64 | BASE_VRAM, 8, 16, QChar('0'))); if (index < 1024) { - data = GBAVideoTileCacheGetTile256(m_tileCache, index, 0); + data = mTileCacheGetTile(m_tileCache.get(), index, 0); } else { - data = GBAVideoTileCacheGetTile256(m_tileCache, index, 1); + data = mTileCacheGetTile(m_tileCache.get(), index, 1); } } else { m_ui.address->setText(tr("0x%0").arg(index * 32 | BASE_VRAM, 8, 16, QChar('0'))); if (index < 2048) { - data = GBAVideoTileCacheGetTile16(m_tileCache, index, m_paletteId); + data = mTileCacheGetTile(m_tileCache.get(), index, m_paletteId); } else { - data = GBAVideoTileCacheGetTile16(m_tileCache, index, m_paletteId + 16); + data = mTileCacheGetTile(m_tileCache.get(), index, m_paletteId + 16); } } for (int i = 0; i < 64; ++i) {

@@ -76,44 +76,80 @@ if (!m_controller->thread() || !m_controller->thread()->core) {

return; } + switch (m_controller->platform()) { +#ifdef M_CORE_GBA + case PLATFORM_GBA: + updateTilesGBA(force); + break; +#endif +#ifdef M_CORE_GB + case PLATFORM_GB: + updateTilesGB(force); + break; +#endif + default: + return; + } +} + +#ifdef M_CORE_GBA +void TileView::updateTilesGBA(bool force) { if (m_ui.palette256->isChecked()) { m_ui.tiles->setTileCount(1536); + mTileCacheSetPalette(m_tileCache.get(), 1); for (int i = 0; i < 1024; ++i) { - const uint16_t* data = GBAVideoTileCacheGetTile256IfDirty(m_tileCache, m_tileStatus, i, 0); + const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache.get(), &m_tileStatus[32 * i], i, 0); if (data) { m_ui.tiles->setTile(i, data); } else if (force) { - m_ui.tiles->setTile(i, GBAVideoTileCacheGetTile256(m_tileCache, i, 0)); + m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache.get(), i, 0)); } } for (int i = 1024; i < 1536; ++i) { - const uint16_t* data = GBAVideoTileCacheGetTile256IfDirty(m_tileCache, m_tileStatus, i, 1); + const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache.get(), &m_tileStatus[32 * i], i, 1); if (data) { m_ui.tiles->setTile(i, data); } else if (force) { - m_ui.tiles->setTile(i, GBAVideoTileCacheGetTile256(m_tileCache, i, 1)); + m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache.get(), i, 1)); } } } else { m_ui.tiles->setTileCount(3072); + mTileCacheSetPalette(m_tileCache.get(), 0); for (int i = 0; i < 2048; ++i) { - const uint16_t* data = GBAVideoTileCacheGetTile16IfDirty(m_tileCache, m_tileStatus, i, m_paletteId); + const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache.get(), &m_tileStatus[32 * i], i, m_paletteId); if (data) { m_ui.tiles->setTile(i, data); } else if (force) { - m_ui.tiles->setTile(i, GBAVideoTileCacheGetTile16(m_tileCache, i, m_paletteId)); + m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache.get(), i, m_paletteId)); } } for (int i = 2048; i < 3072; ++i) { - const uint16_t* data = GBAVideoTileCacheGetTile16IfDirty(m_tileCache, m_tileStatus, i, m_paletteId + 16); + const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache.get(), &m_tileStatus[32 * i], i, m_paletteId + 16); if (data) { m_ui.tiles->setTile(i, data); } else if (force) { - m_ui.tiles->setTile(i, GBAVideoTileCacheGetTile16(m_tileCache, i, m_paletteId + 16)); + m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache.get(), i, m_paletteId + 16)); } } } } +#endif + +#ifdef M_CORE_GB +void TileView::updateTilesGB(bool force) { + m_ui.tiles->setTileCount(1024); + mTileCacheSetPalette(m_tileCache.get(), 0); + for (int i = 0; i < 1024; ++i) { + const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache.get(), &m_tileStatus[16 * i], i, m_paletteId); + if (data) { + m_ui.tiles->setTile(i, data); + } else if (force) { + m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache.get(), i, m_paletteId)); + } + } +} +#endif void TileView::updatePalette(int palette) { m_paletteId = palette;
M src/platform/qt/TileView.hsrc/platform/qt/TileView.h

@@ -13,7 +13,7 @@

#include "ui_TileView.h" extern "C" { -#include "gba/renderers/tile-cache.h" +#include "core/tile-cache.h" } namespace QGBA {

@@ -36,11 +36,18 @@ void resizeEvent(QResizeEvent*) override;

void showEvent(QShowEvent*) override; private: +#ifdef M_CORE_GBA + void updateTilesGBA(bool force); +#endif +#ifdef M_CORE_GB + void updateTilesGB(bool force); +#endif + Ui::TileView m_ui; GameController* m_controller; - GBAVideoTileCache* m_tileCache; - GBAVideoTileCacheStatus m_tileStatus; + std::shared_ptr<mTileCache> m_tileCache; + mTileCacheEntry m_tileStatus[3072 * 32]; // TODO: Correct size int m_paletteId; QTimer m_updateTimer; };
M src/platform/qt/Window.cppsrc/platform/qt/Window.cpp

@@ -1374,13 +1374,10 @@ connect(paletteView, SIGNAL(triggered()), this, SLOT(openPaletteWindow()));

m_gameActions.append(paletteView); addControlledAction(toolsMenu, paletteView, "paletteWindow"); -#ifdef M_CORE_GBA QAction* tileView = new QAction(tr("View &tiles..."), toolsMenu); connect(tileView, SIGNAL(triggered()), this, SLOT(openTileWindow())); m_gameActions.append(tileView); - m_gbaActions.append(tileView); addControlledAction(toolsMenu, tileView, "tileWindow"); -#endif QAction* memoryView = new QAction(tr("View memory..."), toolsMenu); connect(memoryView, SIGNAL(triggered()), this, SLOT(openMemoryWindow()));