all repos — mgba @ f388d65f5fcac60a3b34253d22538b09d62fc9ad

mGBA Game Boy Advance Emulator

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}