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}