all repos — mgba @ 2f066a979031136e7686ceee91af9e8a2e7cc754

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