src/core/map-cache.c (view raw)
1/* Copyright (c) 2013-2017 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/map-cache.h>
7
8#include <mgba-util/memory.h>
9
10void mMapCacheInit(struct mMapCache* cache) {
11 // TODO: Reconfigurable cache for space savings
12 cache->cache = NULL;
13 cache->config = mMapCacheConfigurationFillShouldStore(0);
14 cache->status = NULL;
15}
16
17static void _freeCache(struct mMapCache* cache) {
18 size_t tiles = (1 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig)) * (1 << mMapCacheSystemInfoGetTilesHigh(cache->sysConfig));
19 mappedMemoryFree(cache->cache, 8 * 8 * sizeof(color_t) * tiles);
20 mappedMemoryFree(cache->status, tiles * sizeof(*cache->status));
21 cache->cache = NULL;
22 cache->status = NULL;
23}
24
25static void _redoCacheSize(struct mMapCache* cache) {
26 if (!mMapCacheConfigurationIsShouldStore(cache->config)) {
27 return;
28 }
29
30 size_t tiles = (1 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig)) * (1 << mMapCacheSystemInfoGetTilesHigh(cache->sysConfig));
31 cache->cache = anonymousMemoryMap(8 * 8 * sizeof(color_t) * tiles);
32 cache->status = anonymousMemoryMap(tiles * sizeof(*cache->status));
33}
34
35void mMapCacheConfigure(struct mMapCache* cache, mMapCacheConfiguration config) {
36 if (config == cache->config) {
37 return;
38 }
39 _freeCache(cache);
40 cache->config = config;
41 _redoCacheSize(cache);
42}
43
44void mMapCacheConfigureSystem(struct mMapCache* cache, mMapCacheSystemInfo config) {
45 if (config == cache->sysConfig) {
46 return;
47 }
48 _freeCache(cache);
49 cache->sysConfig = config;
50 _redoCacheSize(cache);
51
52 size_t mapSize = (1 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig)) * (1 << mMapCacheSystemInfoGetTilesHigh(cache->sysConfig));
53 cache->mapSize = mapSize << mMapCacheSystemInfoGetMapAlign(cache->sysConfig);
54}
55
56void mMapCacheConfigureMap(struct mMapCache* cache, uint32_t mapStart) {
57 size_t tiles = (1 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig)) * (1 << mMapCacheSystemInfoGetTilesHigh(cache->sysConfig));
58 memset(cache->status, 0, tiles * sizeof(*cache->status));
59 cache->mapStart = mapStart;
60}
61
62void mMapCacheDeinit(struct mMapCache* cache) {
63 _freeCache(cache);
64}
65
66void mMapCacheWriteVRAM(struct mMapCache* cache, uint32_t address) {
67 if (address >= cache->mapStart && address < cache->mapStart + cache->mapSize) {
68 address -= cache->mapStart;
69 struct mMapCacheEntry* status = &cache->status[address >> mMapCacheSystemInfoGetMapAlign(cache->sysConfig)];
70 ++status->vramVersion;
71 status->flags = mMapCacheEntryFlagsClearVramClean(status->flags);
72 status->tileStatus[mMapCacheEntryFlagsGetPaletteId(status->flags)].vramClean = 0;
73 }
74}
75
76static inline void _cleanTile(struct mMapCache* cache, const color_t* tile, color_t* mapOut, const struct mMapCacheEntry* status) {
77 size_t stride = 8 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
78 int x, y;
79 switch (mMapCacheEntryFlagsGetMirror(status->flags)) {
80 case 0:
81 memcpy(mapOut, tile, sizeof(color_t) * 8);
82 memcpy(&mapOut[stride], &tile[0x08], sizeof(color_t) * 8);
83 memcpy(&mapOut[stride * 2], &tile[0x10], sizeof(color_t) * 8);
84 memcpy(&mapOut[stride * 3], &tile[0x18], sizeof(color_t) * 8);
85 memcpy(&mapOut[stride * 4], &tile[0x20], sizeof(color_t) * 8);
86 memcpy(&mapOut[stride * 5], &tile[0x28], sizeof(color_t) * 8);
87 memcpy(&mapOut[stride * 6], &tile[0x30], sizeof(color_t) * 8);
88 memcpy(&mapOut[stride * 7], &tile[0x38], sizeof(color_t) * 8);
89 break;
90 case 1:
91 for (y = 0; y < 8; ++y) {
92 for (x = 0; x < 8; ++x) {
93 mapOut[y * stride + (7 - x)] = tile[y * 8 + x];
94 }
95 }
96 break;
97 case 2:
98 memcpy(&mapOut[stride * 7], tile, sizeof(color_t) * 8);
99 memcpy(&mapOut[stride * 6], &tile[0x08], sizeof(color_t) * 8);
100 memcpy(&mapOut[stride * 5], &tile[0x10], sizeof(color_t) * 8);
101 memcpy(&mapOut[stride * 4], &tile[0x18], sizeof(color_t) * 8);
102 memcpy(&mapOut[stride * 3], &tile[0x20], sizeof(color_t) * 8);
103 memcpy(&mapOut[stride * 2], &tile[0x28], sizeof(color_t) * 8);
104 memcpy(&mapOut[stride], &tile[0x30], sizeof(color_t) * 8);
105 memcpy(mapOut, &tile[0x38], sizeof(color_t) * 8);
106 break;
107 case 3:
108 for (y = 0; y < 8; ++y) {
109 for (x = 0; x < 8; ++x) {
110 mapOut[(7 - y) * stride + (7 - x)] = tile[y * 8 + x];
111 }
112 }
113 break;
114 }
115}
116
117uint32_t mMapCacheTileId(struct mMapCache* cache, unsigned x, unsigned y) {
118 int tilesWide = mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
119 int tilesHigh = mMapCacheSystemInfoGetTilesHigh(cache->sysConfig);
120 int stride = 1 << mMapCacheSystemInfoGetMacroTileSize(cache->sysConfig);
121 x &= (1 << tilesWide) - 1;
122 y &= (1 << tilesHigh) - 1;
123 unsigned xMajor = x & ~(stride - 1);
124 unsigned yMajor = y >> mMapCacheSystemInfoGetMacroTileSize(cache->sysConfig);
125 x &= stride - 1;
126 y &= stride - 1;
127 yMajor <<= tilesWide;
128 y += xMajor + yMajor;
129 return stride * y + x;
130}
131
132void mMapCacheCleanTile(struct mMapCache* cache, struct mMapCacheEntry* entry, unsigned x, unsigned y) {
133 size_t location = mMapCacheTileId(cache, x, y);
134 struct mMapCacheEntry* status = &cache->status[location];
135 const color_t* tile = NULL;
136 if (!mMapCacheEntryFlagsIsVramClean(status->flags)) {
137 status->flags = mMapCacheEntryFlagsFillVramClean(status->flags);
138 cache->mapParser(cache, status, &cache->vram[cache->mapStart + (location << mMapCacheSystemInfoGetMapAlign(cache->sysConfig))]);
139 }
140 unsigned tileId = status->tileId + cache->tileStart;
141 if (tileId >= mTileCacheSystemInfoGetMaxTiles(cache->tileCache->sysConfig)) {
142 tileId = 0;
143 }
144 tile = mTileCacheGetTileIfDirty(cache->tileCache, status->tileStatus, tileId, mMapCacheEntryFlagsGetPaletteId(status->flags));
145 if (!tile) {
146 if (mMapCacheEntryFlagsIsVramClean(status->flags) && memcmp(status, &entry[location], sizeof(*entry)) == 0) {
147 return;
148 }
149 tile = mTileCacheGetTile(cache->tileCache, tileId, mMapCacheEntryFlagsGetPaletteId(status->flags));
150 }
151
152 size_t stride = 8 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
153 color_t* mapOut = &cache->cache[(y * stride + x) * 8];
154 _cleanTile(cache, tile, mapOut, status);
155 entry[location] = *status;
156}
157
158bool mMapCacheCheckTile(struct mMapCache* cache, const struct mMapCacheEntry* entry, unsigned x, unsigned y) {
159 size_t location = mMapCacheTileId(cache, x, y);
160 struct mMapCacheEntry* status = &cache->status[location];
161 int paletteId = mMapCacheEntryFlagsGetPaletteId(status->flags);
162 const color_t* tile = NULL;
163 if (mMapCacheEntryFlagsIsVramClean(status->flags) && memcmp(status, &entry[location], sizeof(*entry)) == 0) {
164 unsigned tileId = status->tileId + cache->tileStart;
165 if (tileId >= mTileCacheSystemInfoGetMaxTiles(cache->tileCache->sysConfig)) {
166 tileId = 0;
167 }
168 tile = mTileCacheGetTileIfDirty(cache->tileCache, &status->tileStatus[paletteId], tileId, mMapCacheEntryFlagsGetPaletteId(status->flags));
169 return !tile;
170 }
171 return false;
172}
173
174void mMapCacheCleanRow(struct mMapCache* cache, unsigned y) {
175 // TODO: Cache
176 int tilesWide = 1 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
177 int macroTile = (1 << mMapCacheSystemInfoGetMacroTileSize(cache->sysConfig)) - 1;
178 size_t stride = 8 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
179 int location = 0;
180 int x;
181 for (x = 0; x < tilesWide; ++x) {
182 if (!(x & macroTile)) {
183 location = mMapCacheTileId(cache, x, y);
184 } else {
185 ++location;
186 }
187 struct mMapCacheEntry* status = &cache->status[location];
188 if (!mMapCacheEntryFlagsIsVramClean(status->flags)) {
189 status->flags = mMapCacheEntryFlagsFillVramClean(status->flags);
190 cache->mapParser(cache, status, &cache->vram[cache->mapStart + (location << mMapCacheSystemInfoGetMapAlign(cache->sysConfig))]);
191 }
192 unsigned tileId = status->tileId + cache->tileStart;
193 if (tileId >= mTileCacheSystemInfoGetMaxTiles(cache->tileCache->sysConfig)) {
194 tileId = 0;
195 }
196 const color_t* tile = mTileCacheGetTile(cache->tileCache, tileId, mMapCacheEntryFlagsGetPaletteId(status->flags));
197 color_t* mapOut = &cache->cache[(y * stride + x) * 8];
198 _cleanTile(cache, tile, mapOut, status);
199 }
200}
201
202const color_t* mMapCacheGetRow(struct mMapCache* cache, unsigned y) {
203 size_t stride = 8 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
204 return &cache->cache[y * stride];
205}