all repos — mgba @ eab5ed6e142e75656adbe918f2422d936f67c5c2

mGBA Game Boy Advance Emulator

src/core/video-proxy.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/video-proxy.h>
  7
  8#include <mgba-util/memory.h>
  9
 10static inline size_t _roundUp(size_t value, int shift) {
 11	value += (1 << shift) - 1;
 12	return value >> shift;
 13}
 14
 15void mVideoProxyRendererInit(struct mVideoProxy* proxy) {
 16	proxy->palette = anonymousMemoryMap(proxy->paletteSize);
 17	proxy->vram = anonymousMemoryMap(proxy->vramSize);
 18	proxy->oam = anonymousMemoryMap(proxy->oamSize);
 19
 20	proxy->vramDirtyBitmap = calloc(_roundUp(proxy->vramSize, 17), sizeof(uint32_t));
 21	proxy->oamDirtyBitmap = calloc(_roundUp(proxy->oamSize, 6), sizeof(uint32_t));
 22}
 23
 24void mVideoProxyRendererDeinit(struct mVideoProxy* proxy) {
 25	mappedMemoryFree(proxy->palette, proxy->paletteSize);
 26	mappedMemoryFree(proxy->vram, proxy->vramSize);
 27	mappedMemoryFree(proxy->oam, proxy->oamSize);
 28
 29	free(proxy->vramDirtyBitmap);
 30	free(proxy->oamDirtyBitmap);
 31}
 32
 33void mVideoProxyRendererReset(struct mVideoProxy* proxy) {
 34	memset(proxy->vramDirtyBitmap, 0, sizeof(uint32_t) * _roundUp(proxy->vramSize, 17));
 35	memset(proxy->oamDirtyBitmap, 0, sizeof(uint32_t) * _roundUp(proxy->oamSize, 6));
 36}
 37
 38void mVideoProxyRendererWriteVideoRegister(struct mVideoProxy* proxy, uint32_t address, uint16_t value) {
 39	struct mVideoProxyDirtyInfo dirty = {
 40		DIRTY_REGISTER,
 41		address,
 42		value,
 43		0xDEADBEEF,
 44	};
 45	proxy->writeData(proxy, &dirty, sizeof(dirty));
 46}
 47
 48void mVideoProxyRendererWriteVRAM(struct mVideoProxy* proxy, uint32_t address) {
 49	int bit = 1 << (address >> 12);
 50	if (proxy->vramDirtyBitmap[address >> 17] & bit) {
 51		return;
 52	}
 53	proxy->vramDirtyBitmap[address >> 17] |= bit;
 54}
 55
 56void mVideoProxyRendererWritePalette(struct mVideoProxy* proxy, uint32_t address, uint16_t value) {
 57	struct mVideoProxyDirtyInfo dirty = {
 58		DIRTY_PALETTE,
 59		address,
 60		value,
 61		0xDEADBEEF,
 62	};
 63	proxy->writeData(proxy, &dirty, sizeof(dirty));
 64}
 65
 66void mVideoProxyRendererWriteOAM(struct mVideoProxy* proxy, uint32_t address, uint16_t value) {
 67	struct mVideoProxyDirtyInfo dirty = {
 68		DIRTY_OAM,
 69		address,
 70		value,
 71		0xDEADBEEF,
 72	};
 73	proxy->writeData(proxy, &dirty, sizeof(dirty));
 74}
 75
 76void mVideoProxyRendererDrawScanline(struct mVideoProxy* proxy, int y) {
 77	size_t i;
 78	for (i = 0; i < _roundUp(proxy->vramSize, 17); ++i) {
 79		if (proxy->vramDirtyBitmap[i]) {
 80			uint32_t bitmap = proxy->vramDirtyBitmap[i];
 81			proxy->vramDirtyBitmap[i] = 0;
 82			int j;
 83			for (j = 0; j < 32; ++j) {
 84				if (!(bitmap & (1 << j))) {
 85					continue;
 86				}
 87				struct mVideoProxyDirtyInfo dirty = {
 88					DIRTY_VRAM,
 89					j * 0x1000,
 90					0xABCD,
 91					0xDEADBEEF,
 92				};
 93				proxy->writeData(proxy, &dirty, sizeof(dirty));
 94				proxy->writeData(proxy, proxy->vramBlock(proxy, j * 0x1000), 0x1000);
 95			}
 96		}
 97	}
 98	struct mVideoProxyDirtyInfo dirty = {
 99		DIRTY_SCANLINE,
100		y,
101		0,
102		0xDEADBEEF,
103	};
104	proxy->writeData(proxy, &dirty, sizeof(dirty));
105}
106
107void mVideoProxyRendererFlush(struct mVideoProxy* proxy) {
108	struct mVideoProxyDirtyInfo dirty = {
109		DIRTY_FLUSH,
110		0,
111		0,
112		0xDEADBEEF,
113	};
114	proxy->writeData(proxy, &dirty, sizeof(dirty));
115}
116
117bool mVideoProxyRendererRun(struct mVideoProxy* proxy) {
118	struct mVideoProxyDirtyInfo item = {0};
119	while (proxy->readData(proxy, &item, sizeof(item), false)) {
120		switch (item.type) {
121		case DIRTY_REGISTER:
122		case DIRTY_PALETTE:
123		case DIRTY_OAM:
124		case DIRTY_VRAM:
125		case DIRTY_SCANLINE:
126		case DIRTY_FLUSH:
127			if (!proxy->parsePacket(proxy, &item)) {
128				return true;
129			}
130			break;
131		default:
132			return false;
133		}
134	}
135	return true;
136}