Core: Generic tile cache, usable with Game Boy core

This commit is contained in:
Jeffrey Pfau 2016-10-17 11:59:31 -07:00
parent 9bef681c7d
commit d462b4dd7f
20 changed files with 558 additions and 258 deletions

View File

@ -2,6 +2,7 @@
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

274
src/core/tile-cache.c Normal file
View File

@ -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;
}

57
src/core/tile-cache.h Normal file
View File

@ -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

View File

@ -222,7 +222,7 @@ void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
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 @@ void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* o
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;
}

View File

@ -5,6 +5,7 @@
* 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 G
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 @@ static void GBVideoSoftwareRendererWritePalette(struct GBVideoRenderer* renderer
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) {

View File

@ -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;
}

View File

@ -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

View File

@ -7,6 +7,7 @@
#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 GBMo
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 @@ static struct GBVideoRenderer dummyRenderer = {
void GBVideoInit(struct GBVideo* video) {
video->renderer = &dummyRenderer;
video->renderer->cache = NULL;
video->vram = 0;
video->frameskip = 0;
}
@ -80,6 +84,7 @@ void GBVideoDeinit(struct GBVideo* video) {
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 @@ static uint8_t GBVideoDummyRendererWriteVideoRegister(struct GBVideoRenderer* re
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) {

View File

@ -53,11 +53,13 @@ union GBOAM {
};
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 @@ struct GBVideoRenderer {
uint8_t* vram;
union GBOAM* oam;
struct mTileCache* cache;
};
DECL_BITFIELD(GBRegisterLCDC, uint8_t);

View File

@ -5,6 +5,7 @@
* 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 @@ void GBAVideoThreadProxyRendererWriteVRAM(struct GBAVideoRenderer* renderer, uin
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 @@ void GBAVideoThreadProxyRendererWritePalette(struct GBAVideoRenderer* renderer,
};
_writeData(proxyRenderer, &dirty, sizeof(dirty));
if (renderer->cache) {
GBAVideoTileCacheWritePalette(renderer->cache, address);
mTileCacheWritePalette(renderer->cache, address);
}
}

View File

@ -5,180 +5,23 @@
* 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"
#include "gba/renderers/tile-cache.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 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 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;
}
void GBAVideoTileCacheDeinit(struct GBAVideoTileCache* cache) {
if (GBAVideoTileCacheConfigurationIsShouldStore(cache->config)) {
mappedMemoryFree(cache->cache, CACHE_SIZE);
cache->cache = NULL;
}
}
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;
}

View File

@ -9,41 +9,9 @@
#include "util/common.h"
struct GBAVideo;
struct mTileCache;
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;
};
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

View File

@ -5,6 +5,7 @@
* 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 uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender
static void GBAVideoSoftwareRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) {
if (renderer->cache) {
GBAVideoTileCacheWriteVRAM(renderer->cache, address);
mTileCacheWriteVRAM(renderer->cache, address);
}
}
@ -377,7 +378,7 @@ static void GBAVideoSoftwareRendererWritePalette(struct GBAVideoRenderer* render
softwareRenderer->variantPalette[address >> 1] = _darken(color, softwareRenderer->bldy);
}
if (renderer->cache) {
GBAVideoTileCacheWritePalette(renderer->cache, address);
mTileCacheWritePalette(renderer->cache, address);
}
}

View File

@ -6,6 +6,7 @@
#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 @@ static struct GBAVideoRenderer dummyRenderer = {
.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 uint16_t GBAVideoDummyRendererWriteVideoRegister(struct GBAVideoRenderer*
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);
}
}

View File

@ -170,7 +170,7 @@ struct GBAVideoRenderer {
uint16_t* palette;
uint16_t* vram;
union GBAOAM* oam;
struct GBAVideoTileCache* cache;
struct mTileCache* cache;
bool disableBG[4];
bool disableOBJ;

View File

@ -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 @@ extern "C" {
#endif
#ifdef M_CORE_GB
#include "gb/gb.h"
#include "gb/renderers/tile-cache.h"
#endif
#include "util/vfs.h"
}
@ -177,6 +179,31 @@ GameController::GameController(QObject* parent)
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 @@ void GameController::cleanGame() {
}
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 @@ void GameController::updateAutofire() {
}
}
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

View File

@ -27,11 +27,11 @@ extern "C" {
#endif
}
struct GBAAudio;
struct GBAVideoTileCache;
struct mCoreConfig;
struct Configuration;
struct GBAAudio;
struct mCoreConfig;
struct mDebugger;
struct mTileCache;
class QThread;
@ -86,9 +86,7 @@ public:
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 @@ private:
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];

View File

@ -53,16 +53,16 @@ void TileView::selectIndex(int 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 @@ void TileView::updateTiles(bool force) {
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;

View File

@ -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 @@ protected:
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;
};

View File

@ -1374,13 +1374,10 @@ void Window::setupMenu(QMenuBar* menubar) {
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()));