all repos — mgba @ 555122e0a1bc1311040e6ff7a8b2d95090fa76ca

mGBA Game Boy Advance Emulator

src/gba/extra/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/cache-set.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->parsePacket = _parsePacket;
 48	renderer->logger->vramBlock = _vramBlock;
 49	renderer->logger->paletteSize = SIZE_PALETTE_RAM;
 50	renderer->logger->vramSize = SIZE_VRAM;
 51	renderer->logger->oamSize = SIZE_OAM;
 52
 53	renderer->backend = backend;
 54}
 55
 56static void _init(struct GBAVideoProxyRenderer* proxyRenderer) {
 57	mVideoLoggerRendererInit(proxyRenderer->logger);
 58
 59	if (proxyRenderer->logger->block) {
 60		proxyRenderer->backend->palette = proxyRenderer->logger->palette;
 61		proxyRenderer->backend->vram = proxyRenderer->logger->vram;
 62		proxyRenderer->backend->oam = (union GBAOAM*) proxyRenderer->logger->oam;
 63		proxyRenderer->backend->cache = NULL;
 64	}
 65}
 66
 67static void _reset(struct GBAVideoProxyRenderer* proxyRenderer) {
 68	memcpy(proxyRenderer->logger->oam, &proxyRenderer->d.oam->raw, SIZE_OAM);
 69	memcpy(proxyRenderer->logger->palette, proxyRenderer->d.palette, SIZE_PALETTE_RAM);
 70	memcpy(proxyRenderer->logger->vram, proxyRenderer->d.vram, SIZE_VRAM);
 71
 72	mVideoLoggerRendererReset(proxyRenderer->logger);
 73}
 74
 75void GBAVideoProxyRendererShim(struct GBAVideo* video, struct GBAVideoProxyRenderer* renderer) {
 76	if ((renderer->backend && video->renderer != renderer->backend) || video->renderer == &renderer->d) {
 77		return;
 78	}
 79	renderer->backend = video->renderer;
 80	video->renderer = &renderer->d;
 81	renderer->d.cache = renderer->backend->cache;
 82	renderer->d.palette = video->palette;
 83	renderer->d.vram = video->vram;
 84	renderer->d.oam = &video->oam;
 85	_init(renderer);
 86	_reset(renderer);
 87}
 88
 89void GBAVideoProxyRendererUnshim(struct GBAVideo* video, struct GBAVideoProxyRenderer* renderer) {
 90	if (video->renderer != &renderer->d) {
 91		return;
 92	}
 93	renderer->backend->cache = video->renderer->cache;
 94	video->renderer = renderer->backend;
 95	renderer->backend->palette = video->palette;
 96	renderer->backend->vram = video->vram;
 97	renderer->backend->oam = &video->oam;
 98
 99	mVideoLoggerRendererDeinit(renderer->logger);
100}
101
102void GBAVideoProxyRendererInit(struct GBAVideoRenderer* renderer) {
103	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
104
105	_init(proxyRenderer);
106	_reset(proxyRenderer);
107
108	proxyRenderer->backend->init(proxyRenderer->backend);
109}
110
111void GBAVideoProxyRendererReset(struct GBAVideoRenderer* renderer) {
112	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
113
114	_reset(proxyRenderer);
115
116	proxyRenderer->backend->reset(proxyRenderer->backend);
117}
118
119void GBAVideoProxyRendererDeinit(struct GBAVideoRenderer* renderer) {
120	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
121
122	proxyRenderer->backend->deinit(proxyRenderer->backend);
123
124	mVideoLoggerRendererDeinit(proxyRenderer->logger);
125}
126
127static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerDirtyInfo* item) {
128	struct GBAVideoProxyRenderer* proxyRenderer = logger->context;
129	switch (item->type) {
130	case DIRTY_REGISTER:
131		proxyRenderer->backend->writeVideoRegister(proxyRenderer->backend, item->address, item->value);
132		break;
133	case DIRTY_PALETTE:
134		if (item->address < SIZE_PALETTE_RAM) {
135			logger->palette[item->address >> 1] = item->value;
136			proxyRenderer->backend->writePalette(proxyRenderer->backend, item->address, item->value);
137		}
138		break;
139	case DIRTY_OAM:
140		if (item->address < SIZE_PALETTE_RAM) {
141			logger->oam[item->address] = item->value;
142			proxyRenderer->backend->writeOAM(proxyRenderer->backend, item->address);
143		}
144		break;
145	case DIRTY_VRAM:
146		if (item->address <= SIZE_VRAM - 0x1000) {
147			logger->readData(logger, &logger->vram[item->address >> 1], 0x1000, true);
148			proxyRenderer->backend->writeVRAM(proxyRenderer->backend, item->address);
149		}
150		break;
151	case DIRTY_SCANLINE:
152		if (item->address < VIDEO_VERTICAL_PIXELS) {
153			proxyRenderer->backend->drawScanline(proxyRenderer->backend, item->address);
154		}
155		break;
156	case DIRTY_FRAME:
157		proxyRenderer->backend->finishFrame(proxyRenderer->backend);
158		break;
159	case DIRTY_FLUSH:
160		return false;
161	default:
162		return false;
163	}
164	return true;
165}
166
167static uint16_t* _vramBlock(struct mVideoLogger* logger, uint32_t address) {
168	struct GBAVideoProxyRenderer* proxyRenderer = logger->context;
169	return &proxyRenderer->d.vram[address >> 1];
170}
171
172uint16_t GBAVideoProxyRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
173	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
174	switch (address) {
175	case REG_DISPCNT:
176		value &= 0xFFF7;
177		break;
178	case REG_BG0CNT:
179	case REG_BG1CNT:
180		value &= 0xDFFF;
181		break;
182	case REG_BG2CNT:
183	case REG_BG3CNT:
184		value &= 0xFFFF;
185		break;
186	case REG_BG0HOFS:
187	case REG_BG0VOFS:
188	case REG_BG1HOFS:
189	case REG_BG1VOFS:
190	case REG_BG2HOFS:
191	case REG_BG2VOFS:
192	case REG_BG3HOFS:
193	case REG_BG3VOFS:
194		value &= 0x01FF;
195		break;
196	}
197	if (address > REG_BLDY) {
198		return value;
199	}
200
201	mVideoLoggerRendererWriteVideoRegister(proxyRenderer->logger, address, value);
202	if (!proxyRenderer->logger->block) {
203		proxyRenderer->backend->writeVideoRegister(proxyRenderer->backend, address, value);
204	}
205	return value;
206}
207
208void GBAVideoProxyRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) {
209	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
210	mVideoLoggerRendererWriteVRAM(proxyRenderer->logger, address);
211	if (!proxyRenderer->logger->block) {
212		proxyRenderer->backend->writeVRAM(proxyRenderer->backend, address);
213	}
214	if (renderer->cache) {
215		mCacheSetWriteVRAM(renderer->cache, address);
216	}
217}
218
219void GBAVideoProxyRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
220	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
221	mVideoLoggerRendererWritePalette(proxyRenderer->logger, address, value);
222	if (!proxyRenderer->logger->block) {
223		proxyRenderer->backend->writePalette(proxyRenderer->backend, address, value);
224	}
225	if (renderer->cache) {
226		mCacheSetWritePalette(renderer->cache, address >> 1, mColorFrom555(value));
227	}
228}
229
230void GBAVideoProxyRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam) {
231	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
232	if (!proxyRenderer->logger->block) {
233		proxyRenderer->backend->writeOAM(proxyRenderer->backend, oam);
234	}
235	mVideoLoggerRendererWriteOAM(proxyRenderer->logger, oam, proxyRenderer->d.oam->raw[oam]);
236}
237
238void GBAVideoProxyRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
239	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
240	if (!proxyRenderer->logger->block) {
241		proxyRenderer->backend->drawScanline(proxyRenderer->backend, y);
242	}
243	mVideoLoggerRendererDrawScanline(proxyRenderer->logger, y);
244	if (proxyRenderer->logger->block && proxyRenderer->logger->wake) {
245		proxyRenderer->logger->wake(proxyRenderer->logger, y);
246	}
247}
248
249void GBAVideoProxyRendererFinishFrame(struct GBAVideoRenderer* renderer) {
250	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
251	if (proxyRenderer->logger->block && proxyRenderer->logger->wait) {
252		proxyRenderer->logger->lock(proxyRenderer->logger);
253		proxyRenderer->logger->wait(proxyRenderer->logger);
254	}
255	proxyRenderer->backend->finishFrame(proxyRenderer->backend);
256	mVideoLoggerRendererFinishFrame(proxyRenderer->logger);
257	mVideoLoggerRendererFlush(proxyRenderer->logger);
258	if (proxyRenderer->logger->block && proxyRenderer->logger->wait) {
259		proxyRenderer->logger->unlock(proxyRenderer->logger);
260	}
261}
262
263static void GBAVideoProxyRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels) {
264	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
265	if (proxyRenderer->logger->block && proxyRenderer->logger->wait) {
266		proxyRenderer->logger->lock(proxyRenderer->logger);
267		// Insert an extra item into the queue to make sure it gets flushed
268		mVideoLoggerRendererFlush(proxyRenderer->logger);
269		proxyRenderer->logger->wait(proxyRenderer->logger);
270	}
271	proxyRenderer->backend->getPixels(proxyRenderer->backend, stride, pixels);
272	if (proxyRenderer->logger->block && proxyRenderer->logger->wait) {
273		proxyRenderer->logger->unlock(proxyRenderer->logger);
274	}
275}
276
277static void GBAVideoProxyRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels) {
278	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
279	if (proxyRenderer->logger->block && proxyRenderer->logger->wait) {
280		proxyRenderer->logger->lock(proxyRenderer->logger);
281		// Insert an extra item into the queue to make sure it gets flushed
282		mVideoLoggerRendererFlush(proxyRenderer->logger);
283		proxyRenderer->logger->wait(proxyRenderer->logger);
284	}
285	proxyRenderer->backend->putPixels(proxyRenderer->backend, stride, pixels);
286	if (proxyRenderer->logger->block && proxyRenderer->logger->wait) {
287		proxyRenderer->logger->unlock(proxyRenderer->logger);
288	}
289}