diff --git a/CHANGES b/CHANGES index 28bc6d897..c4862311d 100644 --- a/CHANGES +++ b/CHANGES @@ -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: diff --git a/src/gba/renderers/tile-cache.c b/src/gba/renderers/tile-cache.c index d719b0d7b..56d39d626 100644 --- a/src/gba/renderers/tile-cache.c +++ b/src/gba/renderers/tile-cache.c @@ -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; } diff --git a/src/gba/renderers/tile-cache.h b/src/gba/renderers/tile-cache.h index 2a0d30aad..f7290ea64 100644 --- a/src/gba/renderers/tile-cache.h +++ b/src/gba/renderers/tile-cache.h @@ -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 diff --git a/src/platform/qt/GameController.cpp b/src/platform/qt/GameController.cpp index c3d54bd51..1736a5da9 100644 --- a/src/platform/qt/GameController.cpp +++ b/src/platform/qt/GameController.cpp @@ -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(m_threadContext.core->board); + m_tileCache = std::unique_ptr(new GBAVideoTileCache); + GBAVideoTileCacheInit(m_tileCache.get()); + GBAVideoTileCacheAssociate(m_tileCache.get(), &gba->video); + threadContinue(); + return m_tileCache.get(); +} +#endif \ No newline at end of file diff --git a/src/platform/qt/GameController.h b/src/platform/qt/GameController.h index 721e2809d..58565993a 100644 --- a/src/platform/qt/GameController.h +++ b/src/platform/qt/GameController.h @@ -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 m_tileCache; +#endif + bool m_audioChannels[6]; bool m_videoLayers[5]; diff --git a/src/platform/qt/TileView.cpp b/src/platform/qt/TileView.cpp index 599f23430..4b700e1a7 100644 --- a/src/platform/qt/TileView.cpp +++ b/src/platform/qt/TileView.cpp @@ -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(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(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)); } } } diff --git a/src/platform/qt/TileView.h b/src/platform/qt/TileView.h index 28fc4b8a8..e92847681 100644 --- a/src/platform/qt/TileView.h +++ b/src/platform/qt/TileView.h @@ -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; };