src/gba/renderers/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 "gba/video.h"
9#include "util/memory.h"
10
11#define CACHE_SIZE (8 * 8 * 2 * 1024 * 3 * 16)
12
13void GBAVideoTileCacheInit(struct GBAVideoTileCache* cache) {
14 // TODO: Reconfigurable cache for space savings
15 cache->cache = anonymousMemoryMap(CACHE_SIZE);
16 memset(cache->status, 0, sizeof(cache->status));
17 memset(cache->globalPaletteVersion, 0, sizeof(cache->globalPaletteVersion));
18 memset(cache->globalPalette256Version, 0, sizeof(cache->globalPalette256Version));
19}
20
21void GBAVideoTileCacheDeinit(struct GBAVideoTileCache* cache) {
22 mappedMemoryFree(cache->cache, CACHE_SIZE);
23 cache->cache = NULL;
24}
25
26void GBAVideoTileCacheAssociate(struct GBAVideoTileCache* cache, struct GBAVideo* video) {
27 cache->vram = video->vram;
28 cache->palette = video->palette;
29 video->renderer->cache = cache;
30}
31
32void GBAVideoTileCacheWriteVRAM(struct GBAVideoTileCache* cache, uint32_t address) {
33 cache->status[address >> 5].vramClean = 0;
34}
35
36void GBAVideoTileCacheWritePalette(struct GBAVideoTileCache* cache, uint32_t address) {
37 ++cache->globalPaletteVersion[address >> 5];
38 ++cache->globalPalette256Version[address >> 9];
39}
40
41static void _regenerateTile16(struct GBAVideoTileCache* cache, unsigned tileId, unsigned paletteId) {
42 uint16_t* tile = &cache->cache[tileId << 6];
43 uint32_t* start = (uint32_t*) &cache->vram[tileId << 4];
44 paletteId <<= 4;
45 uint16_t* palette = &cache->palette[paletteId];
46 int i;
47 for (i = 0; i < 8; ++i) {
48 uint32_t line = *start;
49 ++start;
50 int pixel;
51 pixel = line & 0xF;
52 tile[0] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
53 pixel = (line >> 4) & 0xF;
54 tile[1] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
55 pixel = (line >> 8) & 0xF;
56 tile[2] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
57 pixel = (line >> 12) & 0xF;
58 tile[3] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
59 pixel = (line >> 16) & 0xF;
60 tile[4] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
61 pixel = (line >> 20) & 0xF;
62 tile[5] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
63 pixel = (line >> 24) & 0xF;
64 tile[6] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
65 pixel = (line >> 28) & 0xF;
66 tile[7] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
67 tile += 8;
68 }
69}
70
71static void _regenerateTile256(struct GBAVideoTileCache* cache, unsigned tileId, unsigned paletteId) {
72 uint16_t* tile = &cache->cache[tileId << 6];
73 uint32_t* start = (uint32_t*) &cache->vram[tileId << 5];
74 paletteId <<= 8;
75 uint16_t* palette = &cache->palette[paletteId];
76 int i;
77 for (i = 0; i < 8; ++i) {
78 uint32_t line = *start;
79 ++start;
80 int pixel;
81 pixel = line & 0xFF;
82 tile[0] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
83 pixel = (line >> 8) & 0xFF;
84 tile[1] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
85 pixel = (line >> 16) & 0xFF;
86 tile[2] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
87 pixel = (line >> 24) & 0xFF;
88 tile[3] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
89
90 line = *start;
91 ++start;
92 pixel = line & 0xFF;
93 tile[4] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
94 pixel = (line >> 8) & 0xFF;
95 tile[5] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
96 pixel = (line >> 16) & 0xFF;
97 tile[6] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
98 pixel = (line >> 24) & 0xFF;
99 tile[7] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
100 tile += 8;
101 }
102}
103
104const uint16_t* GBAVideoTileCacheGetTile16(struct GBAVideoTileCache* cache, unsigned tileId, unsigned paletteId) {
105 struct GBAVideoTileCacheEntry* status = &cache->status[tileId];
106 if (!status->vramClean || status->palette256 || status->paletteVersion[paletteId & 0xF] != cache->globalPaletteVersion[paletteId]) {
107 _regenerateTile16(cache, tileId, paletteId);
108 status->paletteVersion[paletteId & 0xF] = cache->globalPaletteVersion[paletteId];
109 status->palette256 = 0;
110 status->vramClean = 1;
111 }
112 return &cache->cache[tileId << 6];
113}
114
115const uint16_t* GBAVideoTileCacheGetTile16IfDirty(struct GBAVideoTileCache* cache, unsigned tileId, unsigned paletteId) {
116 struct GBAVideoTileCacheEntry* status = &cache->status[tileId];
117 if (!status->vramClean || status->palette256 || status->paletteVersion[paletteId & 0xF] != cache->globalPaletteVersion[paletteId]) {
118 _regenerateTile16(cache, tileId, paletteId);
119 status->paletteVersion[paletteId & 0xF] = cache->globalPaletteVersion[paletteId];
120 status->palette256 = 0;
121 status->vramClean = 1;
122 return &cache->cache[tileId << 6];
123 }
124 return NULL;
125}
126
127
128const uint16_t* GBAVideoTileCacheGetTile256(struct GBAVideoTileCache* cache, unsigned tileId, unsigned paletteId) {
129 struct GBAVideoTileCacheEntry* status = &cache->status[tileId];
130 if (!status->vramClean || !status->palette256 || status->paletteVersion[0] != cache->globalPalette256Version[paletteId]) {
131 _regenerateTile256(cache, tileId, paletteId);
132 status->paletteVersion[0] = cache->globalPalette256Version[paletteId];
133 status->palette256 = 1;
134 status->vramClean = 1;
135 }
136 return &cache->cache[tileId << 6];
137}
138
139const uint16_t* GBAVideoTileCacheGetTile256IfDirty(struct GBAVideoTileCache* cache, unsigned tileId, unsigned paletteId) {
140 struct GBAVideoTileCacheEntry* status = &cache->status[tileId];
141 if (!status->vramClean || !status->palette256 || status->paletteVersion[0] != cache->globalPalette256Version[paletteId]) {
142 _regenerateTile256(cache, tileId, paletteId);
143 status->paletteVersion[0] = cache->globalPalette256Version[paletteId];
144 status->palette256 = 1;
145 status->vramClean = 1;
146 return &cache->cache[tileId << 6];
147 }
148 return NULL;
149}