src/ds/video.c (view raw)
1/* Copyright (c) 2013-2015 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/ds/video.h>
7
8#include <mgba/core/sync.h>
9#include <mgba/internal/ds/ds.h>
10#include <mgba/internal/ds/memory.h>
11#include <mgba/internal/gba/video.h>
12
13#include <mgba-util/memory.h>
14
15mLOG_DEFINE_CATEGORY(DS_VIDEO, "DS Video");
16
17static void DSVideoDummyRendererInit(struct DSVideoRenderer* renderer);
18static void DSVideoDummyRendererReset(struct DSVideoRenderer* renderer);
19static void DSVideoDummyRendererDeinit(struct DSVideoRenderer* renderer);
20static uint16_t DSVideoDummyRendererWriteVideoRegister(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value);
21static void DSVideoDummyRendererWritePalette(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value);
22static void DSVideoDummyRendererWriteOAM(struct DSVideoRenderer* renderer, uint32_t oam);
23static void DSVideoDummyRendererInvalidateExtPal(struct DSVideoRenderer* renderer, bool obj, bool engB, int slot);
24static void DSVideoDummyRendererDrawScanline(struct DSVideoRenderer* renderer, int y);
25static void DSVideoDummyRendererFinishFrame(struct DSVideoRenderer* renderer);
26static void DSVideoDummyRendererGetPixels(struct DSVideoRenderer* renderer, size_t* stride, const void** pixels);
27static void DSVideoDummyRendererPutPixels(struct DSVideoRenderer* renderer, size_t stride, const void* pixels);
28
29static void _startHblank7(struct mTiming*, void* context, uint32_t cyclesLate);
30static void _startHdraw7(struct mTiming*, void* context, uint32_t cyclesLate);
31static void _startHblank9(struct mTiming*, void* context, uint32_t cyclesLate);
32static void _startHdraw9(struct mTiming*, void* context, uint32_t cyclesLate);
33
34static const uint32_t _vramSize[9] = {
35 0x20000,
36 0x20000,
37 0x20000,
38 0x20000,
39 0x10000,
40 0x04000,
41 0x04000,
42 0x08000,
43 0x04000
44};
45
46enum DSVRAMBankMode {
47 MODE_A_BG = 0,
48 MODE_B_BG = 1,
49 MODE_A_OBJ = 2,
50 MODE_B_OBJ = 3,
51 MODE_LCDC,
52 MODE_7_VRAM,
53 MODE_A_BG_EXT_PAL,
54 MODE_B_BG_EXT_PAL,
55 MODE_A_OBJ_EXT_PAL,
56 MODE_B_OBJ_EXT_PAL,
57 MODE_3D_TEX,
58 MODE_3D_TEX_PAL,
59};
60
61const struct DSVRAMBankInfo {
62 int base;
63 uint32_t mirrorSize;
64 enum DSVRAMBankMode mode;
65 int offset[4];
66} _vramInfo[9][8] = {
67 { // A
68 { 0x000, 0x40, MODE_LCDC },
69 { 0x000, 0x20, MODE_A_BG, { 0x00, 0x08, 0x10, 0x18 } },
70 { 0x000, 0x10, MODE_A_OBJ, { 0x00, 0x08, 0x80, 0x80 } },
71 { 0x000, 0x01, MODE_3D_TEX, { 0x00, 0x01, 0x02, 0x03 } },
72 },
73 { // B
74 { 0x008, 0x40, MODE_LCDC },
75 { 0x000, 0x20, MODE_A_BG, { 0x00, 0x08, 0x10, 0x18 } },
76 { 0x000, 0x10, MODE_A_OBJ, { 0x00, 0x08, 0x80, 0x80 } },
77 { 0x000, 0x01, MODE_3D_TEX, { 0x00, 0x01, 0x02, 0x03 } },
78 },
79 { // C
80 { 0x010, 0x40, MODE_LCDC },
81 { 0x000, 0x20, MODE_A_BG, { 0x00, 0x08, 0x10, 0x18 } },
82 { 0x000, 0x40, MODE_7_VRAM, { 0x00, 0x08, 0x80, 0x80 } },
83 { 0x000, 0x01, MODE_3D_TEX, { 0x00, 0x01, 0x02, 0x03 } },
84 { 0x000, 0x08, MODE_B_BG },
85 },
86 { // D
87 { 0x018, 0x40, MODE_LCDC },
88 { 0x000, 0x20, MODE_A_BG, { 0x00, 0x08, 0x10, 0x18 } },
89 { 0x000, 0x40, MODE_7_VRAM, { 0x00, 0x08, 0x80, 0x80 } },
90 { 0x000, 0x01, MODE_3D_TEX, { 0x00, 0x01, 0x02, 0x03 } },
91 { 0x000, 0x08, MODE_B_OBJ },
92 },
93 { // E
94 { 0x020, 0x40, MODE_LCDC },
95 { 0x000, 0x20, MODE_A_BG },
96 { 0x000, 0x10, MODE_A_OBJ },
97 { 0x000, 0x04, MODE_3D_TEX_PAL },
98 { 0x000, 0x04, MODE_A_BG_EXT_PAL },
99 },
100 { // F
101 { 0x024, 0x40, MODE_LCDC },
102 { 0x000, 0x20, MODE_A_BG, { 0x00, 0x01, 0x04, 0x05 } },
103 { 0x000, 0x10, MODE_A_OBJ, { 0x00, 0x01, 0x04, 0x05 } },
104 { 0x000, 0x01, MODE_3D_TEX_PAL, { 0x00, 0x01, 0x04, 0x05 } },
105 { 0x000, 0x02, MODE_A_BG_EXT_PAL, { 0x00, 0x02, 0x00, 0x02 } },
106 { 0x000, 0x01, MODE_A_OBJ_EXT_PAL},
107 },
108 { // G
109 { 0x025, 0x40, MODE_LCDC },
110 { 0x000, 0x20, MODE_A_BG, { 0x00, 0x01, 0x04, 0x05 } },
111 { 0x000, 0x10, MODE_A_OBJ, { 0x00, 0x01, 0x04, 0x05 } },
112 { 0x000, 0x01, MODE_3D_TEX_PAL, { 0x00, 0x01, 0x04, 0x05 } },
113 { 0x000, 0x02, MODE_A_BG_EXT_PAL, { 0x00, 0x02, 0x00, 0x02 } },
114 { 0x000, 0x01, MODE_A_OBJ_EXT_PAL},
115 },
116 { // H
117 { 0x026, 0x40, MODE_LCDC },
118 { 0x000, 0x04, MODE_B_BG },
119 { 0x000, 0x04, MODE_B_BG_EXT_PAL },
120 },
121 { // I
122 { 0x028, 0x40, MODE_LCDC },
123 { 0x002, 0x04, MODE_B_BG },
124 { 0x000, 0x01, MODE_B_OBJ },
125 { 0x000, 0x01, MODE_B_OBJ_EXT_PAL },
126 },
127};
128
129static struct DSVideoRenderer dummyRenderer = {
130 .init = DSVideoDummyRendererInit,
131 .reset = DSVideoDummyRendererReset,
132 .deinit = DSVideoDummyRendererDeinit,
133 .writeVideoRegister = DSVideoDummyRendererWriteVideoRegister,
134 .writePalette = DSVideoDummyRendererWritePalette,
135 .writeOAM = DSVideoDummyRendererWriteOAM,
136 .invalidateExtPal = DSVideoDummyRendererInvalidateExtPal,
137 .drawScanline = DSVideoDummyRendererDrawScanline,
138 .finishFrame = DSVideoDummyRendererFinishFrame,
139 .getPixels = DSVideoDummyRendererGetPixels,
140 .putPixels = DSVideoDummyRendererPutPixels,
141};
142
143void DSVideoInit(struct DSVideo* video) {
144 video->renderer = &dummyRenderer;
145 video->vram = NULL;
146 video->frameskip = 0;
147 video->event7.name = "DS7 Video";
148 video->event7.callback = NULL;
149 video->event7.context = video;
150 video->event7.priority = 8;
151 video->event9.name = "DS9 Video";
152 video->event9.callback = NULL;
153 video->event9.context = video;
154 video->event9.priority = 8;
155}
156
157void DSVideoReset(struct DSVideo* video) {
158 video->vcount = 0;
159 video->p->ds7.memory.io[DS_REG_VCOUNT >> 1] = video->vcount;
160 video->p->ds9.memory.io[DS_REG_VCOUNT >> 1] = video->vcount;
161
162 video->event7.callback = _startHblank7;
163 video->event9.callback = _startHblank9;
164 mTimingSchedule(&video->p->ds7.timing, &video->event7, DS_VIDEO_HORIZONTAL_LENGTH - DS7_VIDEO_HBLANK_LENGTH);
165 mTimingSchedule(&video->p->ds9.timing, &video->event9, (DS_VIDEO_HORIZONTAL_LENGTH - DS9_VIDEO_HBLANK_LENGTH) * 2);
166
167 video->frameCounter = 0;
168 video->frameskipCounter = 0;
169
170 if (video->vram) {
171 mappedMemoryFree(video->vram, DS_SIZE_VRAM);
172 }
173 video->vram = anonymousMemoryMap(DS_SIZE_VRAM);
174 video->renderer->vram = video->vram;
175
176 video->p->memory.vramBank[0] = &video->vram[0x00000];
177 video->p->memory.vramBank[1] = &video->vram[0x10000];
178 video->p->memory.vramBank[2] = &video->vram[0x20000];
179 video->p->memory.vramBank[3] = &video->vram[0x30000];
180 video->p->memory.vramBank[4] = &video->vram[0x40000];
181 video->p->memory.vramBank[5] = &video->vram[0x48000];
182 video->p->memory.vramBank[6] = &video->vram[0x4A000];
183 video->p->memory.vramBank[7] = &video->vram[0x4C000];
184 video->p->memory.vramBank[8] = &video->vram[0x50000];
185
186 video->renderer->deinit(video->renderer);
187 video->renderer->init(video->renderer);
188}
189
190void DSVideoAssociateRenderer(struct DSVideo* video, struct DSVideoRenderer* renderer) {
191 video->renderer->deinit(video->renderer);
192 video->renderer = renderer;
193 renderer->palette = video->palette;
194 renderer->vram = video->vram;
195 memcpy(renderer->vramABG, video->vramABG, sizeof(renderer->vramABG));
196 memcpy(renderer->vramAOBJ, video->vramAOBJ, sizeof(renderer->vramAOBJ));
197 memcpy(renderer->vramABGExtPal, video->vramABGExtPal, sizeof(renderer->vramABGExtPal));
198 renderer->vramAOBJExtPal = video->vramAOBJExtPal;
199 memcpy(renderer->vramBBG, video->vramBBG, sizeof(renderer->vramBBG));
200 memcpy(renderer->vramBOBJ, video->vramBOBJ, sizeof(renderer->vramBOBJ));
201 memcpy(renderer->vramBBGExtPal, video->vramBBGExtPal, sizeof(renderer->vramBBGExtPal));
202 renderer->vramBOBJExtPal = video->vramBOBJExtPal;
203 renderer->oam = &video->oam;
204 renderer->gx = &video->p->gx;
205 video->renderer->init(video->renderer);
206}
207
208void DSVideoDeinit(struct DSVideo* video) {
209 DSVideoAssociateRenderer(video, &dummyRenderer);
210 mappedMemoryFree(video->vram, DS_SIZE_VRAM);
211}
212
213void _startHdraw7(struct mTiming* timing, void* context, uint32_t cyclesLate) {
214 struct DSVideo* video = context;
215 GBARegisterDISPSTAT dispstat = video->p->ds7.memory.io[DS_REG_DISPSTAT >> 1];
216 dispstat = GBARegisterDISPSTATClearInHblank(dispstat);
217 video->event7.callback = _startHblank7;
218 mTimingSchedule(timing, &video->event7, DS_VIDEO_HORIZONTAL_LENGTH - DS7_VIDEO_HBLANK_LENGTH - cyclesLate);
219
220 video->p->ds7.memory.io[DS_REG_VCOUNT >> 1] = video->vcount;
221
222 if (video->vcount == GBARegisterDISPSTATGetVcountSetting(dispstat)) {
223 dispstat = GBARegisterDISPSTATFillVcounter(dispstat);
224 if (GBARegisterDISPSTATIsVcounterIRQ(dispstat)) {
225 DSRaiseIRQ(video->p->ds7.cpu, video->p->ds7.memory.io, DS_IRQ_VCOUNTER);
226 }
227 } else {
228 dispstat = GBARegisterDISPSTATClearVcounter(dispstat);
229 }
230 video->p->ds7.memory.io[DS_REG_DISPSTAT >> 1] = dispstat;
231
232 switch (video->vcount) {
233 case DS_VIDEO_VERTICAL_PIXELS:
234 video->p->ds7.memory.io[DS_REG_DISPSTAT >> 1] = GBARegisterDISPSTATFillInVblank(dispstat);
235 if (GBARegisterDISPSTATIsVblankIRQ(dispstat)) {
236 DSRaiseIRQ(video->p->ds7.cpu, video->p->ds7.memory.io, DS_IRQ_VBLANK);
237 }
238 break;
239 case DS_VIDEO_VERTICAL_TOTAL_PIXELS - 1:
240 video->p->ds7.memory.io[DS_REG_DISPSTAT >> 1] = GBARegisterDISPSTATClearInVblank(dispstat);
241 break;
242 }
243}
244
245void _startHblank7(struct mTiming* timing, void* context, uint32_t cyclesLate) {
246 struct DSVideo* video = context;
247 GBARegisterDISPSTAT dispstat = video->p->ds7.memory.io[DS_REG_DISPSTAT >> 1];
248 dispstat = GBARegisterDISPSTATFillInHblank(dispstat);
249 video->event7.callback = _startHdraw7;
250 mTimingSchedule(timing, &video->event7, DS7_VIDEO_HBLANK_LENGTH - cyclesLate);
251
252 // Begin Hblank
253 dispstat = GBARegisterDISPSTATFillInHblank(dispstat);
254
255 if (GBARegisterDISPSTATIsHblankIRQ(dispstat)) {
256 DSRaiseIRQ(video->p->ds7.cpu, video->p->ds7.memory.io, DS_IRQ_HBLANK);
257 }
258 video->p->ds7.memory.io[DS_REG_DISPSTAT >> 1] = dispstat;
259}
260
261void _startHdraw9(struct mTiming* timing, void* context, uint32_t cyclesLate) {
262 struct DSVideo* video = context;
263 GBARegisterDISPSTAT dispstat = video->p->ds9.memory.io[DS_REG_DISPSTAT >> 1];
264 dispstat = GBARegisterDISPSTATClearInHblank(dispstat);
265 video->event9.callback = _startHblank9;
266 mTimingSchedule(timing, &video->event9, (DS_VIDEO_HORIZONTAL_LENGTH - DS9_VIDEO_HBLANK_LENGTH) * 2 - cyclesLate);
267
268 ++video->vcount;
269 if (video->vcount == DS_VIDEO_VERTICAL_TOTAL_PIXELS) {
270 video->vcount = 0;
271 }
272 video->p->ds9.memory.io[DS_REG_VCOUNT >> 1] = video->vcount;
273
274 if (video->vcount == GBARegisterDISPSTATGetVcountSetting(dispstat)) {
275 dispstat = GBARegisterDISPSTATFillVcounter(dispstat);
276 if (GBARegisterDISPSTATIsVcounterIRQ(dispstat)) {
277 DSRaiseIRQ(video->p->ds9.cpu, video->p->ds9.memory.io, DS_IRQ_VCOUNTER);
278 }
279 } else {
280 dispstat = GBARegisterDISPSTATClearVcounter(dispstat);
281 }
282 video->p->ds9.memory.io[DS_REG_DISPSTAT >> 1] = dispstat;
283
284 // Note: state may be recorded during callbacks, so ensure it is consistent!
285 switch (video->vcount) {
286 case 0:
287 DSFrameStarted(video->p);
288 break;
289 case DS_VIDEO_VERTICAL_PIXELS:
290 video->p->ds9.memory.io[DS_REG_DISPSTAT >> 1] = GBARegisterDISPSTATFillInVblank(dispstat);
291 if (video->frameskipCounter <= 0) {
292 video->renderer->finishFrame(video->renderer);
293 DSGXFlush(&video->p->gx);
294 }
295 if (GBARegisterDISPSTATIsVblankIRQ(dispstat)) {
296 DSRaiseIRQ(video->p->ds9.cpu, video->p->ds9.memory.io, DS_IRQ_VBLANK);
297 }
298 DSFrameEnded(video->p);
299 --video->frameskipCounter;
300 if (video->frameskipCounter < 0) {
301 mCoreSyncPostFrame(video->p->sync);
302 video->frameskipCounter = video->frameskip;
303 }
304 ++video->frameCounter;
305 break;
306 case DS_VIDEO_VERTICAL_TOTAL_PIXELS - 1:
307 video->p->ds9.memory.io[DS_REG_DISPSTAT >> 1] = GBARegisterDISPSTATClearInVblank(dispstat);
308 break;
309 }
310}
311
312void _startHblank9(struct mTiming* timing, void* context, uint32_t cyclesLate) {
313 struct DSVideo* video = context;
314 GBARegisterDISPSTAT dispstat = video->p->ds9.memory.io[DS_REG_DISPSTAT >> 1];
315 dispstat = GBARegisterDISPSTATFillInHblank(dispstat);
316 video->event9.callback = _startHdraw9;
317 mTimingSchedule(timing, &video->event9, (DS9_VIDEO_HBLANK_LENGTH * 2) - cyclesLate);
318
319 // Begin Hblank
320 dispstat = GBARegisterDISPSTATFillInHblank(dispstat);
321 if (video->frameskipCounter <= 0) {
322 if (video->vcount < DS_VIDEO_VERTICAL_PIXELS) {
323 video->renderer->drawScanline(video->renderer, video->vcount);
324 }
325 if (video->vcount < DS_VIDEO_VERTICAL_PIXELS - 48) {
326 video->p->gx.renderer->drawScanline(video->p->gx.renderer, video->vcount + 48);
327 }
328 if (video->vcount >= DS_VIDEO_VERTICAL_TOTAL_PIXELS - 48) {
329 video->p->gx.renderer->drawScanline(video->p->gx.renderer, video->vcount + 48 - DS_VIDEO_VERTICAL_TOTAL_PIXELS);
330 }
331 }
332
333 if (GBARegisterDISPSTATIsHblankIRQ(dispstat)) {
334 DSRaiseIRQ(video->p->ds9.cpu, video->p->ds9.memory.io, DS_IRQ_HBLANK);
335 }
336 video->p->ds9.memory.io[DS_REG_DISPSTAT >> 1] = dispstat;
337}
338
339void DSVideoWriteDISPSTAT(struct DSCommon* dscore, uint16_t value) {
340 dscore->memory.io[DS_REG_DISPSTAT >> 1] &= 0x7;
341 dscore->memory.io[DS_REG_DISPSTAT >> 1] |= value;
342 // TODO: Does a VCounter IRQ trigger on write?
343}
344
345void DSVideoConfigureVRAM(struct DS* ds, int index, uint8_t value, uint8_t oldValue) {
346 struct DSMemory* memory = &ds->memory;
347 if (value == oldValue) {
348 return;
349 }
350 uint32_t i, j;
351 uint32_t size = _vramSize[index] >> DS_VRAM_OFFSET;
352 struct DSVRAMBankInfo oldInfo = _vramInfo[index][oldValue & 0x7];
353 uint32_t offset = oldInfo.base + oldInfo.offset[(oldValue >> 3) & 3];
354 switch (oldInfo.mode) {
355 case MODE_A_BG:
356 for (i = 0; i < size; ++i) {
357 if (ds->video.vramABG[offset + i] == &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)]) {
358 ds->video.vramABG[offset + i] = NULL;
359 ds->video.renderer->vramABG[offset + i] = NULL;
360 }
361 }
362 break;
363 case MODE_B_BG:
364 for (i = 0; i < size; ++i) {
365 if (ds->video.vramBBG[offset + i] == &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)]) {
366 ds->video.vramBBG[offset + i] = NULL;
367 ds->video.renderer->vramBBG[offset + i] = NULL;
368 }
369 }
370 break;
371 case MODE_A_OBJ:
372 for (i = 0; i < size; ++i) {
373 if (ds->video.vramAOBJ[offset + i] == &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)]) {
374 ds->video.vramAOBJ[offset + i] = NULL;
375 ds->video.renderer->vramAOBJ[offset + i] = NULL;
376 }
377 }
378 break;
379 case MODE_B_OBJ:
380 for (i = 0; i < size; ++i) {
381 if (ds->video.vramBOBJ[offset + i] == &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)]) {
382 ds->video.vramBOBJ[offset + i] = NULL;
383 ds->video.renderer->vramBOBJ[offset + i] = NULL;
384 }
385 }
386 break;
387 case MODE_A_BG_EXT_PAL:
388 for (i = 0; i < oldInfo.mirrorSize; ++i) {
389 if (ds->video.vramABGExtPal[offset + i] == &memory->vramBank[index][i << 12]) {
390 ds->video.vramABGExtPal[offset + i] = NULL;
391 ds->video.renderer->vramABGExtPal[offset + i] = NULL;
392 ds->video.renderer->invalidateExtPal(ds->video.renderer, false, false, offset + i);
393 }
394 }
395 break;
396 case MODE_B_BG_EXT_PAL:
397 for (i = 0; i < oldInfo.mirrorSize; ++i) {
398 if (ds->video.vramBBGExtPal[offset + i] == &memory->vramBank[index][i << 12]) {
399 ds->video.vramBBGExtPal[offset + i] = NULL;
400 ds->video.renderer->vramBBGExtPal[offset + i] = NULL;
401 ds->video.renderer->invalidateExtPal(ds->video.renderer, false, true, offset + i);
402 }
403 }
404 break;
405 case MODE_A_OBJ_EXT_PAL:
406 if (ds->video.vramAOBJExtPal == memory->vramBank[index]) {
407 ds->video.vramAOBJExtPal = NULL;
408 ds->video.renderer->vramAOBJExtPal = NULL;
409 ds->video.renderer->invalidateExtPal(ds->video.renderer, true, false, 0);
410 }
411 break;
412 case MODE_B_OBJ_EXT_PAL:
413 if (ds->video.vramBOBJExtPal == memory->vramBank[index]) {
414 ds->video.vramBOBJExtPal = NULL;
415 ds->video.renderer->vramBOBJExtPal = NULL;
416 ds->video.renderer->invalidateExtPal(ds->video.renderer, true, true, 0);
417 }
418 break;
419 case MODE_3D_TEX:
420 if (ds->gx.tex[offset] == memory->vramBank[index]) {
421 ds->gx.tex[offset] = NULL;
422 ds->gx.renderer->tex[offset] = NULL;
423 ds->gx.renderer->invalidateTex(ds->gx.renderer, offset);
424 }
425 break;
426 case MODE_3D_TEX_PAL:
427 for (i = 0; i < oldInfo.mirrorSize; ++i) {
428 if (ds->gx.texPal[offset + i] == &memory->vramBank[index][i << 13]) {
429 ds->gx.texPal[offset + i] = NULL;
430 ds->gx.renderer->texPal[offset + i] = NULL;
431 }
432 }
433 break;
434 case MODE_7_VRAM:
435 for (i = 0; i < size; i += 16) {
436 ds->memory.vram7[(offset + i) >> 4] = NULL;
437 }
438 break;
439 case MODE_LCDC:
440 break;
441 }
442
443 struct DSVRAMBankInfo info = _vramInfo[index][value & 0x7];
444 memset(&memory->vramMirror[index], 0, sizeof(memory->vramMirror[index]));
445 memset(&memory->vramMode[index], 0, sizeof(memory->vramMode[index]));
446 if (!(value & 0x80) || !info.mirrorSize) {
447 return;
448 }
449 offset = info.base + info.offset[(value >> 3) & 3];
450 if (info.mode <= MODE_LCDC) {
451 memory->vramMode[index][info.mode] = 0xFFFF;
452 for (j = offset; j < 0x40; j += info.mirrorSize) {
453 for (i = 0; i < size; ++i) {
454 memory->vramMirror[index][i + j] = 1 << index;
455 }
456 }
457 }
458 switch (info.mode) {
459 case MODE_A_BG:
460 for (i = 0; i < size; ++i) {
461 ds->video.vramABG[offset + i] = &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)];
462 ds->video.renderer->vramABG[offset + i] = ds->video.vramABG[offset + i];
463 }
464 break;
465 case MODE_B_BG:
466 for (i = 0; i < size; ++i) {
467 ds->video.vramBBG[offset + i] = &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)];
468 ds->video.renderer->vramBBG[offset + i] = ds->video.vramBBG[offset + i];
469 }
470 break;
471 case MODE_A_OBJ:
472 for (i = 0; i < size; ++i) {
473 ds->video.vramAOBJ[offset + i] = &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)];
474 ds->video.renderer->vramAOBJ[offset + i] = ds->video.vramAOBJ[offset + i];
475 }
476 break;
477 case MODE_B_OBJ:
478 for (i = 0; i < size; ++i) {
479 ds->video.vramBOBJ[offset + i] = &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)];
480 ds->video.renderer->vramBOBJ[offset + i] = ds->video.vramBOBJ[offset + i];
481 }
482 break;
483 case MODE_A_BG_EXT_PAL:
484 for (i = 0; i < info.mirrorSize; ++i) {
485 ds->video.vramABGExtPal[offset + i] = &memory->vramBank[index][i << 12];
486 ds->video.renderer->vramABGExtPal[offset + i] = ds->video.vramABGExtPal[offset + i];
487 ds->video.renderer->invalidateExtPal(ds->video.renderer, false, false, offset + i);
488 }
489 break;
490 case MODE_B_BG_EXT_PAL:
491 for (i = 0; i < info.mirrorSize; ++i) {
492 ds->video.vramBBGExtPal[offset + i] = &memory->vramBank[index][i << 12];
493 ds->video.renderer->vramBBGExtPal[offset + i] = ds->video.vramBBGExtPal[offset + i];
494 ds->video.renderer->invalidateExtPal(ds->video.renderer, false, true, offset + i);
495 }
496 break;
497 case MODE_A_OBJ_EXT_PAL:
498 ds->video.vramAOBJExtPal = memory->vramBank[index];
499 ds->video.renderer->vramAOBJExtPal = ds->video.vramAOBJExtPal;
500 ds->video.renderer->invalidateExtPal(ds->video.renderer, true, false, 0);
501 break;
502 case MODE_B_OBJ_EXT_PAL:
503 ds->video.vramBOBJExtPal = memory->vramBank[index];
504 ds->video.renderer->vramBOBJExtPal = ds->video.vramBOBJExtPal;
505 ds->video.renderer->invalidateExtPal(ds->video.renderer, true, true, 0);
506 break;
507 case MODE_3D_TEX:
508 ds->gx.tex[offset] = memory->vramBank[index];
509 ds->gx.renderer->tex[offset] = ds->gx.tex[offset];
510 ds->gx.renderer->invalidateTex(ds->gx.renderer, offset);
511 break;
512 case MODE_3D_TEX_PAL:
513 for (i = 0; i < info.mirrorSize; ++i) {
514 ds->gx.texPal[offset + i] = &memory->vramBank[index][i << 13];
515 ds->gx.renderer->texPal[offset + i] = ds->gx.texPal[offset + i];
516 }
517 break;
518 case MODE_7_VRAM:
519 for (i = 0; i < size; i += 16) {
520 ds->memory.vram7[(offset + i) >> 4] = &memory->vramBank[index][i << (DS_VRAM_OFFSET - 5)];
521 }
522 break;
523 case MODE_LCDC:
524 break;
525 }
526}
527
528static void DSVideoDummyRendererInit(struct DSVideoRenderer* renderer) {
529 UNUSED(renderer);
530 // Nothing to do
531}
532
533static void DSVideoDummyRendererReset(struct DSVideoRenderer* renderer) {
534 UNUSED(renderer);
535 // Nothing to do
536}
537
538static void DSVideoDummyRendererDeinit(struct DSVideoRenderer* renderer) {
539 UNUSED(renderer);
540 // Nothing to do
541}
542
543static uint16_t DSVideoDummyRendererWriteVideoRegister(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value) {
544 UNUSED(renderer);
545 return value;
546}
547
548static void DSVideoDummyRendererWritePalette(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value) {
549 UNUSED(renderer);
550 UNUSED(address);
551 UNUSED(value);
552 // Nothing to do
553}
554
555static void DSVideoDummyRendererWriteOAM(struct DSVideoRenderer* renderer, uint32_t oam) {
556 UNUSED(renderer);
557 UNUSED(oam);
558 // Nothing to do
559}
560
561static void DSVideoDummyRendererInvalidateExtPal(struct DSVideoRenderer* renderer, bool obj, bool engB, int slot) {
562 UNUSED(renderer);
563 UNUSED(obj);
564 UNUSED(engB);
565 // Nothing to do
566}
567
568static void DSVideoDummyRendererDrawScanline(struct DSVideoRenderer* renderer, int y) {
569 UNUSED(renderer);
570 UNUSED(y);
571 // Nothing to do
572}
573
574static void DSVideoDummyRendererFinishFrame(struct DSVideoRenderer* renderer) {
575 UNUSED(renderer);
576 // Nothing to do
577}
578
579static void DSVideoDummyRendererGetPixels(struct DSVideoRenderer* renderer, size_t* stride, const void** pixels) {
580 UNUSED(renderer);
581 UNUSED(stride);
582 UNUSED(pixels);
583 // Nothing to do
584}
585
586static void DSVideoDummyRendererPutPixels(struct DSVideoRenderer* renderer, size_t stride, const void* pixels) {
587 UNUSED(renderer);
588 UNUSED(stride);
589 UNUSED(pixels);
590 // Nothing to do
591}