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