Core: Add support for caching bitmapped modes

This commit is contained in:
Vicki Pfau 2019-04-30 17:44:56 -07:00
parent 19a42a387a
commit fbe375fab9
9 changed files with 347 additions and 26 deletions

View File

@ -7,6 +7,7 @@ Features:
- GB: Expose platform information to CLI debugger
- Support Discord Rich Presence
- Debugger: Add tracing to file
- Map viewer supports bitmapped GBA modes
Emulation fixes:
- GBA: All IRQs have 7 cycle delay (fixes mgba.io/i/539, mgba.io/i/1208)
- GBA: Reset now reloads multiboot ROMs

View File

@ -0,0 +1,64 @@
/* Copyright (c) 2013-2019 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_BITMAP_CACHE_H
#define M_BITMAP_CACHE_H
#include <mgba-util/common.h>
CXX_GUARD_START
#include <mgba/core/interface.h>
DECL_BITFIELD(mBitmapCacheConfiguration, uint32_t);
DECL_BIT(mBitmapCacheConfiguration, ShouldStore, 0);
DECL_BITFIELD(mBitmapCacheSystemInfo, uint32_t);
DECL_BITS(mBitmapCacheSystemInfo, EntryBPP, 0, 3);
DECL_BIT(mBitmapCacheSystemInfo, UsesPalette, 3);
DECL_BITS(mBitmapCacheSystemInfo, Width, 4, 10);
DECL_BITS(mBitmapCacheSystemInfo, Height, 14, 10);
DECL_BITS(mBitmapCacheSystemInfo, Buffers, 24, 2);
struct mBitmapCacheEntry {
uint32_t paletteVersion;
uint32_t vramVersion;
uint8_t vramClean;
};
struct mBitmapCache {
color_t* cache;
struct mBitmapCacheEntry* status;
uint32_t globalPaletteVersion;
uint8_t* vram;
color_t* palette;
uint32_t bitsSize;
uint32_t bitsStart[2];
uint32_t stride;
uint8_t buffer;
mBitmapCacheConfiguration config;
mBitmapCacheSystemInfo sysConfig;
void* context;
};
void mBitmapCacheInit(struct mBitmapCache* cache);
void mBitmapCacheDeinit(struct mBitmapCache* cache);
void mBitmapCacheConfigure(struct mBitmapCache* cache, mBitmapCacheConfiguration config);
void mBitmapCacheConfigureSystem(struct mBitmapCache* cache, mBitmapCacheSystemInfo config);
void mBitmapCacheWriteVRAM(struct mBitmapCache* cache, uint32_t address);
void mBitmapCacheWritePalette(struct mBitmapCache* cache, uint32_t entry, color_t color);
void mBitmapCacheCleanRow(struct mBitmapCache* cache, struct mBitmapCacheEntry* entry, unsigned y);
bool mBitmapCacheCheckRow(struct mBitmapCache* cache, const struct mBitmapCacheEntry* entry, unsigned y);
const color_t* mBitmapCacheGetRow(struct mBitmapCache* cache, unsigned y);
CXX_GUARD_END
#endif

View File

@ -10,19 +10,22 @@
CXX_GUARD_START
#include <mgba/core/bitmap-cache.h>
#include <mgba/core/map-cache.h>
#include <mgba/core/tile-cache.h>
#include <mgba-util/vector.h>
DECLARE_VECTOR(mMapCacheSet, struct mMapCache);
DECLARE_VECTOR(mBitmapCacheSet, struct mBitmapCache);
DECLARE_VECTOR(mTileCacheSet, struct mTileCache);
struct mCacheSet {
struct mMapCacheSet maps;
struct mBitmapCacheSet bitmaps;
struct mTileCacheSet tiles;
};
void mCacheSetInit(struct mCacheSet*, size_t nMaps, size_t nTiles);
void mCacheSetInit(struct mCacheSet*, size_t nMaps, size_t nBitmaps, size_t nTiles);
void mCacheSetDeinit(struct mCacheSet*);
void mCacheSetAssignVRAM(struct mCacheSet*, void* vram);

182
src/core/bitmap-cache.c Normal file
View File

@ -0,0 +1,182 @@
/* Copyright (c) 2013-2019 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 <mgba/core/bitmap-cache.h>
#include <mgba-util/memory.h>
void mBitmapCacheInit(struct mBitmapCache* cache) {
// TODO: Reconfigurable cache for space savings
cache->cache = NULL;
cache->config = mBitmapCacheConfigurationFillShouldStore(0);
cache->status = NULL;
cache->palette = NULL;
cache->buffer = 0;
}
static void _freeCache(struct mBitmapCache* cache) {
size_t size = mBitmapCacheSystemInfoGetHeight(cache->sysConfig) * mBitmapCacheSystemInfoGetBuffers(cache->sysConfig);
mappedMemoryFree(cache->cache, mBitmapCacheSystemInfoGetWidth(cache->sysConfig) * size * sizeof(color_t));
mappedMemoryFree(cache->status, size * sizeof(*cache->status));
if (cache->palette) {
free(cache->palette);
}
cache->cache = NULL;
cache->status = NULL;
cache->palette = NULL;
}
static void _redoCacheSize(struct mBitmapCache* cache) {
if (!mBitmapCacheConfigurationIsShouldStore(cache->config)) {
return;
}
size_t size = mBitmapCacheSystemInfoGetHeight(cache->sysConfig) * mBitmapCacheSystemInfoGetBuffers(cache->sysConfig);
cache->cache = anonymousMemoryMap(mBitmapCacheSystemInfoGetWidth(cache->sysConfig) * size * sizeof(color_t));
cache->status = anonymousMemoryMap(size * sizeof(*cache->status));
if (mBitmapCacheSystemInfoIsUsesPalette(cache->sysConfig)) {
cache->palette = malloc((1 << (1 << mBitmapCacheSystemInfoGetEntryBPP(cache->sysConfig))) * sizeof(color_t));
} else {
cache->palette = NULL;
}
}
void mBitmapCacheConfigure(struct mBitmapCache* cache, mBitmapCacheConfiguration config) {
if (config == cache->config) {
return;
}
_freeCache(cache);
cache->config = config;
_redoCacheSize(cache);
}
void mBitmapCacheConfigureSystem(struct mBitmapCache* cache, mBitmapCacheSystemInfo config) {
if (config == cache->sysConfig) {
return;
}
_freeCache(cache);
cache->sysConfig = config;
_redoCacheSize(cache);
size_t stride = mBitmapCacheSystemInfoGetWidth(cache->sysConfig);
size_t size = stride * mBitmapCacheSystemInfoGetHeight(cache->sysConfig);
size_t bpe = mBitmapCacheSystemInfoGetEntryBPP(cache->sysConfig);
if (bpe > 3) {
size <<= bpe - 3;
stride <<= bpe - 3;
} else {
size >>= 3 - bpe;
stride >>= 3 - bpe;
}
cache->bitsSize = size;
cache->stride = stride;
}
void mBitmapCacheDeinit(struct mBitmapCache* cache) {
_freeCache(cache);
}
void mBitmapCacheWriteVRAM(struct mBitmapCache* cache, uint32_t address) {
size_t i;
for (i = 0; i < mBitmapCacheSystemInfoGetBuffers(cache->sysConfig); ++i) {
if (address < cache->bitsStart[i]) {
continue;
}
uint32_t offset = address - cache->bitsStart[i];
if (offset >= cache->bitsSize) {
continue;
}
offset /= cache->stride;
offset *= mBitmapCacheSystemInfoGetBuffers(cache->sysConfig);
offset += cache->buffer;
cache->status[offset].vramClean = 0;
++cache->status[offset].vramVersion;
}
}
void mBitmapCacheWritePalette(struct mBitmapCache* cache, uint32_t entry, color_t color) {
if (!mBitmapCacheSystemInfoIsUsesPalette(cache->sysConfig)) {
return;
}
size_t maxEntry = 1 << (1 << mBitmapCacheSystemInfoGetEntryBPP(cache->sysConfig));
if (entry >= maxEntry) {
return;
}
cache->palette[entry] = color;
++cache->globalPaletteVersion;
}
uint32_t _lookupEntry8(void* vram, uint32_t offset) {
return ((uint8_t*) vram)[offset];
}
uint32_t _lookupEntry15(void* vram, uint32_t offset) {
return mColorFrom555(((uint16_t*) vram)[offset]);
}
void mBitmapCacheCleanRow(struct mBitmapCache* cache, struct mBitmapCacheEntry* entry, unsigned y) {
color_t* row = &cache->cache[(cache->buffer * mBitmapCacheSystemInfoGetHeight(cache->sysConfig) + y) * mBitmapCacheSystemInfoGetWidth(cache->sysConfig)];
size_t location = cache->buffer + mBitmapCacheSystemInfoGetBuffers(cache->sysConfig) * y;
struct mBitmapCacheEntry* status = &cache->status[location];
struct mBitmapCacheEntry desiredStatus = {
.paletteVersion = cache->globalPaletteVersion,
.vramVersion = entry->vramVersion,
.vramClean = 1
};
if (entry) {
entry[location] = desiredStatus;
}
if (!mBitmapCacheConfigurationIsShouldStore(cache->config) || !memcmp(status, &desiredStatus, sizeof(*entry))) {
return;
}
size_t offset = cache->bitsStart[cache->buffer] + y * mBitmapCacheSystemInfoGetWidth(cache->sysConfig);
void* vram;
int bpe = mBitmapCacheSystemInfoGetEntryBPP(cache->sysConfig);
uint32_t (*lookupEntry)(void*, uint32_t);
switch (bpe) {
case 3:
lookupEntry = _lookupEntry8;
vram = &cache->vram[offset];
break;
case 4:
lookupEntry = _lookupEntry15;
vram = &cache->vram[offset << 1];
break;
default:
abort();
break;
}
size_t x;
if (mBitmapCacheSystemInfoIsUsesPalette(cache->sysConfig)) {
for (x = 0; x < mBitmapCacheSystemInfoGetWidth(cache->sysConfig); ++x) {
row[x] = cache->palette[lookupEntry(vram, x)];
}
} else {
for (x = 0; x < mBitmapCacheSystemInfoGetWidth(cache->sysConfig); ++x) {
row[x] = lookupEntry(vram, x);
}
}
*status = desiredStatus;
}
bool mBitmapCacheCheckRow(struct mBitmapCache* cache, const struct mBitmapCacheEntry* entry, unsigned y) {
size_t location = cache->buffer + mBitmapCacheSystemInfoGetBuffers(cache->sysConfig) * y;
struct mBitmapCacheEntry desiredStatus = {
.paletteVersion = cache->globalPaletteVersion,
.vramVersion = entry->vramVersion,
.vramClean = 1
};
return memcmp(&entry[location], &desiredStatus, sizeof(*entry)) == 0;
}
const color_t* mBitmapCacheGetRow(struct mBitmapCache* cache, unsigned y) {
color_t* row = &cache->cache[(cache->buffer * mBitmapCacheSystemInfoGetHeight(cache->sysConfig) + y) * mBitmapCacheSystemInfoGetWidth(cache->sysConfig)];
return row;
}

View File

@ -6,11 +6,14 @@
#include <mgba/core/cache-set.h>
DEFINE_VECTOR(mMapCacheSet, struct mMapCache);
DEFINE_VECTOR(mBitmapCacheSet, struct mBitmapCache);
DEFINE_VECTOR(mTileCacheSet, struct mTileCache);
void mCacheSetInit(struct mCacheSet* cache, size_t nMaps, size_t nTiles) {
void mCacheSetInit(struct mCacheSet* cache, size_t nMaps, size_t nBitmaps, size_t nTiles) {
mMapCacheSetInit(&cache->maps, nMaps);
mMapCacheSetResize(&cache->maps, nMaps);
mBitmapCacheSetInit(&cache->bitmaps, nBitmaps);
mBitmapCacheSetResize(&cache->bitmaps, nBitmaps);
mTileCacheSetInit(&cache->tiles, nTiles);
mTileCacheSetResize(&cache->tiles, nTiles);
@ -18,6 +21,9 @@ void mCacheSetInit(struct mCacheSet* cache, size_t nMaps, size_t nTiles) {
for (i = 0; i < nMaps; ++i) {
mMapCacheInit(mMapCacheSetGetPointer(&cache->maps, i));
}
for (i = 0; i < nBitmaps; ++i) {
mBitmapCacheInit(mBitmapCacheSetGetPointer(&cache->bitmaps, i));
}
for (i = 0; i < nTiles; ++i) {
mTileCacheInit(mTileCacheSetGetPointer(&cache->tiles, i));
}
@ -28,6 +34,9 @@ void mCacheSetDeinit(struct mCacheSet* cache) {
for (i = 0; i < mMapCacheSetSize(&cache->maps); ++i) {
mMapCacheDeinit(mMapCacheSetGetPointer(&cache->maps, i));
}
for (i = 0; i < mBitmapCacheSetSize(&cache->bitmaps); ++i) {
mBitmapCacheDeinit(mBitmapCacheSetGetPointer(&cache->bitmaps, i));
}
for (i = 0; i < mTileCacheSetSize(&cache->tiles); ++i) {
mTileCacheDeinit(mTileCacheSetGetPointer(&cache->tiles, i));
}
@ -38,6 +47,9 @@ void mCacheSetAssignVRAM(struct mCacheSet* cache, void* vram) {
for (i = 0; i < mMapCacheSetSize(&cache->maps); ++i) {
mMapCacheSetGetPointer(&cache->maps, i)->vram = vram;
}
for (i = 0; i < mBitmapCacheSetSize(&cache->bitmaps); ++i) {
mBitmapCacheSetGetPointer(&cache->bitmaps, i)->vram = vram;
}
for (i = 0; i < mTileCacheSetSize(&cache->tiles); ++i) {
struct mTileCache* tileCache = mTileCacheSetGetPointer(&cache->tiles, i);
tileCache->vram = (void*) ((uintptr_t) vram + tileCache->tileBase);
@ -49,6 +61,9 @@ void mCacheSetWriteVRAM(struct mCacheSet* cache, uint32_t address) {
for (i = 0; i < mMapCacheSetSize(&cache->maps); ++i) {
mMapCacheWriteVRAM(mMapCacheSetGetPointer(&cache->maps, i), address);
}
for (i = 0; i < mBitmapCacheSetSize(&cache->bitmaps); ++i) {
mBitmapCacheWriteVRAM(mBitmapCacheSetGetPointer(&cache->bitmaps, i), address);
}
for (i = 0; i < mTileCacheSetSize(&cache->tiles); ++i) {
mTileCacheWriteVRAM(mTileCacheSetGetPointer(&cache->tiles, i), address);
}
@ -56,6 +71,9 @@ void mCacheSetWriteVRAM(struct mCacheSet* cache, uint32_t address) {
void mCacheSetWritePalette(struct mCacheSet* cache, uint32_t entry, color_t color) {
size_t i;
for (i = 0; i < mBitmapCacheSetSize(&cache->bitmaps); ++i) {
mBitmapCacheWritePalette(mBitmapCacheSetGetPointer(&cache->bitmaps, i), entry, color);
}
for (i = 0; i < mTileCacheSetSize(&cache->tiles); ++i) {
mTileCacheWritePalette(mTileCacheSetGetPointer(&cache->tiles, i), entry, color);
}

View File

@ -11,16 +11,13 @@
#include <mgba/internal/gb/video.h>
void GBVideoCacheInit(struct mCacheSet* cache) {
mCacheSetInit(cache, 2, 1);
mCacheSetInit(cache, 2, 0, 1);
mTileCacheConfiguration config = 0;
config = mTileCacheSystemInfoSetPaletteBPP(config, 1); // 2^(2^1) = 4 entries
config = mTileCacheSystemInfoSetPaletteCount(config, 4); // 16 palettes
config = mTileCacheSystemInfoSetMaxTiles(config, 1024);
mTileCacheInit(mTileCacheSetGetPointer(&cache->tiles, 0));
mTileCacheConfigureSystem(mTileCacheSetGetPointer(&cache->tiles, 0), config, 0, 0);
mMapCacheInit(mMapCacheSetGetPointer(&cache->maps, 0));
mMapCacheInit(mMapCacheSetGetPointer(&cache->maps, 1));
mMapCacheSetGetPointer(&cache->maps, 0)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0);
mMapCacheSetGetPointer(&cache->maps, 1)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0);
}

View File

@ -11,35 +11,45 @@
#include <mgba/internal/gba/video.h>
void GBAVideoCacheInit(struct mCacheSet* cache) {
mCacheSetInit(cache, 4, 4);
mCacheSetInit(cache, 4, 2, 4);
mTileCacheSystemInfo sysconfig = 0;
mTileCacheConfiguration config = mTileCacheConfigurationFillShouldStore(0);
sysconfig = mTileCacheSystemInfoSetPaletteBPP(sysconfig, 2); // 2^(2^2) = 16 entries
sysconfig = mTileCacheSystemInfoSetPaletteCount(sysconfig, 4); // 16 palettes
sysconfig = mTileCacheSystemInfoSetMaxTiles(sysconfig, 2048);
mTileCacheInit(mTileCacheSetGetPointer(&cache->tiles, 0));
mTileCacheConfigure(mTileCacheSetGetPointer(&cache->tiles, 0), config);
mTileCacheConfigureSystem(mTileCacheSetGetPointer(&cache->tiles, 0), sysconfig, 0, 0);
sysconfig = mTileCacheSystemInfoSetMaxTiles(sysconfig, 1024);
mTileCacheInit(mTileCacheSetGetPointer(&cache->tiles, 2));
mTileCacheConfigure(mTileCacheSetGetPointer(&cache->tiles, 2), config);
mTileCacheConfigureSystem(mTileCacheSetGetPointer(&cache->tiles, 2), sysconfig, 0x10000, 0x100);
sysconfig = mTileCacheSystemInfoSetPaletteBPP(sysconfig, 3); // 2^(2^3) = 256 entries
sysconfig = mTileCacheSystemInfoSetPaletteCount(sysconfig, 0); // 1 palettes
sysconfig = mTileCacheSystemInfoSetMaxTiles(sysconfig, 2048);
mTileCacheInit(mTileCacheSetGetPointer(&cache->tiles, 1));
mTileCacheConfigure(mTileCacheSetGetPointer(&cache->tiles, 1), config);
mTileCacheConfigureSystem(mTileCacheSetGetPointer(&cache->tiles, 1), sysconfig, 0, 0);
sysconfig = mTileCacheSystemInfoSetMaxTiles(sysconfig, 1024);
mTileCacheInit(mTileCacheSetGetPointer(&cache->tiles, 3));
mTileCacheConfigure(mTileCacheSetGetPointer(&cache->tiles, 3), config);
mTileCacheConfigureSystem(mTileCacheSetGetPointer(&cache->tiles, 3), sysconfig, 0x10000, 0x100);
mMapCacheInit(mMapCacheSetGetPointer(&cache->maps, 0));
mMapCacheInit(mMapCacheSetGetPointer(&cache->maps, 1));
mMapCacheInit(mMapCacheSetGetPointer(&cache->maps, 2));
mMapCacheInit(mMapCacheSetGetPointer(&cache->maps, 3));
mBitmapCacheSystemInfo bitConfig;
bitConfig = mBitmapCacheSystemInfoSetEntryBPP(0, 4);
bitConfig = mBitmapCacheSystemInfoClearUsesPalette(bitConfig);
bitConfig = mBitmapCacheSystemInfoSetHeight(bitConfig, 160);
bitConfig = mBitmapCacheSystemInfoSetWidth(bitConfig, 240);
bitConfig = mBitmapCacheSystemInfoSetBuffers(bitConfig, 1);
mBitmapCacheConfigureSystem(mBitmapCacheSetGetPointer(&cache->bitmaps, 0), bitConfig);
mBitmapCacheSetGetPointer(&cache->bitmaps, 0)->bitsStart[0] = 0;
mBitmapCacheSetGetPointer(&cache->bitmaps, 0)->bitsStart[1] = 0xA000;
bitConfig = mBitmapCacheSystemInfoSetEntryBPP(0, 3);
bitConfig = mBitmapCacheSystemInfoFillUsesPalette(bitConfig);
bitConfig = mBitmapCacheSystemInfoSetHeight(bitConfig, 160);
bitConfig = mBitmapCacheSystemInfoSetWidth(bitConfig, 240);
bitConfig = mBitmapCacheSystemInfoSetBuffers(bitConfig, 2);
mBitmapCacheConfigureSystem(mBitmapCacheSetGetPointer(&cache->bitmaps, 1), bitConfig);
mBitmapCacheSetGetPointer(&cache->bitmaps, 1)->bitsStart[0] = 0;
mBitmapCacheSetGetPointer(&cache->bitmaps, 1)->bitsStart[1] = 0xA000;
}
void GBAVideoCacheAssociate(struct mCacheSet* cache, struct GBAVideo* video) {
@ -77,6 +87,8 @@ static void mapParser2(struct mMapCache* cache, struct mMapCacheEntry* entry, vo
}
static void GBAVideoCacheWriteDISPCNT(struct mCacheSet* cache, uint16_t value) {
mBitmapCacheSetGetPointer(&cache->bitmaps, 1)->buffer = GBARegisterDISPCNTGetFrameSelect(value);
switch (GBARegisterDISPCNTGetMode(value)) {
case 0:
default:
@ -110,6 +122,28 @@ static void GBAVideoCacheWriteDISPCNT(struct mCacheSet* cache, uint16_t value) {
mMapCacheSetGetPointer(&cache->maps, 3)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 1);
break;
}
mBitmapCacheSystemInfo bitConfig;
switch (GBARegisterDISPCNTGetMode(value)) {
case 3:
bitConfig = mBitmapCacheSystemInfoSetEntryBPP(0, 4);
bitConfig = mBitmapCacheSystemInfoClearUsesPalette(bitConfig);
bitConfig = mBitmapCacheSystemInfoSetHeight(bitConfig, 160);
bitConfig = mBitmapCacheSystemInfoSetWidth(bitConfig, 240);
bitConfig = mBitmapCacheSystemInfoSetBuffers(bitConfig, 1);
mBitmapCacheConfigureSystem(mBitmapCacheSetGetPointer(&cache->bitmaps, 0), bitConfig);
mBitmapCacheSetGetPointer(&cache->bitmaps, 0)->buffer = 0;
break;
case 5:
bitConfig = mBitmapCacheSystemInfoSetEntryBPP(0, 4);
bitConfig = mBitmapCacheSystemInfoClearUsesPalette(bitConfig);
bitConfig = mBitmapCacheSystemInfoSetHeight(bitConfig, 128);
bitConfig = mBitmapCacheSystemInfoSetWidth(bitConfig, 160);
bitConfig = mBitmapCacheSystemInfoSetBuffers(bitConfig, 2);
mBitmapCacheConfigureSystem(mBitmapCacheSetGetPointer(&cache->bitmaps, 0), bitConfig);
mBitmapCacheSetGetPointer(&cache->bitmaps, 0)->buffer = GBARegisterDISPCNTGetFrameSelect(value);
break;
}
}
static void GBAVideoCacheWriteBGCNT(struct mCacheSet* cache, size_t bg, uint16_t value) {

View File

@ -12,7 +12,10 @@
#include <mgba-util/png-io.h>
#include <mgba-util/vfs.h>
#ifdef M_CORE_GBA
#include <mgba/internal/gba/gba.h>
#include <mgba/internal/gba/io.h>
#include <mgba/internal/gba/memory.h>
#include <mgba/internal/gba/video.h>
#endif
#ifdef M_CORE_GB
#include <mgba/internal/gb/memory.h>
@ -139,17 +142,36 @@ bool MapView::eventFilter(QObject* obj, QEvent* event) {
void MapView::updateTilesGBA(bool force) {
{
CoreController::Interrupter interrupter(m_controller);
mMapCache* mapCache = mMapCacheSetGetPointer(&m_cacheSet->maps, m_map);
int tilesW = 1 << mMapCacheSystemInfoGetTilesWide(mapCache->sysConfig);
int tilesH = 1 << mMapCacheSystemInfoGetTilesHigh(mapCache->sysConfig);
m_rawMap = QImage(QSize(tilesW * 8, tilesH * 8), QImage::Format_ARGB32);
uchar* bgBits = m_rawMap.bits();
for (int j = 0; j < tilesH; ++j) {
for (int i = 0; i < tilesW; ++i) {
mMapCacheCleanTile(mapCache, m_mapStatus, i, j);
int bitmap = -1;
if (m_controller->platform() == PLATFORM_GBA) {
int mode = GBARegisterDISPCNTGetMode(static_cast<GBA*>(m_controller->thread()->core->board)->memory.io[REG_DISPCNT]);
if (m_map == 2 && mode > 2) {
bitmap = mode == 4 ? 1 : 0;
}
for (int i = 0; i < 8; ++i) {
memcpy(static_cast<void*>(&bgBits[tilesW * 32 * (i + j * 8)]), mMapCacheGetRow(mapCache, i + j * 8), tilesW * 32);
}
if (bitmap >= 0) {
mBitmapCache* bitmapCache = mBitmapCacheSetGetPointer(&m_cacheSet->bitmaps, bitmap);
int width = mBitmapCacheSystemInfoGetWidth(bitmapCache->sysConfig);
int height = mBitmapCacheSystemInfoGetHeight(bitmapCache->sysConfig);
m_rawMap = QImage(QSize(width, height), QImage::Format_ARGB32);
uchar* bgBits = m_rawMap.bits();
for (int j = 0; j < height; ++j) {
mBitmapCacheCleanRow(bitmapCache, m_bitmapStatus, j);
memcpy(static_cast<void*>(&bgBits[width * j * 4]), mBitmapCacheGetRow(bitmapCache, j), width * 4);
}
} else {
mMapCache* mapCache = mMapCacheSetGetPointer(&m_cacheSet->maps, m_map);
int tilesW = 1 << mMapCacheSystemInfoGetTilesWide(mapCache->sysConfig);
int tilesH = 1 << mMapCacheSystemInfoGetTilesHigh(mapCache->sysConfig);
m_rawMap = QImage(QSize(tilesW * 8, tilesH * 8), QImage::Format_ARGB32);
uchar* bgBits = m_rawMap.bits();
for (int j = 0; j < tilesH; ++j) {
for (int i = 0; i < tilesW; ++i) {
mMapCacheCleanTile(mapCache, m_mapStatus, i, j);
}
for (int i = 0; i < 8; ++i) {
memcpy(static_cast<void*>(&bgBits[tilesW * 32 * (i + j * 8)]), mMapCacheGetRow(mapCache, i + j * 8), tilesW * 32);
}
}
}
}
@ -181,7 +203,6 @@ void MapView::exportMap() {
png_structp png = PNGWriteOpen(vf);
png_infop info = PNGWriteHeaderA(png, m_rawMap.width(), m_rawMap.height());
mMapCache* mapCache = mMapCacheSetGetPointer(&m_cacheSet->maps, m_map);
QImage map = m_rawMap.rgbSwapped();
PNGWritePixelsA(png, map.width(), map.height(), map.bytesPerLine() / 4, static_cast<const void*>(map.constBits()));
PNGWriteClose(png, info);

View File

@ -45,6 +45,7 @@ private:
std::shared_ptr<CoreController> m_controller;
mMapCacheEntry m_mapStatus[128 * 128] = {}; // TODO: Correct size
mBitmapCacheEntry m_bitmapStatus[512 * 2] = {}; // TODO: Correct size
int m_map = 0;
QImage m_rawMap;
int m_boundary;