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}