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}