src/core/tile-cache.c (view raw)
1/* Copyright (c) 2013-2016 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 "tile-cache.h"
7
8#include "util/memory.h"
9
10void mTileCacheInit(struct mTileCache* cache) {
11 // TODO: Reconfigurable cache for space savings
12 cache->cache = NULL;
13 cache->config = mTileCacheConfigurationFillShouldStore(0);
14 cache->status = NULL;
15 cache->activePalette = 0;
16 memset(cache->globalPaletteVersion, 0, sizeof(cache->globalPaletteVersion));
17}
18
19static void _freeCache(struct mTileCache* cache) {
20 unsigned count0;
21 count0 = 1 << mTileCacheSystemInfoGetPalette0Count(cache->sysConfig);
22 unsigned count1;
23 count1 = 1 << mTileCacheSystemInfoGetPalette1Count(cache->sysConfig);
24 unsigned tiles = mTileCacheSystemInfoGetMaxTiles(cache->sysConfig);
25 unsigned size = count0 > count1 ? count0 : count1;
26 if (cache->cache) {
27 mappedMemoryFree(cache->cache, 8 * 8 * 2 * tiles * size);
28 cache->cache = NULL;
29 }
30 if (cache->status) {
31 mappedMemoryFree(cache->status, tiles * size * sizeof(*cache->status));
32 cache->status = NULL;
33 }
34 free(cache->globalPaletteVersion[0]);
35 free(cache->globalPaletteVersion[1]);
36 memset(cache->globalPaletteVersion, 0, sizeof(cache->globalPaletteVersion));
37}
38
39static void _redoCacheSize(struct mTileCache* cache) {
40 if (!mTileCacheConfigurationIsShouldStore(cache->config)) {
41 return;
42 }
43 unsigned count0 = mTileCacheSystemInfoGetPalette0Count(cache->sysConfig);
44 unsigned bpp0 = mTileCacheSystemInfoGetPalette0BPP(cache->sysConfig);
45 bpp0 = 1 << (1 << bpp0);
46 if (count0) {
47 count0 = 1 << count0;
48 }
49 unsigned count1 = mTileCacheSystemInfoGetPalette1Count(cache->sysConfig);
50 unsigned bpp1 = mTileCacheSystemInfoGetPalette1BPP(cache->sysConfig);
51 bpp1 = 1 << (1 << bpp1);
52 if (count1) {
53 count1 = 1 << count1;
54 }
55 unsigned size = count0 > count1 ? count0 : count1;
56 if (!size) {
57 return;
58 }
59 unsigned tiles = mTileCacheSystemInfoGetMaxTiles(cache->sysConfig);
60 cache->cache = anonymousMemoryMap(8 * 8 * 2 * tiles * size);
61 cache->status = anonymousMemoryMap(tiles * size * sizeof(*cache->status));
62 if (count0) {
63 cache->globalPaletteVersion[0] = malloc(count0 * bpp0 * sizeof(*cache->globalPaletteVersion[0]));
64 }
65 if (count1) {
66 cache->globalPaletteVersion[1] = malloc(count1 * bpp1 * sizeof(*cache->globalPaletteVersion[1]));
67 }
68}
69
70void mTileCacheConfigure(struct mTileCache* cache, mTileCacheConfiguration config) {
71 _freeCache(cache);
72 cache->config = config;
73 _redoCacheSize(cache);
74}
75
76void mTileCacheConfigureSystem(struct mTileCache* cache, mTileCacheSystemInfo config) {
77 _freeCache(cache);
78 cache->sysConfig = config;
79 _redoCacheSize(cache);
80}
81
82void mTileCacheDeinit(struct mTileCache* cache) {
83 _freeCache(cache);
84}
85
86void mTileCacheWriteVRAM(struct mTileCache* cache, uint32_t address) {
87 unsigned bpp = cache->bpp + 3;
88 unsigned count = cache->count;
89 size_t i;
90 for (i = 0; i < count; ++i) {
91 ++cache->status[(address >> bpp) * count + i].vramVersion;
92 cache->status[(address >> bpp) * count + i].vramClean = 0;
93 }
94}
95
96void mTileCacheWritePalette(struct mTileCache* cache, uint32_t address) {
97 if (cache->globalPaletteVersion[0]) {
98 ++cache->globalPaletteVersion[0][address >> 1];
99 }
100 if (cache->globalPaletteVersion[1]) {
101 ++cache->globalPaletteVersion[1][address >> 1];
102 }
103}
104
105void mTileCacheSetPalette(struct mTileCache* cache, int palette) {
106 cache->activePalette = palette;
107 if (palette == 0) {
108 cache->bpp = mTileCacheSystemInfoGetPalette0BPP(cache->sysConfig);
109 cache->count = 1 << mTileCacheSystemInfoGetPalette0Count(cache->sysConfig);
110 } else {
111 cache->bpp = mTileCacheSystemInfoGetPalette1BPP(cache->sysConfig);
112 cache->count = 1 << mTileCacheSystemInfoGetPalette1Count(cache->sysConfig);
113 }
114 cache->entries = 1 << (1 << cache->bpp);
115}
116
117static void _regenerateTile4(struct mTileCache* cache, uint16_t* tile, unsigned tileId, unsigned paletteId) {
118 uint8_t* start = (uint8_t*) &cache->vram[tileId << 3];
119 paletteId <<= 2;
120 uint16_t* palette = &cache->palette[paletteId];
121 int i;
122 for (i = 0; i < 8; ++i) {
123 uint8_t tileDataLower = start[0];
124 uint8_t tileDataUpper = start[1];
125 start += 2;
126 int pixel;
127 pixel = ((tileDataUpper & 128) >> 6) | ((tileDataLower & 128) >> 7);
128 tile[0] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
129 pixel = ((tileDataUpper & 64) >> 5) | ((tileDataLower & 64) >> 6);
130 tile[1] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
131 pixel = ((tileDataUpper & 32) >> 4) | ((tileDataLower & 32) >> 5);
132 tile[2] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
133 pixel = ((tileDataUpper & 16) >> 3) | ((tileDataLower & 16) >> 4);
134 tile[3] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
135 pixel = ((tileDataUpper & 8) >> 2) | ((tileDataLower & 8) >> 3);
136 tile[4] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
137 pixel = ((tileDataUpper & 4) >> 1) | ((tileDataLower & 4) >> 2);
138 tile[5] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
139 pixel = (tileDataUpper & 2) | ((tileDataLower & 2) >> 1);
140 tile[6] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
141 pixel = ((tileDataUpper & 1) << 1) | (tileDataLower & 1);
142 tile[7] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
143 tile += 8;
144 }
145}
146
147static void _regenerateTile16(struct mTileCache* cache, uint16_t* tile, unsigned tileId, unsigned paletteId) {
148 uint32_t* start = (uint32_t*) &cache->vram[tileId << 4];
149 paletteId <<= 4;
150 uint16_t* palette = &cache->palette[paletteId];
151 int i;
152 for (i = 0; i < 8; ++i) {
153 uint32_t line = *start;
154 ++start;
155 int pixel;
156 pixel = line & 0xF;
157 tile[0] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
158 pixel = (line >> 4) & 0xF;
159 tile[1] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
160 pixel = (line >> 8) & 0xF;
161 tile[2] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
162 pixel = (line >> 12) & 0xF;
163 tile[3] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
164 pixel = (line >> 16) & 0xF;
165 tile[4] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
166 pixel = (line >> 20) & 0xF;
167 tile[5] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
168 pixel = (line >> 24) & 0xF;
169 tile[6] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
170 pixel = (line >> 28) & 0xF;
171 tile[7] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
172 tile += 8;
173 }
174}
175
176static void _regenerateTile256(struct mTileCache* cache, uint16_t* tile, unsigned tileId, unsigned paletteId) {
177 uint32_t* start = (uint32_t*) &cache->vram[tileId << 5];
178 paletteId <<= 8;
179 uint16_t* palette = &cache->palette[paletteId];
180 int i;
181 for (i = 0; i < 8; ++i) {
182 uint32_t line = *start;
183 ++start;
184 int pixel;
185 pixel = line & 0xFF;
186 tile[0] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
187 pixel = (line >> 8) & 0xFF;
188 tile[1] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
189 pixel = (line >> 16) & 0xFF;
190 tile[2] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
191 pixel = (line >> 24) & 0xFF;
192 tile[3] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
193
194 line = *start;
195 ++start;
196 pixel = line & 0xFF;
197 tile[4] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
198 pixel = (line >> 8) & 0xFF;
199 tile[5] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
200 pixel = (line >> 16) & 0xFF;
201 tile[6] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
202 pixel = (line >> 24) & 0xFF;
203 tile[7] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
204 tile += 8;
205 }
206}
207
208static inline uint16_t* _tileLookup(struct mTileCache* cache, unsigned tileId, unsigned paletteId) {
209 if (mTileCacheConfigurationIsShouldStore(cache->config)) {
210 unsigned tiles = mTileCacheSystemInfoGetMaxTiles(cache->sysConfig);
211 return &cache->cache[(tileId + paletteId * tiles) << 6];
212 } else {
213 return cache->temporaryTile;
214 }
215}
216
217const uint16_t* mTileCacheGetTile(struct mTileCache* cache, unsigned tileId, unsigned paletteId) {
218 unsigned cPaletteId = cache->activePalette;
219 unsigned count = cache->count;
220 unsigned bpp = cache->bpp;
221 struct mTileCacheEntry* status = &cache->status[tileId * count + paletteId];
222 uint16_t* tile = _tileLookup(cache, tileId, paletteId);
223 if (!mTileCacheConfigurationIsShouldStore(cache->config) || !status->vramClean || status->paletteId != cPaletteId || status->paletteVersion != cache->globalPaletteVersion[cPaletteId][paletteId]) {
224 switch (bpp) {
225 case 0:
226 return NULL;
227 case 1:
228 _regenerateTile4(cache, tile, tileId, paletteId);
229 break;
230 case 2:
231 _regenerateTile16(cache, tile, tileId, paletteId);
232 break;
233 case 3:
234 _regenerateTile256(cache, tile, tileId, paletteId);
235 break;
236 }
237 status->paletteVersion = cache->globalPaletteVersion[cPaletteId][paletteId];
238 status->paletteId = cPaletteId;
239 status->vramClean = 1;
240 }
241 return tile;
242}
243
244const uint16_t* mTileCacheGetTileIfDirty(struct mTileCache* cache, struct mTileCacheEntry* entry, unsigned tileId, unsigned paletteId) {
245 unsigned cPaletteId = cache->activePalette;
246 unsigned count = cache->count;
247 unsigned bpp = cache->bpp;
248 struct mTileCacheEntry* status = &cache->status[tileId * count + paletteId];
249 uint16_t* tile = NULL;
250 if (!status->vramClean || status->paletteId != cPaletteId || status->paletteVersion != cache->globalPaletteVersion[cPaletteId][paletteId]) {
251 tile = _tileLookup(cache, tileId, paletteId);
252 switch (bpp) {
253 case 0:
254 return NULL;
255 case 1:
256 _regenerateTile4(cache, tile, tileId, paletteId);
257 break;
258 case 2:
259 _regenerateTile16(cache, tile, tileId, paletteId);
260 break;
261 case 3:
262 _regenerateTile256(cache, tile, tileId, paletteId);
263 break;
264 }
265 status->paletteVersion = cache->globalPaletteVersion[cPaletteId][paletteId];
266 status->paletteId = cPaletteId;
267 status->vramClean = 1;
268 }
269 if (memcmp(status, &entry[paletteId], sizeof(*status))) {
270 tile = _tileLookup(cache, tileId, paletteId);
271 entry[paletteId] = *status;
272 }
273 return tile;
274}