all repos — mgba @ bed6ba1fc48a7432c8b45ebb38ea7e403c45bfb0

mGBA Game Boy Advance Emulator

src/gba/renderers/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/internal/gba/renderers/proxy.h>
  7
  8#include <mgba/core/tile-cache.h>
  9#include <mgba/internal/gba/gba.h>
 10#include <mgba/internal/gba/io.h>
 11
 12static void GBAVideoProxyRendererInit(struct GBAVideoRenderer* renderer);
 13static void GBAVideoProxyRendererReset(struct GBAVideoRenderer* renderer);
 14static void GBAVideoProxyRendererDeinit(struct GBAVideoRenderer* renderer);
 15static uint16_t GBAVideoProxyRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
 16static void GBAVideoProxyRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address);
 17static void GBAVideoProxyRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
 18static void GBAVideoProxyRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam);
 19static void GBAVideoProxyRendererDrawScanline(struct GBAVideoRenderer* renderer, int y);
 20static void GBAVideoProxyRendererFinishFrame(struct GBAVideoRenderer* renderer);
 21static void GBAVideoProxyRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels);
 22static void GBAVideoProxyRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels);
 23
 24static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerDirtyInfo* packet);
 25static uint16_t* _vramBlock(struct mVideoLogger* logger, uint32_t address);
 26
 27void GBAVideoProxyRendererCreate(struct GBAVideoProxyRenderer* renderer, struct GBAVideoRenderer* backend) {
 28	renderer->d.init = GBAVideoProxyRendererInit;
 29	renderer->d.reset = GBAVideoProxyRendererReset;
 30	renderer->d.deinit = GBAVideoProxyRendererDeinit;
 31	renderer->d.writeVideoRegister = GBAVideoProxyRendererWriteVideoRegister;
 32	renderer->d.writeVRAM = GBAVideoProxyRendererWriteVRAM;
 33	renderer->d.writeOAM = GBAVideoProxyRendererWriteOAM;
 34	renderer->d.writePalette = GBAVideoProxyRendererWritePalette;
 35	renderer->d.drawScanline = GBAVideoProxyRendererDrawScanline;
 36	renderer->d.finishFrame = GBAVideoProxyRendererFinishFrame;
 37	renderer->d.getPixels = GBAVideoProxyRendererGetPixels;
 38	renderer->d.putPixels = GBAVideoProxyRendererPutPixels;
 39
 40	renderer->d.disableBG[0] = false;
 41	renderer->d.disableBG[1] = false;
 42	renderer->d.disableBG[2] = false;
 43	renderer->d.disableBG[3] = false;
 44	renderer->d.disableOBJ = false;
 45
 46	renderer->logger.context = renderer;
 47	renderer->logger.writeData = NULL;
 48	renderer->logger.readData = NULL;
 49	renderer->logger.parsePacket = _parsePacket;
 50	renderer->logger.vramBlock = _vramBlock;
 51	renderer->logger.paletteSize = SIZE_PALETTE_RAM;
 52	renderer->logger.vramSize = SIZE_VRAM;
 53	renderer->logger.oamSize = SIZE_OAM;
 54
 55	renderer->backend = backend;
 56}
 57
 58void GBAVideoProxyRendererInit(struct GBAVideoRenderer* renderer) {
 59	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
 60
 61	mVideoLoggerRendererInit(&proxyRenderer->logger);
 62
 63	if (proxyRenderer->block) {
 64		proxyRenderer->backend->palette = proxyRenderer->logger.palette;
 65		proxyRenderer->backend->vram = proxyRenderer->logger.vram;
 66		proxyRenderer->backend->oam = (union GBAOAM*) proxyRenderer->logger.oam;
 67		proxyRenderer->backend->cache = NULL;
 68	}
 69
 70	proxyRenderer->init(proxyRenderer);
 71
 72	proxyRenderer->backend->init(proxyRenderer->backend);
 73}
 74
 75void GBAVideoProxyRendererReset(struct GBAVideoRenderer* renderer) {
 76	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
 77	memcpy(proxyRenderer->logger.oam, &renderer->oam->raw, SIZE_OAM);
 78	memcpy(proxyRenderer->logger.palette, renderer->palette, SIZE_PALETTE_RAM);
 79	memcpy(proxyRenderer->logger.vram, renderer->vram, SIZE_VRAM);
 80
 81	mVideoLoggerRendererReset(&proxyRenderer->logger);
 82
 83	proxyRenderer->reset(proxyRenderer);
 84
 85	proxyRenderer->backend->reset(proxyRenderer->backend);
 86}
 87
 88void GBAVideoProxyRendererDeinit(struct GBAVideoRenderer* renderer) {
 89	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
 90
 91	proxyRenderer->deinit(proxyRenderer);
 92
 93	proxyRenderer->backend->deinit(proxyRenderer->backend);
 94
 95	mVideoLoggerRendererDeinit(&proxyRenderer->logger);
 96}
 97
 98static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerDirtyInfo* item) {
 99	struct GBAVideoProxyRenderer* proxyRenderer = logger->context;
100	switch (item->type) {
101	case DIRTY_REGISTER:
102		proxyRenderer->backend->writeVideoRegister(proxyRenderer->backend, item->address, item->value);
103		break;
104	case DIRTY_PALETTE:
105		logger->palette[item->address >> 1] = item->value;
106		proxyRenderer->backend->writePalette(proxyRenderer->backend, item->address, item->value);
107		break;
108	case DIRTY_OAM:
109		logger->oam[item->address] = item->value;
110		proxyRenderer->backend->writeOAM(proxyRenderer->backend, item->address);
111		break;
112	case DIRTY_VRAM:
113		logger->readData(logger, &logger->vram[item->address >> 1], 0x1000, true);
114		proxyRenderer->backend->writeVRAM(proxyRenderer->backend, item->address);
115		break;
116	case DIRTY_SCANLINE:
117		proxyRenderer->backend->drawScanline(proxyRenderer->backend, item->address);
118		break;
119	case DIRTY_FLUSH:
120		return false;
121	default:
122		return false;
123	}
124	return true;
125}
126
127static uint16_t* _vramBlock(struct mVideoLogger* logger, uint32_t address) {
128	struct GBAVideoProxyRenderer* proxyRenderer = logger->context;
129	return &proxyRenderer->d.vram[address >> 1];
130}
131
132uint16_t GBAVideoProxyRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
133	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
134	switch (address) {
135	case REG_BG0CNT:
136	case REG_BG1CNT:
137	case REG_BG2CNT:
138	case REG_BG3CNT:
139		value &= 0xFFCF;
140		break;
141	case REG_BG0HOFS:
142	case REG_BG0VOFS:
143	case REG_BG1HOFS:
144	case REG_BG1VOFS:
145	case REG_BG2HOFS:
146	case REG_BG2VOFS:
147	case REG_BG3HOFS:
148	case REG_BG3VOFS:
149		value &= 0x01FF;
150		break;
151	}
152	if (address > REG_BLDY) {
153		return value;
154	}
155
156	mVideoLoggerRendererWriteVideoRegister(&proxyRenderer->logger, address, value);
157	return value;
158}
159
160void GBAVideoProxyRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) {
161	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
162	mVideoLoggerRendererWriteVRAM(&proxyRenderer->logger, address);
163	if (!proxyRenderer->block) {
164		proxyRenderer->backend->writeVRAM(proxyRenderer->backend, address);
165	}
166	if (renderer->cache) {
167		mTileCacheWriteVRAM(renderer->cache, address);
168	}
169}
170
171void GBAVideoProxyRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
172	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
173	mVideoLoggerRendererWritePalette(&proxyRenderer->logger, address, value);
174	if (!proxyRenderer->block) {
175		proxyRenderer->backend->writePalette(proxyRenderer->backend, address, value);
176	}
177	if (renderer->cache) {
178		mTileCacheWritePalette(renderer->cache, address);
179	}
180}
181
182void GBAVideoProxyRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam) {
183	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
184	if (!proxyRenderer->block) {
185		proxyRenderer->backend->writeOAM(proxyRenderer->backend, oam);
186	}
187	mVideoLoggerRendererWriteOAM(&proxyRenderer->logger, oam, proxyRenderer->d.oam->raw[oam]);
188}
189
190void GBAVideoProxyRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
191	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
192	if (!proxyRenderer->block) {
193		proxyRenderer->backend->drawScanline(proxyRenderer->backend, y);
194	}
195	mVideoLoggerRendererDrawScanline(&proxyRenderer->logger, y);
196	if (proxyRenderer->block) {
197		proxyRenderer->wake(proxyRenderer, y);
198	}
199}
200
201void GBAVideoProxyRendererFinishFrame(struct GBAVideoRenderer* renderer) {
202	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
203	if (proxyRenderer->block) {
204		proxyRenderer->lock(proxyRenderer);
205		proxyRenderer->wait(proxyRenderer);
206	}
207	mVideoLoggerRendererFlush(&proxyRenderer->logger);
208	if (proxyRenderer->block) {
209		proxyRenderer->unlock(proxyRenderer);
210	}
211}
212
213static void GBAVideoProxyRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels) {
214	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
215	if (proxyRenderer->block) {
216		proxyRenderer->lock(proxyRenderer);
217		// Insert an extra item into the queue to make sure it gets flushed
218		mVideoLoggerRendererFlush(&proxyRenderer->logger);
219		proxyRenderer->wait(proxyRenderer);
220	}
221	proxyRenderer->backend->getPixels(proxyRenderer->backend, stride, pixels);
222	if (proxyRenderer->block) {
223		proxyRenderer->unlock(proxyRenderer);
224	}
225}
226
227static void GBAVideoProxyRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels) {
228	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
229	if (proxyRenderer->block) {
230		proxyRenderer->lock(proxyRenderer);
231		// Insert an extra item into the queue to make sure it gets flushed
232		mVideoLoggerRendererFlush(&proxyRenderer->logger);
233		proxyRenderer->wait(proxyRenderer);
234	}
235	proxyRenderer->backend->putPixels(proxyRenderer->backend, stride, pixels);
236	if (proxyRenderer->block) {
237		proxyRenderer->unlock(proxyRenderer);
238	}
239}