all repos — mgba @ 3ccffdc29eab88906a6cbb9d686f474261da4e16

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 void _handleEvent(struct mVideoLogger* logger, enum mVideoLoggerEvent event);
 25static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerDirtyInfo* packet);
 26static uint16_t* _vramBlock(struct mVideoLogger* logger, uint32_t address);
 27
 28void GBAVideoProxyRendererCreate(struct GBAVideoProxyRenderer* renderer, struct GBAVideoRenderer* backend) {
 29	renderer->d.init = GBAVideoProxyRendererInit;
 30	renderer->d.reset = GBAVideoProxyRendererReset;
 31	renderer->d.deinit = GBAVideoProxyRendererDeinit;
 32	renderer->d.writeVideoRegister = GBAVideoProxyRendererWriteVideoRegister;
 33	renderer->d.writeVRAM = GBAVideoProxyRendererWriteVRAM;
 34	renderer->d.writeOAM = GBAVideoProxyRendererWriteOAM;
 35	renderer->d.writePalette = GBAVideoProxyRendererWritePalette;
 36	renderer->d.drawScanline = GBAVideoProxyRendererDrawScanline;
 37	renderer->d.finishFrame = GBAVideoProxyRendererFinishFrame;
 38	renderer->d.getPixels = GBAVideoProxyRendererGetPixels;
 39	renderer->d.putPixels = GBAVideoProxyRendererPutPixels;
 40
 41	renderer->d.disableBG[0] = false;
 42	renderer->d.disableBG[1] = false;
 43	renderer->d.disableBG[2] = false;
 44	renderer->d.disableBG[3] = false;
 45	renderer->d.disableOBJ = false;
 46
 47	renderer->d.highlightBG[0] = false;
 48	renderer->d.highlightBG[1] = false;
 49	renderer->d.highlightBG[2] = false;
 50	renderer->d.highlightBG[3] = false;
 51	int i;
 52	for (i = 0; i < 128; ++i) {
 53		renderer->d.highlightOBJ[i] = false;
 54	}
 55	renderer->d.highlightColor = 0xFFFFFF;
 56	renderer->d.highlightAmount = 0;
 57
 58	renderer->logger->context = renderer;
 59	renderer->logger->parsePacket = _parsePacket;
 60	renderer->logger->handleEvent = _handleEvent;
 61	renderer->logger->vramBlock = _vramBlock;
 62	renderer->logger->paletteSize = SIZE_PALETTE_RAM;
 63	renderer->logger->vramSize = SIZE_VRAM;
 64	renderer->logger->oamSize = SIZE_OAM;
 65
 66	renderer->backend = backend;
 67}
 68
 69static void _init(struct GBAVideoProxyRenderer* proxyRenderer) {
 70	mVideoLoggerRendererInit(proxyRenderer->logger);
 71
 72	if (proxyRenderer->logger->block) {
 73		proxyRenderer->backend->palette = proxyRenderer->logger->palette;
 74		memset(proxyRenderer->backend->vramBG, 0, sizeof(proxyRenderer->backend->vramBG));
 75		proxyRenderer->backend->vramBG[0] = &proxyRenderer->logger->vram[0x0000];
 76		proxyRenderer->backend->vramBG[1] = &proxyRenderer->logger->vram[0x2000];
 77		proxyRenderer->backend->vramBG[2] = &proxyRenderer->logger->vram[0x4000];
 78		proxyRenderer->backend->vramBG[3] = &proxyRenderer->logger->vram[0x6000];
 79		memset(proxyRenderer->backend->vramOBJ, 0, sizeof(proxyRenderer->backend->vramOBJ));
 80		proxyRenderer->backend->vramOBJ[0] = &proxyRenderer->logger->vram[0x8000];
 81		proxyRenderer->backend->vramOBJ[1] = &proxyRenderer->logger->vram[0xA000];
 82		proxyRenderer->backend->oam = (union GBAOAM*) proxyRenderer->logger->oam;
 83		proxyRenderer->backend->cache = NULL;
 84	}
 85}
 86
 87static void _reset(struct GBAVideoProxyRenderer* proxyRenderer) {
 88	memcpy(proxyRenderer->logger->oam, &proxyRenderer->d.oam->raw, SIZE_OAM);
 89	memcpy(proxyRenderer->logger->palette, proxyRenderer->d.palette, SIZE_PALETTE_RAM);
 90	memcpy(&proxyRenderer->logger->vram[0x0000], proxyRenderer->d.vramBG[0], 0x4000);
 91	memcpy(&proxyRenderer->logger->vram[0x2000], proxyRenderer->d.vramBG[1], 0x4000);
 92	memcpy(&proxyRenderer->logger->vram[0x4000], proxyRenderer->d.vramBG[2], 0x4000);
 93	memcpy(&proxyRenderer->logger->vram[0x6000], proxyRenderer->d.vramBG[3], 0x4000);
 94	memcpy(&proxyRenderer->logger->vram[0x8000], proxyRenderer->d.vramOBJ[0], 0x4000);
 95	memcpy(&proxyRenderer->logger->vram[0xA000], proxyRenderer->d.vramOBJ[1], 0x4000);
 96
 97	mVideoLoggerRendererReset(proxyRenderer->logger);
 98}
 99
100void GBAVideoProxyRendererShim(struct GBAVideo* video, struct GBAVideoProxyRenderer* renderer) {
101	if ((renderer->backend && video->renderer != renderer->backend) || video->renderer == &renderer->d) {
102		return;
103	}
104	renderer->backend = video->renderer;
105	video->renderer = &renderer->d;
106	renderer->d.cache = renderer->backend->cache;
107	renderer->d.palette = video->palette;
108	memcpy(renderer->d.vramBG, renderer->backend->vramBG, sizeof(renderer->backend->vramBG));
109	memcpy(renderer->d.vramOBJ, renderer->backend->vramOBJ, sizeof(renderer->backend->vramOBJ));
110	renderer->d.oam = &video->oam;
111	_init(renderer);
112	_reset(renderer);
113}
114
115void GBAVideoProxyRendererUnshim(struct GBAVideo* video, struct GBAVideoProxyRenderer* renderer) {
116	if (video->renderer != &renderer->d) {
117		return;
118	}
119	renderer->backend->cache = video->renderer->cache;
120	video->renderer = renderer->backend;
121	renderer->backend->palette = video->palette;
122	memcpy(renderer->backend->vramBG, renderer->d.vramBG, sizeof(renderer->backend->vramBG));
123	memcpy(renderer->backend->vramOBJ, renderer->d.vramOBJ, sizeof(renderer->backend->vramOBJ));
124	renderer->backend->oam = &video->oam;
125
126	mVideoLoggerRendererDeinit(renderer->logger);
127}
128
129void GBAVideoProxyRendererInit(struct GBAVideoRenderer* renderer) {
130	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
131
132	_init(proxyRenderer);
133	_reset(proxyRenderer);
134
135	if (!proxyRenderer->logger->block) {
136		proxyRenderer->backend->init(proxyRenderer->backend);
137	} else {
138		proxyRenderer->logger->postEvent(proxyRenderer->logger, LOGGER_EVENT_INIT);
139	}
140}
141
142void GBAVideoProxyRendererReset(struct GBAVideoRenderer* renderer) {
143	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
144
145	_reset(proxyRenderer);
146
147	if (!proxyRenderer->logger->block) {
148		proxyRenderer->backend->reset(proxyRenderer->backend);
149	} else {
150		proxyRenderer->logger->postEvent(proxyRenderer->logger, LOGGER_EVENT_RESET);
151	}
152}
153
154void GBAVideoProxyRendererDeinit(struct GBAVideoRenderer* renderer) {
155	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
156
157	if (!proxyRenderer->logger->block) {
158		proxyRenderer->backend->deinit(proxyRenderer->backend);
159	} else {
160		mVideoLoggerRendererFlush(proxyRenderer->logger);
161		proxyRenderer->logger->postEvent(proxyRenderer->logger, LOGGER_EVENT_DEINIT);
162	}
163
164	mVideoLoggerRendererDeinit(proxyRenderer->logger);
165}
166
167static void _handleEvent(struct mVideoLogger* logger, enum mVideoLoggerEvent event) {
168	struct GBAVideoProxyRenderer* proxyRenderer = logger->context;
169	switch (event) {
170	default:
171		break;
172	case LOGGER_EVENT_INIT:
173		proxyRenderer->backend->init(proxyRenderer->backend);
174		break;
175	case LOGGER_EVENT_DEINIT:
176		proxyRenderer->backend->deinit(proxyRenderer->backend);
177		break;
178	case LOGGER_EVENT_RESET:
179		proxyRenderer->backend->reset(proxyRenderer->backend);
180		break;
181	case LOGGER_EVENT_GET_PIXELS:
182		proxyRenderer->backend->getPixels(proxyRenderer->backend, &logger->pixelStride, &logger->pixelBuffer);
183		break;
184	}
185}
186
187static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerDirtyInfo* item) {
188	struct GBAVideoProxyRenderer* proxyRenderer = logger->context;
189	switch (item->type) {
190	case DIRTY_REGISTER:
191		proxyRenderer->backend->writeVideoRegister(proxyRenderer->backend, item->address, item->value);
192		break;
193	case DIRTY_PALETTE:
194		if (item->address < SIZE_PALETTE_RAM) {
195			logger->palette[item->address >> 1] = item->value;
196			proxyRenderer->backend->writePalette(proxyRenderer->backend, item->address, item->value);
197		}
198		break;
199	case DIRTY_OAM:
200		if (item->address < SIZE_OAM) {
201			logger->oam[item->address] = item->value;
202			proxyRenderer->backend->writeOAM(proxyRenderer->backend, item->address);
203		}
204		break;
205	case DIRTY_VRAM:
206		if (item->address <= SIZE_VRAM - 0x1000) {
207			logger->readData(logger, &logger->vram[item->address >> 1], 0x1000, true);
208			proxyRenderer->backend->writeVRAM(proxyRenderer->backend, item->address);
209		} else {
210			logger->readData(logger, NULL, 0x1000, true);
211		}
212		break;
213	case DIRTY_SCANLINE:
214		proxyRenderer->backend->disableBG[0] = proxyRenderer->d.disableBG[0];
215		proxyRenderer->backend->disableBG[1] = proxyRenderer->d.disableBG[1];
216		proxyRenderer->backend->disableBG[2] = proxyRenderer->d.disableBG[2];
217		proxyRenderer->backend->disableBG[3] = proxyRenderer->d.disableBG[3];
218		proxyRenderer->backend->disableOBJ = proxyRenderer->d.disableOBJ;
219		proxyRenderer->backend->highlightBG[0] = proxyRenderer->d.highlightBG[0];
220		proxyRenderer->backend->highlightBG[1] = proxyRenderer->d.highlightBG[1];
221		proxyRenderer->backend->highlightBG[2] = proxyRenderer->d.highlightBG[2];
222		proxyRenderer->backend->highlightBG[3] = proxyRenderer->d.highlightBG[3];
223		memcpy(proxyRenderer->backend->highlightOBJ, proxyRenderer->d.highlightOBJ, sizeof(proxyRenderer->backend->highlightOBJ));
224		proxyRenderer->backend->highlightAmount = proxyRenderer->d.highlightAmount;
225		if (item->address < GBA_VIDEO_VERTICAL_PIXELS) {
226			proxyRenderer->backend->drawScanline(proxyRenderer->backend, item->address);
227		}
228		break;
229	case DIRTY_FRAME:
230		proxyRenderer->backend->finishFrame(proxyRenderer->backend);
231		break;
232	case DIRTY_FLUSH:
233		return false;
234	default:
235		return false;
236	}
237	return true;
238}
239
240static uint16_t* _vramBlock(struct mVideoLogger* logger, uint32_t address) {
241	struct GBAVideoProxyRenderer* proxyRenderer = logger->context;
242	if (address < 0x10000) {
243		return &proxyRenderer->d.vramBG[address >> VRAM_BLOCK_OFFSET][(address & VRAM_BLOCK_MASK) >> 1];
244	} else {
245		return &proxyRenderer->d.vramOBJ[(address & 0x7FFF) >> VRAM_BLOCK_OFFSET][(address & VRAM_BLOCK_MASK) >> 1];
246	}
247}
248
249uint16_t GBAVideoProxyRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
250	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
251	switch (address) {
252	case REG_DISPCNT:
253		value &= 0xFFF7;
254		break;
255	case REG_BG0CNT:
256	case REG_BG1CNT:
257		value &= 0xDFFF;
258		break;
259	case REG_BG2CNT:
260	case REG_BG3CNT:
261		value &= 0xFFFF;
262		break;
263	case REG_BG0HOFS:
264	case REG_BG0VOFS:
265	case REG_BG1HOFS:
266	case REG_BG1VOFS:
267	case REG_BG2HOFS:
268	case REG_BG2VOFS:
269	case REG_BG3HOFS:
270	case REG_BG3VOFS:
271		value &= 0x01FF;
272		break;
273	}
274	if (address > REG_BLDY) {
275		return value;
276	}
277
278	mVideoLoggerRendererWriteVideoRegister(proxyRenderer->logger, address, value);
279	if (!proxyRenderer->logger->block) {
280		proxyRenderer->backend->writeVideoRegister(proxyRenderer->backend, address, value);
281	}
282	return value;
283}
284
285void GBAVideoProxyRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) {
286	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
287	mVideoLoggerRendererWriteVRAM(proxyRenderer->logger, address);
288	if (!proxyRenderer->logger->block) {
289		proxyRenderer->backend->writeVRAM(proxyRenderer->backend, address);
290	}
291	if (renderer->cache) {
292		mCacheSetWriteVRAM(renderer->cache, address);
293	}
294}
295
296void GBAVideoProxyRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
297	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
298	mVideoLoggerRendererWritePalette(proxyRenderer->logger, address, value);
299	if (!proxyRenderer->logger->block) {
300		proxyRenderer->backend->writePalette(proxyRenderer->backend, address, value);
301	}
302	if (renderer->cache) {
303		mCacheSetWritePalette(renderer->cache, address >> 1, mColorFrom555(value));
304	}
305}
306
307void GBAVideoProxyRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam) {
308	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
309	if (!proxyRenderer->logger->block) {
310		proxyRenderer->backend->writeOAM(proxyRenderer->backend, oam);
311	}
312	mVideoLoggerRendererWriteOAM(proxyRenderer->logger, oam, proxyRenderer->d.oam->raw[oam]);
313}
314
315void GBAVideoProxyRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
316	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
317	if (!proxyRenderer->logger->block) {
318		proxyRenderer->backend->drawScanline(proxyRenderer->backend, y);
319	}
320	mVideoLoggerRendererDrawScanline(proxyRenderer->logger, y);
321	if (proxyRenderer->logger->block && proxyRenderer->logger->wake) {
322		proxyRenderer->logger->wake(proxyRenderer->logger, y);
323	}
324}
325
326void GBAVideoProxyRendererFinishFrame(struct GBAVideoRenderer* renderer) {
327	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
328	if (!proxyRenderer->logger->block) {
329		proxyRenderer->backend->finishFrame(proxyRenderer->backend);
330	}
331	mVideoLoggerRendererFinishFrame(proxyRenderer->logger);
332	mVideoLoggerRendererFlush(proxyRenderer->logger);
333}
334
335static void GBAVideoProxyRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels) {
336	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
337	if (proxyRenderer->logger->block && proxyRenderer->logger->wait) {
338		// Insert an extra item into the queue to make sure it gets flushed
339		mVideoLoggerRendererFlush(proxyRenderer->logger);
340		proxyRenderer->logger->postEvent(proxyRenderer->logger, LOGGER_EVENT_GET_PIXELS);
341		mVideoLoggerRendererFlush(proxyRenderer->logger);
342		*pixels = proxyRenderer->logger->pixelBuffer;
343		*stride = proxyRenderer->logger->pixelStride;
344	} else {
345		proxyRenderer->backend->getPixels(proxyRenderer->backend, stride, pixels);
346	}
347}
348
349static void GBAVideoProxyRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels) {
350	struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
351	if (proxyRenderer->logger->block && proxyRenderer->logger->wait) {
352		proxyRenderer->logger->lock(proxyRenderer->logger);
353	}
354	proxyRenderer->backend->putPixels(proxyRenderer->backend, stride, pixels);
355	if (proxyRenderer->logger->block && proxyRenderer->logger->wait) {
356		proxyRenderer->logger->unlock(proxyRenderer->logger);
357	}
358}