all repos — mgba @ 2c59cb8211c4bf46665d12ed174cf7efe512e0d0

mGBA Game Boy Advance Emulator

src/core/map-cache.c (view raw)

  1/* Copyright (c) 2013-2017 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include <mgba/core/map-cache.h>
  7
  8#include <mgba-util/memory.h>
  9
 10void mMapCacheInit(struct mMapCache* cache) {
 11	// TODO: Reconfigurable cache for space savings
 12	cache->cache = NULL;
 13	cache->config = mMapCacheConfigurationFillShouldStore(0);
 14	cache->status = NULL;
 15}
 16
 17static void _freeCache(struct mMapCache* cache) {
 18	size_t tiles = (1 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig)) * (1 << mMapCacheSystemInfoGetTilesHigh(cache->sysConfig));
 19	mappedMemoryFree(cache->cache, 8 * 8 * sizeof(color_t) * tiles);
 20	mappedMemoryFree(cache->status, tiles * sizeof(*cache->status));
 21	cache->cache = NULL;
 22	cache->status = NULL;
 23}
 24
 25static void _redoCacheSize(struct mMapCache* cache) {
 26	if (!mMapCacheConfigurationIsShouldStore(cache->config)) {
 27		return;
 28	}
 29
 30	size_t tiles = (1 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig)) * (1 << mMapCacheSystemInfoGetTilesHigh(cache->sysConfig));
 31	cache->cache = anonymousMemoryMap(8 * 8 * sizeof(color_t) * tiles);
 32	cache->status = anonymousMemoryMap(tiles * sizeof(*cache->status));
 33}
 34
 35void mMapCacheConfigure(struct mMapCache* cache, mMapCacheConfiguration config) {
 36	if (config == cache->config) {
 37		return;
 38	}
 39	_freeCache(cache);
 40	cache->config = config;
 41	_redoCacheSize(cache);
 42}
 43
 44void mMapCacheConfigureSystem(struct mMapCache* cache, mMapCacheSystemInfo config) {
 45	if (config == cache->sysConfig) {
 46		return;
 47	}
 48	_freeCache(cache);
 49	cache->sysConfig = config;
 50	_redoCacheSize(cache);
 51
 52	size_t mapSize = (1 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig)) * (1 << mMapCacheSystemInfoGetTilesHigh(cache->sysConfig));
 53	cache->mapSize = mapSize << mMapCacheSystemInfoGetMapAlign(cache->sysConfig);
 54}
 55
 56void mMapCacheConfigureMap(struct mMapCache* cache, uint32_t mapStart) {
 57	size_t tiles = (1 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig)) * (1 << mMapCacheSystemInfoGetTilesHigh(cache->sysConfig));
 58	memset(cache->status, 0, tiles * sizeof(*cache->status));
 59	cache->mapStart = mapStart;
 60}
 61
 62void mMapCacheDeinit(struct mMapCache* cache) {
 63	_freeCache(cache);
 64}
 65
 66void mMapCacheWriteVRAM(struct mMapCache* cache, uint32_t address) {
 67	if (address >= cache->mapStart && address < cache->mapStart + cache->mapSize) {
 68		address -= cache->mapStart;
 69		struct mMapCacheEntry* status = &cache->status[address >> mMapCacheSystemInfoGetMapAlign(cache->sysConfig)];
 70		++status->vramVersion;
 71		status->flags = mMapCacheEntryFlagsClearVramClean(status->flags);
 72		status->tileStatus[mMapCacheEntryFlagsGetPaletteId(status->flags)].vramClean = 0;
 73	}
 74}
 75
 76static inline void _cleanTile(struct mMapCache* cache, const color_t* tile, color_t* mapOut, const struct mMapCacheEntry* status) {
 77	size_t stride = 8 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
 78	int x, y;
 79	switch (mMapCacheEntryFlagsGetMirror(status->flags)) {
 80	case 0:
 81		memcpy(mapOut, tile, sizeof(color_t) * 8);
 82		memcpy(&mapOut[stride], &tile[0x08], sizeof(color_t) * 8);
 83		memcpy(&mapOut[stride * 2], &tile[0x10], sizeof(color_t) * 8);
 84		memcpy(&mapOut[stride * 3], &tile[0x18], sizeof(color_t) * 8);
 85		memcpy(&mapOut[stride * 4], &tile[0x20], sizeof(color_t) * 8);
 86		memcpy(&mapOut[stride * 5], &tile[0x28], sizeof(color_t) * 8);
 87		memcpy(&mapOut[stride * 6], &tile[0x30], sizeof(color_t) * 8);
 88		memcpy(&mapOut[stride * 7], &tile[0x38], sizeof(color_t) * 8);
 89		break;
 90	case 1:
 91		for (y = 0; y < 8; ++y) {
 92			for (x = 0; x < 8; ++x) {
 93				mapOut[y * stride + (7 - x)] = tile[y * 8 + x];
 94			}
 95		}
 96		break;
 97	case 2:
 98		memcpy(&mapOut[stride * 7], tile, sizeof(color_t) * 8);
 99		memcpy(&mapOut[stride * 6], &tile[0x08], sizeof(color_t) * 8);
100		memcpy(&mapOut[stride * 5], &tile[0x10], sizeof(color_t) * 8);
101		memcpy(&mapOut[stride * 4], &tile[0x18], sizeof(color_t) * 8);
102		memcpy(&mapOut[stride * 3], &tile[0x20], sizeof(color_t) * 8);
103		memcpy(&mapOut[stride * 2], &tile[0x28], sizeof(color_t) * 8);
104		memcpy(&mapOut[stride], &tile[0x30], sizeof(color_t) * 8);
105		memcpy(mapOut, &tile[0x38], sizeof(color_t) * 8);
106		break;
107	case 3:
108		for (y = 0; y < 8; ++y) {
109			for (x = 0; x < 8; ++x) {
110				mapOut[(7 - y) * stride + (7 - x)] = tile[y * 8 + x];
111			}
112		}
113		break;
114	}
115}
116
117void mMapCacheCleanTile(struct mMapCache* cache, struct mMapCacheEntry* entry, unsigned x, unsigned y) {
118	size_t location = (1 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig)) * y + x;
119	struct mMapCacheEntry* status = &cache->status[location];
120	int paletteId = mMapCacheEntryFlagsGetPaletteId(status->flags);
121	const color_t* tile = NULL;
122	if (!mMapCacheEntryFlagsIsVramClean(status->flags)) {
123		status->flags = mMapCacheEntryFlagsFillVramClean(status->flags);
124		cache->mapParser(cache, status, &cache->vram[cache->mapStart + (location << mMapCacheSystemInfoGetMapAlign(cache->sysConfig))]);
125		tile = mTileCacheGetTileIfDirty(cache->tileCache, &status->tileStatus[paletteId], status->tileId + cache->tileStart, mMapCacheEntryFlagsGetPaletteId(status->flags));
126		if (!tile) {
127			tile = mTileCacheGetTile(cache->tileCache, status->tileId + cache->tileStart, mMapCacheEntryFlagsGetPaletteId(status->flags));
128		}
129	} else {
130		tile = mTileCacheGetTileIfDirty(cache->tileCache, &status->tileStatus[paletteId], status->tileId + cache->tileStart, mMapCacheEntryFlagsGetPaletteId(status->flags));
131		if (!tile && memcmp(status, &entry[location], sizeof(*entry)) == 0) {
132			return;
133		}
134		tile = mTileCacheGetTile(cache->tileCache, status->tileId + cache->tileStart, mMapCacheEntryFlagsGetPaletteId(status->flags));
135	}
136
137	size_t stride = 8 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
138	color_t* mapOut = &cache->cache[(y * stride + x) * 8];
139	_cleanTile(cache, tile, mapOut, status);
140	entry[location] = *status;
141}
142
143bool mMapCacheCheckTile(struct mMapCache* cache, const struct mMapCacheEntry* entry, unsigned x, unsigned y) {
144	size_t location = (1 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig)) * y + x;
145	struct mMapCacheEntry* status = &cache->status[location];
146	int paletteId = mMapCacheEntryFlagsGetPaletteId(status->flags);
147	const color_t* tile = NULL;
148	if (mMapCacheEntryFlagsIsVramClean(status->flags) && memcmp(status, &entry[location], sizeof(*entry)) == 0) {
149		tile = mTileCacheGetTileIfDirty(cache->tileCache, &status->tileStatus[paletteId], status->tileId + cache->tileStart, mMapCacheEntryFlagsGetPaletteId(status->flags));
150		return !tile;
151	}
152	return false;
153}
154
155const color_t* mMapCacheGetRow(struct mMapCache* cache, unsigned y) {
156	size_t stride = 8 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
157	return &cache->cache[y * stride];
158}