all repos — mgba @ d3019c306f77434d90dd13e70fff0f69f31dfee4

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