GBA Video: Allow multiple handles into the same tile cache

This commit is contained in:
Jeffrey Pfau 2016-10-16 18:23:28 -07:00
parent 250c19b91c
commit 9bef681c7d
7 changed files with 81 additions and 43 deletions

View File

@ -16,6 +16,7 @@ Misc:
- SDL: Remove scancode key input
- GBA Video: Clean up unused timers
- Test: Add a basic test suite
- GBA Video: Allow multiple handles into the same tile cache
0.5.1: (2016-10-05)
Bugfixes:

View File

@ -46,6 +46,7 @@ void GBAVideoTileCacheAssociate(struct GBAVideoTileCache* cache, struct GBAVideo
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;
}
}
@ -136,20 +137,23 @@ const uint16_t* GBAVideoTileCacheGetTile16(struct GBAVideoTileCache* cache, unsi
return tile;
}
const uint16_t* GBAVideoTileCacheGetTile16IfDirty(struct GBAVideoTileCache* cache, unsigned tileId, unsigned paletteId) {
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]) {
uint16_t* tile = _tileLookup(cache, tileId, paletteId);
tile = _tileLookup(cache, tileId, paletteId);
_regenerateTile16(cache, tile, tileId, paletteId);
status->paletteVersion = cache->globalPaletteVersion[paletteId];
status->palette256 = 0;
status->vramClean = 1;
return tile;
}
return NULL;
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);
@ -162,15 +166,19 @@ const uint16_t* GBAVideoTileCacheGetTile256(struct GBAVideoTileCache* cache, uns
return tile;
}
const uint16_t* GBAVideoTileCacheGetTile256IfDirty(struct GBAVideoTileCache* cache, unsigned tileId, unsigned paletteId) {
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]) {
uint16_t* tile = _tileLookup(cache, tileId, paletteId);
tile = _tileLookup(cache, tileId, paletteId);
_regenerateTile256(cache, tile, tileId, paletteId);
status->paletteVersion = cache->globalPalette256Version[paletteId];
status->palette256 = 1;
status->vramClean = 1;
return tile;
}
return NULL;
if (memcmp(status, &handle[tileId][paletteId], sizeof(*status))) {
tile = _tileLookup(cache, tileId, paletteId);
handle[tileId][paletteId] = *status;
}
return tile;
}

View File

@ -13,13 +13,18 @@ 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;
struct GBAVideoTileCacheEntry {
uint32_t paletteVersion;
uint8_t vramClean;
uint8_t palette256;
} status[1024 * 3][16];
GBAVideoTileCacheStatus status;
uint32_t globalPaletteVersion[32];
uint32_t globalPalette256Version[2];
@ -37,8 +42,8 @@ void GBAVideoTileCacheAssociate(struct GBAVideoTileCache* cache, struct GBAVideo
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, 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, unsigned tileId, unsigned paletteId);
const uint16_t* GBAVideoTileCacheGetTile256IfDirty(struct GBAVideoTileCache* cache, GBAVideoTileCacheStatus handle, unsigned tileId, unsigned paletteId);
#endif

View File

@ -26,6 +26,7 @@ extern "C" {
#include "gba/core.h"
#include "gba/gba.h"
#include "gba/extra/sharkport.h"
#include "gba/renderers/tile-cache.h"
#endif
#ifdef M_CORE_GB
#include "gb/gb.h"
@ -586,6 +587,13 @@ void GameController::cleanGame() {
}
mCoreThreadJoin(&m_threadContext);
#ifdef M_CORE_GBA
if (m_tileCache) {
GBAVideoTileCacheDeinit(m_tileCache.get());
m_tileCache.reset();
}
#endif
delete[] m_drawContext;
delete[] m_frontBuffer;
@ -1192,3 +1200,21 @@ void GameController::updateAutofire() {
}
}
}
#ifdef M_CORE_GBA
struct GBAVideoTileCache* GameController::tileCache() {
if (platform() != PLATFORM_GBA) {
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();
}
#endif

View File

@ -28,6 +28,7 @@ extern "C" {
}
struct GBAAudio;
struct GBAVideoTileCache;
struct mCoreConfig;
struct Configuration;
struct mDebugger;
@ -85,6 +86,10 @@ public:
void setDebugger(mDebugger*);
#endif
#ifdef M_CORE_GBA
GBAVideoTileCache* tileCache();
#endif
signals:
void frameAvailable(const uint32_t*);
void gameStarted(mCoreThread*, const QString& fname);
@ -210,6 +215,10 @@ private:
float m_turboSpeed;
bool m_wasPaused;
#ifdef M_CORE_GBA
std::unique_ptr<GBAVideoTileCache> m_tileCache;
#endif
bool m_audioChannels[6];
bool m_videoLayers[5];

View File

@ -19,10 +19,11 @@ using namespace QGBA;
TileView::TileView(GameController* controller, QWidget* parent)
: QWidget(parent)
, m_controller(controller)
, m_tileStatus{}
, m_tileCache(controller->tileCache())
, m_paletteId(0)
{
m_ui.setupUi(this);
GBAVideoTileCacheInit(&m_tileCache);
m_ui.preview->setDimensions(QSize(8, 8));
m_updateTimer.setSingleShot(true);
@ -46,31 +47,22 @@ TileView::TileView(GameController* controller, QWidget* parent)
});
}
TileView::~TileView() {
if (m_controller->isLoaded() && m_controller->thread() && m_controller->thread()->core) {
GBA* gba = static_cast<GBA*>(m_controller->thread()->core->board);
gba->video.renderer->cache = nullptr;
}
GBAVideoTileCacheDeinit(&m_tileCache);
}
void TileView::selectIndex(int index) {
const uint16_t* data;
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 = GBAVideoTileCacheGetTile256(m_tileCache, index, 0);
} else {
data = GBAVideoTileCacheGetTile256(&m_tileCache, index, 1);
data = GBAVideoTileCacheGetTile256(m_tileCache, 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 = GBAVideoTileCacheGetTile16(m_tileCache, index, m_paletteId);
} else {
data = GBAVideoTileCacheGetTile16(&m_tileCache, index, m_paletteId + 16);
data = GBAVideoTileCacheGetTile16(m_tileCache, index, m_paletteId + 16);
}
}
for (int i = 0; i < 64; ++i) {
@ -84,43 +76,40 @@ void TileView::updateTiles(bool force) {
return;
}
GBA* gba = static_cast<GBA*>(m_controller->thread()->core->board);
GBAVideoTileCacheAssociate(&m_tileCache, &gba->video);
if (m_ui.palette256->isChecked()) {
m_ui.tiles->setTileCount(1536);
for (int i = 0; i < 1024; ++i) {
const uint16_t* data = GBAVideoTileCacheGetTile256IfDirty(&m_tileCache, i, 0);
const uint16_t* data = GBAVideoTileCacheGetTile256IfDirty(m_tileCache, m_tileStatus, 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, GBAVideoTileCacheGetTile256(m_tileCache, i, 0));
}
}
for (int i = 1024; i < 1536; ++i) {
const uint16_t* data = GBAVideoTileCacheGetTile256IfDirty(&m_tileCache, i, 1);
const uint16_t* data = GBAVideoTileCacheGetTile256IfDirty(m_tileCache, m_tileStatus, 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, GBAVideoTileCacheGetTile256(m_tileCache, i, 1));
}
}
} else {
m_ui.tiles->setTileCount(3072);
for (int i = 0; i < 2048; ++i) {
const uint16_t* data = GBAVideoTileCacheGetTile16IfDirty(&m_tileCache, i, m_paletteId);
const uint16_t* data = GBAVideoTileCacheGetTile16IfDirty(m_tileCache, m_tileStatus, 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, GBAVideoTileCacheGetTile16(m_tileCache, i, m_paletteId));
}
}
for (int i = 2048; i < 3072; ++i) {
const uint16_t* data = GBAVideoTileCacheGetTile16IfDirty(&m_tileCache, i, m_paletteId + 16);
const uint16_t* data = GBAVideoTileCacheGetTile16IfDirty(m_tileCache, m_tileStatus, 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, GBAVideoTileCacheGetTile16(m_tileCache, i, m_paletteId + 16));
}
}
}

View File

@ -23,7 +23,6 @@ Q_OBJECT
public:
TileView(GameController* controller, QWidget* parent = nullptr);
virtual ~TileView();
public slots:
void updateTiles(bool force = false);
@ -40,7 +39,8 @@ private:
Ui::TileView m_ui;
GameController* m_controller;
GBAVideoTileCache m_tileCache;
GBAVideoTileCache* m_tileCache;
GBAVideoTileCacheStatus m_tileStatus;
int m_paletteId;
QTimer m_updateTimer;
};