all repos — mgba @ 6900d130ae1fc082ac98c53213a4d31b1f9928fb

mGBA Game Boy Advance Emulator

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

  1/* Copyright (c) 2013-2019 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/bitmap-cache.h>
  7
  8#include <mgba-util/memory.h>
  9
 10void mBitmapCacheInit(struct mBitmapCache* cache) {
 11	// TODO: Reconfigurable cache for space savings
 12	cache->cache = NULL;
 13	cache->config = mBitmapCacheConfigurationFillShouldStore(0);
 14	cache->status = NULL;
 15	cache->palette = NULL;
 16	cache->buffer = 0;
 17}
 18
 19static void _freeCache(struct mBitmapCache* cache) {
 20	size_t size = mBitmapCacheSystemInfoGetHeight(cache->sysConfig) * mBitmapCacheSystemInfoGetBuffers(cache->sysConfig);
 21	mappedMemoryFree(cache->cache, mBitmapCacheSystemInfoGetWidth(cache->sysConfig) * size * sizeof(color_t));
 22	mappedMemoryFree(cache->status, size * sizeof(*cache->status));
 23	if (cache->palette) {
 24		free(cache->palette);
 25	}
 26	cache->cache = NULL;
 27	cache->status = NULL;
 28	cache->palette = NULL;
 29}
 30
 31static void _redoCacheSize(struct mBitmapCache* cache) {
 32	if (!mBitmapCacheConfigurationIsShouldStore(cache->config)) {
 33		return;
 34	}
 35
 36	size_t size = mBitmapCacheSystemInfoGetHeight(cache->sysConfig) * mBitmapCacheSystemInfoGetBuffers(cache->sysConfig);
 37	cache->cache = anonymousMemoryMap(mBitmapCacheSystemInfoGetWidth(cache->sysConfig) * size * sizeof(color_t));
 38	cache->status = anonymousMemoryMap(size * sizeof(*cache->status));
 39	if (mBitmapCacheSystemInfoIsUsesPalette(cache->sysConfig)) {
 40		cache->palette = malloc((1 << (1 << mBitmapCacheSystemInfoGetEntryBPP(cache->sysConfig))) * sizeof(color_t));
 41	} else {
 42		cache->palette = NULL;
 43	}
 44}
 45
 46void mBitmapCacheConfigure(struct mBitmapCache* cache, mBitmapCacheConfiguration config) {
 47	if (config == cache->config) {
 48		return;
 49	}
 50	_freeCache(cache);
 51	cache->config = config;
 52	_redoCacheSize(cache);
 53}
 54
 55void mBitmapCacheConfigureSystem(struct mBitmapCache* cache, mBitmapCacheSystemInfo config) {
 56	if (config == cache->sysConfig) {
 57		return;
 58	}
 59	_freeCache(cache);
 60	cache->sysConfig = config;
 61	_redoCacheSize(cache);
 62
 63	size_t stride = mBitmapCacheSystemInfoGetWidth(cache->sysConfig);
 64	size_t size = stride * mBitmapCacheSystemInfoGetHeight(cache->sysConfig);
 65	size_t bpe = mBitmapCacheSystemInfoGetEntryBPP(cache->sysConfig);
 66	if (bpe > 3) {
 67		size <<= bpe - 3;
 68		stride <<= bpe - 3;
 69	} else {
 70		size >>= 3 - bpe;
 71		stride >>= 3 - bpe;
 72	}
 73	cache->bitsSize = size;
 74	cache->stride = stride;
 75}
 76
 77void mBitmapCacheDeinit(struct mBitmapCache* cache) {
 78	_freeCache(cache);
 79}
 80
 81void mBitmapCacheWriteVRAM(struct mBitmapCache* cache, uint32_t address) {
 82	size_t i;
 83	for (i = 0; i < mBitmapCacheSystemInfoGetBuffers(cache->sysConfig); ++i) {
 84		if (address < cache->bitsStart[i]) {
 85			continue;
 86		}
 87		uint32_t offset = address - cache->bitsStart[i];
 88		if (offset >= cache->bitsSize) {
 89			continue;
 90		}
 91		offset /= cache->stride;
 92		offset *= mBitmapCacheSystemInfoGetBuffers(cache->sysConfig);
 93		offset += cache->buffer;
 94		cache->status[offset].vramClean = 0;
 95		++cache->status[offset].vramVersion;
 96	}
 97}
 98
 99void mBitmapCacheWritePalette(struct mBitmapCache* cache, uint32_t entry, color_t color) {
100	if (!mBitmapCacheSystemInfoIsUsesPalette(cache->sysConfig)) {
101		return;
102	}
103	size_t maxEntry = 1 << (1 << mBitmapCacheSystemInfoGetEntryBPP(cache->sysConfig));
104	if (entry >= maxEntry) {
105		return;
106	}
107	cache->palette[entry] = color;
108	++cache->globalPaletteVersion;
109}
110
111uint32_t _lookupEntry8(void* vram, uint32_t offset) {
112	return ((uint8_t*) vram)[offset];
113}
114
115uint32_t _lookupEntry15(void* vram, uint32_t offset) {
116	return mColorFrom555(((uint16_t*) vram)[offset]);
117}
118
119void mBitmapCacheCleanRow(struct mBitmapCache* cache, struct mBitmapCacheEntry* entry, unsigned y) {
120	color_t* row = &cache->cache[(cache->buffer * mBitmapCacheSystemInfoGetHeight(cache->sysConfig) + y) * mBitmapCacheSystemInfoGetWidth(cache->sysConfig)];
121	size_t location = cache->buffer + mBitmapCacheSystemInfoGetBuffers(cache->sysConfig) * y;
122	struct mBitmapCacheEntry* status = &cache->status[location];
123	struct mBitmapCacheEntry desiredStatus = {
124		.paletteVersion = cache->globalPaletteVersion,
125		.vramVersion = entry->vramVersion,
126		.vramClean = 1
127	};
128
129	if (entry) {
130		entry[location] = desiredStatus;
131	}
132
133	if (!mBitmapCacheConfigurationIsShouldStore(cache->config) || !memcmp(status, &desiredStatus, sizeof(*entry))) {
134		return;
135	}
136
137	size_t offset = cache->bitsStart[cache->buffer] + y * mBitmapCacheSystemInfoGetWidth(cache->sysConfig);
138	void* vram;
139	int bpe = mBitmapCacheSystemInfoGetEntryBPP(cache->sysConfig);
140	uint32_t (*lookupEntry)(void*, uint32_t);
141	switch (bpe) {
142	case 3:
143		lookupEntry = _lookupEntry8;
144		vram = &cache->vram[offset];
145		break;
146	case 4:
147		lookupEntry = _lookupEntry15;
148		vram = &cache->vram[offset << 1];
149		break;
150	default:
151		abort();
152		break;
153	}
154
155	size_t x;
156	if (mBitmapCacheSystemInfoIsUsesPalette(cache->sysConfig)) {
157		for (x = 0; x < mBitmapCacheSystemInfoGetWidth(cache->sysConfig); ++x) {
158			row[x] = cache->palette[lookupEntry(vram, x)];
159		}
160	} else {
161		for (x = 0; x < mBitmapCacheSystemInfoGetWidth(cache->sysConfig); ++x) {
162			row[x] = lookupEntry(vram, x);
163		}
164	}
165	*status = desiredStatus;
166}
167
168bool mBitmapCacheCheckRow(struct mBitmapCache* cache, const struct mBitmapCacheEntry* entry, unsigned y) {
169	size_t location = cache->buffer + mBitmapCacheSystemInfoGetBuffers(cache->sysConfig) * y;
170	struct mBitmapCacheEntry desiredStatus = {
171		.paletteVersion = cache->globalPaletteVersion,
172		.vramVersion = entry->vramVersion,
173		.vramClean = 1
174	};
175
176	return memcmp(&entry[location], &desiredStatus, sizeof(*entry)) == 0;
177}
178
179const color_t* mBitmapCacheGetRow(struct mBitmapCache* cache, unsigned y) {
180	color_t* row = &cache->cache[(cache->buffer * mBitmapCacheSystemInfoGetHeight(cache->sysConfig) + y) * mBitmapCacheSystemInfoGetWidth(cache->sysConfig)];
181	return row;
182}