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}