mirror of https://github.com/mgba-emu/mgba.git
Core: Generic tile cache, usable with Game Boy core
This commit is contained in:
parent
9bef681c7d
commit
d462b4dd7f
1
CHANGES
1
CHANGES
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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()));
|
||||
|
|
Loading…
Reference in New Issue