all repos — mgba @ 229d138dacd0df43d14a498ad190200bde17df9c

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
117static inline size_t _tileId(struct mMapCache* cache, unsigned x, unsigned y) {
118	int tilesWide = mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
119	int tilesHigh = mMapCacheSystemInfoGetTilesHigh(cache->sysConfig);
120	int stride = tilesHigh < 5 ? (1 << tilesHigh) : 32;
121	x &= (1 << tilesWide) - 1;
122	y &= (1 << tilesHigh) - 1;
123	unsigned xMajor = x & ~0x1F;
124	unsigned yMajor = y >> 5;
125	x &= 0x1F;
126	y &= 0x1F;
127	yMajor <<= tilesHigh;
128	y += xMajor + yMajor;
129	return stride * y + x;
130}
131
132void mMapCacheCleanTile(struct mMapCache* cache, struct mMapCacheEntry* entry, unsigned x, unsigned y) {
133	size_t location = _tileId(cache, x, y);
134	struct mMapCacheEntry* status = &cache->status[location];
135	int paletteId = mMapCacheEntryFlagsGetPaletteId(status->flags);
136	const color_t* tile = NULL;
137	if (!mMapCacheEntryFlagsIsVramClean(status->flags)) {
138		status->flags = mMapCacheEntryFlagsFillVramClean(status->flags);
139		cache->mapParser(cache, status, &cache->vram[cache->mapStart + (location << mMapCacheSystemInfoGetMapAlign(cache->sysConfig))]);
140		tile = mTileCacheGetTileIfDirty(cache->tileCache, &status->tileStatus[paletteId], status->tileId + cache->tileStart, mMapCacheEntryFlagsGetPaletteId(status->flags));
141		if (!tile) {
142			tile = mTileCacheGetTile(cache->tileCache, status->tileId + cache->tileStart, mMapCacheEntryFlagsGetPaletteId(status->flags));
143		}
144	} else {
145		tile = mTileCacheGetTileIfDirty(cache->tileCache, &status->tileStatus[paletteId], status->tileId + cache->tileStart, mMapCacheEntryFlagsGetPaletteId(status->flags));
146		if (!tile && memcmp(status, &entry[location], sizeof(*entry)) == 0) {
147			return;
148		}
149		tile = mTileCacheGetTile(cache->tileCache, status->tileId + cache->tileStart, mMapCacheEntryFlagsGetPaletteId(status->flags));
150	}
151
152	size_t stride = 8 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
153	color_t* mapOut = &cache->cache[(y * stride + x) * 8];
154	_cleanTile(cache, tile, mapOut, status);
155	entry[location] = *status;
156}
157
158bool mMapCacheCheckTile(struct mMapCache* cache, const struct mMapCacheEntry* entry, unsigned x, unsigned y) {
159	size_t location = _tileId(cache, x, y);
160	struct mMapCacheEntry* status = &cache->status[location];
161	int paletteId = mMapCacheEntryFlagsGetPaletteId(status->flags);
162	const color_t* tile = NULL;
163	if (mMapCacheEntryFlagsIsVramClean(status->flags) && memcmp(status, &entry[location], sizeof(*entry)) == 0) {
164		tile = mTileCacheGetTileIfDirty(cache->tileCache, &status->tileStatus[paletteId], status->tileId + cache->tileStart, mMapCacheEntryFlagsGetPaletteId(status->flags));
165		return !tile;
166	}
167	return false;
168}
169
170const color_t* mMapCacheGetRow(struct mMapCache* cache, unsigned y) {
171	size_t stride = 8 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
172	return &cache->cache[y * stride];
173}