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, 0x10, 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, 0x10, 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, 0x10, 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, 0x10, 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 .drawScanline = DSVideoDummyRendererDrawScanline,
137 .finishFrame = DSVideoDummyRendererFinishFrame,
138 .getPixels = DSVideoDummyRendererGetPixels,
139 .putPixels = DSVideoDummyRendererPutPixels,
140};
141
142void DSVideoInit(struct DSVideo* video) {
143 video->renderer = &dummyRenderer;
144 video->vram = NULL;
145 video->frameskip = 0;
146 video->event7.name = "DS7 Video";
147 video->event7.callback = NULL;
148 video->event7.context = video;
149 video->event7.priority = 8;
150 video->event9.name = "DS9 Video";
151 video->event9.callback = NULL;
152 video->event9.context = video;
153 video->event9.priority = 8;
154}
155
156void DSVideoReset(struct DSVideo* video) {
157 video->vcount = 0;
158 video->p->ds7.memory.io[DS_REG_VCOUNT >> 1] = video->vcount;
159 video->p->ds9.memory.io[DS_REG_VCOUNT >> 1] = video->vcount;
160
161 video->event7.callback = _startHblank7;
162 video->event9.callback = _startHblank9;
163 mTimingSchedule(&video->p->ds7.timing, &video->event7, DS_VIDEO_HORIZONTAL_LENGTH - DS7_VIDEO_HBLANK_LENGTH);
164 mTimingSchedule(&video->p->ds9.timing, &video->event9, (DS_VIDEO_HORIZONTAL_LENGTH - DS9_VIDEO_HBLANK_LENGTH) * 2);
165
166 video->frameCounter = 0;
167 video->frameskipCounter = 0;
168
169 if (video->vram) {
170 mappedMemoryFree(video->vram, DS_SIZE_VRAM);
171 }
172 video->vram = anonymousMemoryMap(DS_SIZE_VRAM);
173 video->renderer->vram = video->vram;
174
175 video->p->memory.vramBank[0] = &video->vram[0x00000];
176 video->p->memory.vramBank[1] = &video->vram[0x10000];
177 video->p->memory.vramBank[2] = &video->vram[0x20000];
178 video->p->memory.vramBank[3] = &video->vram[0x30000];
179 video->p->memory.vramBank[4] = &video->vram[0x40000];
180 video->p->memory.vramBank[5] = &video->vram[0x48000];
181 video->p->memory.vramBank[6] = &video->vram[0x4A000];
182 video->p->memory.vramBank[7] = &video->vram[0x4C000];
183 video->p->memory.vramBank[8] = &video->vram[0x50000];
184
185 video->renderer->deinit(video->renderer);
186 video->renderer->init(video->renderer);
187}
188
189void DSVideoAssociateRenderer(struct DSVideo* video, struct DSVideoRenderer* renderer) {
190 video->renderer->deinit(video->renderer);
191 video->renderer = renderer;
192 renderer->palette = video->palette;
193 renderer->vram = video->vram;
194 memcpy(renderer->vramABG, video->vramABG, sizeof(renderer->vramABG));
195 memcpy(renderer->vramAOBJ, video->vramAOBJ, sizeof(renderer->vramAOBJ));
196 memcpy(renderer->vramABGExtPal, video->vramABGExtPal, sizeof(renderer->vramABGExtPal));
197 memcpy(renderer->vramAOBJExtPal, video->vramAOBJExtPal, sizeof(renderer->vramAOBJExtPal));
198 memcpy(renderer->vramBBG, video->vramBBG, sizeof(renderer->vramBBG));
199 memcpy(renderer->vramBOBJ, video->vramBOBJ, sizeof(renderer->vramBOBJ));
200 memcpy(renderer->vramBBGExtPal, video->vramBBGExtPal, sizeof(renderer->vramBBGExtPal));
201 memcpy(renderer->vramBOBJExtPal, video->vramBOBJExtPal, sizeof(renderer->vramBOBJExtPal));
202 renderer->oam = &video->oam;
203 video->renderer->init(video->renderer);
204}
205
206void DSVideoDeinit(struct DSVideo* video) {
207 DSVideoAssociateRenderer(video, &dummyRenderer);
208 mappedMemoryFree(video->vram, DS_SIZE_VRAM);
209}
210
211void _startHdraw7(struct mTiming* timing, void* context, uint32_t cyclesLate) {
212 struct DSVideo* video = context;
213 GBARegisterDISPSTAT dispstat = video->p->ds7.memory.io[DS_REG_DISPSTAT >> 1];
214 dispstat = GBARegisterDISPSTATClearInHblank(dispstat);
215 video->event7.callback = _startHblank7;
216 mTimingSchedule(timing, &video->event7, DS_VIDEO_HORIZONTAL_LENGTH - DS7_VIDEO_HBLANK_LENGTH - cyclesLate);
217
218 video->p->ds7.memory.io[DS_REG_VCOUNT >> 1] = video->vcount;
219
220 if (video->vcount == GBARegisterDISPSTATGetVcountSetting(dispstat)) {
221 dispstat = GBARegisterDISPSTATFillVcounter(dispstat);
222 if (GBARegisterDISPSTATIsVcounterIRQ(dispstat)) {
223 DSRaiseIRQ(video->p->ds7.cpu, video->p->ds7.memory.io, DS_IRQ_VCOUNTER);
224 }
225 } else {
226 dispstat = GBARegisterDISPSTATClearVcounter(dispstat);
227 }
228 video->p->ds7.memory.io[DS_REG_DISPSTAT >> 1] = dispstat;
229
230 switch (video->vcount) {
231 case DS_VIDEO_VERTICAL_PIXELS:
232 video->p->ds7.memory.io[DS_REG_DISPSTAT >> 1] = GBARegisterDISPSTATFillInVblank(dispstat);
233 if (GBARegisterDISPSTATIsVblankIRQ(dispstat)) {
234 DSRaiseIRQ(video->p->ds7.cpu, video->p->ds7.memory.io, DS_IRQ_VBLANK);
235 }
236 break;
237 case DS_VIDEO_VERTICAL_TOTAL_PIXELS - 1:
238 video->p->ds7.memory.io[DS_REG_DISPSTAT >> 1] = GBARegisterDISPSTATClearInVblank(dispstat);
239 break;
240 }
241}
242
243void _startHblank7(struct mTiming* timing, void* context, uint32_t cyclesLate) {
244 struct DSVideo* video = context;
245 GBARegisterDISPSTAT dispstat = video->p->ds7.memory.io[DS_REG_DISPSTAT >> 1];
246 dispstat = GBARegisterDISPSTATFillInHblank(dispstat);
247 video->event7.callback = _startHdraw7;
248 mTimingSchedule(timing, &video->event7, DS7_VIDEO_HBLANK_LENGTH - cyclesLate);
249
250 // Begin Hblank
251 dispstat = GBARegisterDISPSTATFillInHblank(dispstat);
252
253 if (GBARegisterDISPSTATIsHblankIRQ(dispstat)) {
254 DSRaiseIRQ(video->p->ds7.cpu, video->p->ds7.memory.io, DS_IRQ_HBLANK);
255 }
256 video->p->ds7.memory.io[DS_REG_DISPSTAT >> 1] = dispstat;
257}
258
259void _startHdraw9(struct mTiming* timing, void* context, uint32_t cyclesLate) {
260 struct DSVideo* video = context;
261 GBARegisterDISPSTAT dispstat = video->p->ds9.memory.io[DS_REG_DISPSTAT >> 1];
262 dispstat = GBARegisterDISPSTATClearInHblank(dispstat);
263 video->event9.callback = _startHblank9;
264 mTimingSchedule(timing, &video->event9, (DS_VIDEO_HORIZONTAL_LENGTH - DS9_VIDEO_HBLANK_LENGTH) * 2 - cyclesLate);
265
266 ++video->vcount;
267 if (video->vcount == DS_VIDEO_VERTICAL_TOTAL_PIXELS) {
268 video->vcount = 0;
269 }
270 video->p->ds9.memory.io[DS_REG_VCOUNT >> 1] = video->vcount;
271
272 if (video->vcount == GBARegisterDISPSTATGetVcountSetting(dispstat)) {
273 dispstat = GBARegisterDISPSTATFillVcounter(dispstat);
274 if (GBARegisterDISPSTATIsVcounterIRQ(dispstat)) {
275 DSRaiseIRQ(video->p->ds9.cpu, video->p->ds9.memory.io, DS_IRQ_VCOUNTER);
276 }
277 } else {
278 dispstat = GBARegisterDISPSTATClearVcounter(dispstat);
279 }
280 video->p->ds9.memory.io[DS_REG_DISPSTAT >> 1] = dispstat;
281
282 // Note: state may be recorded during callbacks, so ensure it is consistent!
283 switch (video->vcount) {
284 case 0:
285 DSFrameStarted(video->p);
286 break;
287 case DS_VIDEO_VERTICAL_PIXELS:
288 video->p->ds9.memory.io[DS_REG_DISPSTAT >> 1] = GBARegisterDISPSTATFillInVblank(dispstat);
289 if (video->frameskipCounter <= 0) {
290 video->renderer->finishFrame(video->renderer);
291 }
292 if (GBARegisterDISPSTATIsVblankIRQ(dispstat)) {
293 DSRaiseIRQ(video->p->ds9.cpu, video->p->ds9.memory.io, DS_IRQ_VBLANK);
294 }
295 DSFrameEnded(video->p);
296 --video->frameskipCounter;
297 if (video->frameskipCounter < 0) {
298 mCoreSyncPostFrame(video->p->sync);
299 video->frameskipCounter = video->frameskip;
300 }
301 ++video->frameCounter;
302 break;
303 case DS_VIDEO_VERTICAL_TOTAL_PIXELS - 1:
304 video->p->ds9.memory.io[DS_REG_DISPSTAT >> 1] = GBARegisterDISPSTATClearInVblank(dispstat);
305 break;
306 }
307}
308
309void _startHblank9(struct mTiming* timing, void* context, uint32_t cyclesLate) {
310 struct DSVideo* video = context;
311 GBARegisterDISPSTAT dispstat = video->p->ds9.memory.io[DS_REG_DISPSTAT >> 1];
312 dispstat = GBARegisterDISPSTATFillInHblank(dispstat);
313 video->event9.callback = _startHdraw9;
314 mTimingSchedule(timing, &video->event9, (DS9_VIDEO_HBLANK_LENGTH * 2) - cyclesLate);
315
316 // Begin Hblank
317 dispstat = GBARegisterDISPSTATFillInHblank(dispstat);
318 if (video->vcount < DS_VIDEO_VERTICAL_PIXELS && video->frameskipCounter <= 0) {
319 video->renderer->drawScanline(video->renderer, video->vcount);
320 }
321
322 if (GBARegisterDISPSTATIsHblankIRQ(dispstat)) {
323 DSRaiseIRQ(video->p->ds9.cpu, video->p->ds9.memory.io, DS_IRQ_HBLANK);
324 }
325 video->p->ds9.memory.io[DS_REG_DISPSTAT >> 1] = dispstat;
326}
327
328void DSVideoWriteDISPSTAT(struct DSCommon* dscore, uint16_t value) {
329 dscore->memory.io[DS_REG_DISPSTAT >> 1] &= 0x7;
330 dscore->memory.io[DS_REG_DISPSTAT >> 1] |= value;
331 // TODO: Does a VCounter IRQ trigger on write?
332}
333
334void DSVideoConfigureVRAM(struct DS* ds, int index, uint8_t value, uint8_t oldValue) {
335 struct DSMemory* memory = &ds->memory;
336 if (value == oldValue) {
337 return;
338 }
339 uint32_t i, j;
340 uint32_t size = _vramSize[index] >> DS_VRAM_OFFSET;
341 struct DSVRAMBankInfo oldInfo = _vramInfo[index][oldValue & 0x7];
342 uint32_t offset = oldInfo.base + oldInfo.offset[(oldValue >> 3) & 3];
343 switch (oldInfo.mode) {
344 case MODE_A_BG:
345 for (i = 0; i < size; ++i) {
346 if (ds->video.vramABG[offset + i] == &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)]) {
347 ds->video.vramABG[offset + i] = NULL;
348 ds->video.renderer->vramABG[offset + i] = NULL;
349 }
350 }
351 break;
352 case MODE_B_BG:
353 for (i = 0; i < size; ++i) {
354 if (ds->video.vramBBG[offset + i] == &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)]) {
355 ds->video.vramBBG[offset + i] = NULL;
356 ds->video.renderer->vramBBG[offset + i] = NULL;
357 }
358 }
359 break;
360 case MODE_A_OBJ:
361 for (i = 0; i < size; ++i) {
362 if (ds->video.vramAOBJ[offset + i] == &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)]) {
363 ds->video.vramAOBJ[offset + i] = NULL;
364 ds->video.renderer->vramAOBJ[offset + i] = NULL;
365 }
366 }
367 break;
368 case MODE_B_OBJ:
369 for (i = 0; i < size; ++i) {
370 if (ds->video.vramBOBJ[offset + i] == &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)]) {
371 ds->video.vramBOBJ[offset + i] = NULL;
372 ds->video.renderer->vramBOBJ[offset + i] = NULL;
373 }
374 }
375 break;
376 case MODE_A_BG_EXT_PAL:
377 for (i = 0; i < oldInfo.mirrorSize; ++i) {
378 if (ds->video.vramABGExtPal[offset + i] == &memory->vramBank[index][i << 12]) {
379 ds->video.vramABGExtPal[offset + i] = NULL;
380 ds->video.renderer->vramABGExtPal[offset + i] = NULL;
381 ds->video.renderer->invalidateExtPal(ds->video.renderer, false, false, offset + i);
382 }
383 }
384 break;
385 case MODE_B_BG_EXT_PAL:
386 for (i = 0; i < oldInfo.mirrorSize; ++i) {
387 if (ds->video.vramBBGExtPal[offset + i] == &memory->vramBank[index][i << 12]) {
388 ds->video.vramBBGExtPal[offset + i] = NULL;
389 ds->video.renderer->vramBBGExtPal[offset + i] = NULL;
390 ds->video.renderer->invalidateExtPal(ds->video.renderer, false, true, offset + i);
391 }
392 }
393 break;
394 case MODE_7_VRAM:
395 for (i = 0; i < size; i += 16) {
396 ds->memory.vram7[(offset + i) >> 4] = NULL;
397 }
398 break;
399 case MODE_LCDC:
400 break;
401 }
402
403 struct DSVRAMBankInfo info = _vramInfo[index][value & 0x7];
404 memset(&memory->vramMirror[index], 0, sizeof(memory->vramMirror[index]));
405 memset(&memory->vramMode[index], 0, sizeof(memory->vramMode[index]));
406 if (!(value & 0x80) || !info.mirrorSize) {
407 return;
408 }
409 offset = info.base + info.offset[(value >> 3) & 3];
410 if (info.mode <= MODE_LCDC) {
411 memory->vramMode[index][info.mode] = 0xFFFF;
412 for (j = offset; j < 0x40; j += info.mirrorSize) {
413 for (i = 0; i < size; ++i) {
414 memory->vramMirror[index][i + j] = 1 << index;
415 }
416 }
417 }
418 switch (info.mode) {
419 case MODE_A_BG:
420 for (i = 0; i < size; ++i) {
421 ds->video.vramABG[offset + i] = &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)];
422 ds->video.renderer->vramABG[offset + i] = ds->video.vramABG[offset + i];
423 }
424 break;
425 case MODE_B_BG:
426 for (i = 0; i < size; ++i) {
427 ds->video.vramBBG[offset + i] = &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)];
428 ds->video.renderer->vramBBG[offset + i] = ds->video.vramBBG[offset + i];
429 }
430 break;
431 case MODE_A_OBJ:
432 for (i = 0; i < size; ++i) {
433 ds->video.vramAOBJ[offset + i] = &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)];
434 ds->video.renderer->vramAOBJ[offset + i] = ds->video.vramAOBJ[offset + i];
435 }
436 break;
437 case MODE_B_OBJ:
438 for (i = 0; i < size; ++i) {
439 ds->video.vramBOBJ[offset + i] = &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)];
440 ds->video.renderer->vramBOBJ[offset + i] = ds->video.vramBOBJ[offset + i];
441 }
442 break;
443 case MODE_A_BG_EXT_PAL:
444 for (i = 0; i < info.mirrorSize; ++i) {
445 ds->video.vramABGExtPal[offset + i] = &memory->vramBank[index][i << 12];
446 ds->video.renderer->vramABGExtPal[offset + i] = ds->video.vramABGExtPal[offset + i];
447 ds->video.renderer->invalidateExtPal(ds->video.renderer, false, false, offset + i);
448 }
449 break;
450 case MODE_B_BG_EXT_PAL:
451 for (i = 0; i < info.mirrorSize; ++i) {
452 ds->video.vramBBGExtPal[offset + i] = &memory->vramBank[index][i << 12];
453 ds->video.renderer->vramBBGExtPal[offset + i] = ds->video.vramBBGExtPal[offset + i];
454 ds->video.renderer->invalidateExtPal(ds->video.renderer, false, true, offset + i);
455 }
456 break;
457 case MODE_7_VRAM:
458 for (i = 0; i < size; i += 16) {
459 ds->memory.vram7[(offset + i) >> 4] = &memory->vramBank[index][i << (DS_VRAM_OFFSET - 5)];
460 }
461 break;
462 case MODE_LCDC:
463 break;
464 }
465}
466
467static void DSVideoDummyRendererInit(struct DSVideoRenderer* renderer) {
468 UNUSED(renderer);
469 // Nothing to do
470}
471
472static void DSVideoDummyRendererReset(struct DSVideoRenderer* renderer) {
473 UNUSED(renderer);
474 // Nothing to do
475}
476
477static void DSVideoDummyRendererDeinit(struct DSVideoRenderer* renderer) {
478 UNUSED(renderer);
479 // Nothing to do
480}
481
482static uint16_t DSVideoDummyRendererWriteVideoRegister(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value) {
483 UNUSED(renderer);
484 return value;
485}
486
487static void DSVideoDummyRendererWritePalette(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value) {
488 UNUSED(renderer);
489 UNUSED(address);
490 UNUSED(value);
491 // Nothing to do
492}
493
494static void DSVideoDummyRendererWriteOAM(struct DSVideoRenderer* renderer, uint32_t oam) {
495 UNUSED(renderer);
496 UNUSED(oam);
497 // Nothing to do
498}
499
500static void DSVideoDummyRendererInvalidateExtPal(struct DSVideoRenderer* renderer, bool obj, bool engB, int slot) {
501 UNUSED(renderer);
502 UNUSED(obj);
503 UNUSED(engB);
504 // Nothing to do
505}
506
507static void DSVideoDummyRendererDrawScanline(struct DSVideoRenderer* renderer, int y) {
508 UNUSED(renderer);
509 UNUSED(y);
510 // Nothing to do
511}
512
513static void DSVideoDummyRendererFinishFrame(struct DSVideoRenderer* renderer) {
514 UNUSED(renderer);
515 // Nothing to do
516}
517
518static void DSVideoDummyRendererGetPixels(struct DSVideoRenderer* renderer, size_t* stride, const void** pixels) {
519 UNUSED(renderer);
520 UNUSED(stride);
521 UNUSED(pixels);
522 // Nothing to do
523}
524
525static void DSVideoDummyRendererPutPixels(struct DSVideoRenderer* renderer, size_t stride, const void* pixels) {
526 UNUSED(renderer);
527 UNUSED(stride);
528 UNUSED(pixels);
529 // Nothing to do
530}