DS Video: Start hooking up software renderer
Vicki Pfau vi@endrift.com
Tue, 21 Feb 2017 16:11:32 -0800
5 files changed,
135 insertions(+),
62 deletions(-)
M
include/mgba/internal/ds/video.h
→
include/mgba/internal/ds/video.h
@@ -12,6 +12,7 @@ CXX_GUARD_START
#include <mgba/core/log.h> #include <mgba/core/timing.h> +#include <mgba/internal/gba/video.h> mLOG_DECLARE_CATEGORY(DS_VIDEO);@@ -29,6 +30,11 @@
DS_VIDEO_TOTAL_LENGTH = DS_VIDEO_HORIZONTAL_LENGTH * DS_VIDEO_VERTICAL_TOTAL_PIXELS, }; +union DSOAM { + union GBAOAM oam[2]; + uint16_t raw[1024]; +}; + struct DSVideoRenderer { void (*init)(struct DSVideoRenderer* renderer); void (*reset)(struct DSVideoRenderer* renderer);@@ -41,7 +47,9 @@
void (*getPixels)(struct DSVideoRenderer* renderer, size_t* stride, const void** pixels); void (*putPixels)(struct DSVideoRenderer* renderer, size_t stride, const void* pixels); + uint16_t* palette; uint16_t* vram; + union DSOAM* oam; }; struct DS;@@ -54,7 +62,9 @@
// VCOUNT int vcount; + uint16_t palette[1024]; uint16_t* vram; + union DSOAM oam; int32_t frameCounter; int frameskip;
M
src/ds/io.c
→
src/ds/io.c
@@ -386,71 +386,77 @@ DS9IOWrite(ds, DS9_REG_VRAMCNT_G, 0x0300);
} void DS9IOWrite(struct DS* ds, uint32_t address, uint16_t value) { - switch (address) { - // VRAM control - case DS9_REG_VRAMCNT_A: - case DS9_REG_VRAMCNT_C: - case DS9_REG_VRAMCNT_E: - value &= 0x9F9F; - DSVideoConfigureVRAM(&ds->memory, address - DS9_REG_VRAMCNT_A, value & 0xFF); - DSVideoConfigureVRAM(&ds->memory, address - DS9_REG_VRAMCNT_A + 1, value >> 8); - break; - case DS9_REG_VRAMCNT_G: - value &= 0x9F03; - DSVideoConfigureVRAM(&ds->memory, 6, value & 0xFF); - DSConfigureWRAM(&ds->memory, value >> 8); - break; - case DS9_REG_VRAMCNT_H: - value &= 0x9F9F; - DSVideoConfigureVRAM(&ds->memory, 7, value & 0xFF); - DSVideoConfigureVRAM(&ds->memory, 8, value >> 8); - break; + if (address <= DS9_REG_A_BLDY && (address > DS_REG_VCOUNT || address == DS9_REG_A_DISPCNT_LO || address == DS9_REG_B_DISPCNT_LO)) { + value = ds->video.renderer->writeVideoRegister(ds->video.renderer, address, value); + } else if (address >= DS9_REG_B_DISPCNT_LO && address <= DS9_REG_B_BLDY && (address == DS9_REG_B_DISPCNT_LO || address == DS9_REG_B_DISPCNT_LO)) { + value = ds->video.renderer->writeVideoRegister(ds->video.renderer, address, value); + } else { + switch (address) { + // VRAM control + case DS9_REG_VRAMCNT_A: + case DS9_REG_VRAMCNT_C: + case DS9_REG_VRAMCNT_E: + value &= 0x9F9F; + DSVideoConfigureVRAM(&ds->memory, address - DS9_REG_VRAMCNT_A, value & 0xFF); + DSVideoConfigureVRAM(&ds->memory, address - DS9_REG_VRAMCNT_A + 1, value >> 8); + break; + case DS9_REG_VRAMCNT_G: + value &= 0x9F03; + DSVideoConfigureVRAM(&ds->memory, 6, value & 0xFF); + DSConfigureWRAM(&ds->memory, value >> 8); + break; + case DS9_REG_VRAMCNT_H: + value &= 0x9F9F; + DSVideoConfigureVRAM(&ds->memory, 7, value & 0xFF); + DSVideoConfigureVRAM(&ds->memory, 8, value >> 8); + break; - case DS9_REG_EXMEMCNT: - value &= 0xE8FF; - DSConfigureExternalMemory(ds, value); - break; + case DS9_REG_EXMEMCNT: + value &= 0xE8FF; + DSConfigureExternalMemory(ds, value); + break; - // Math - case DS9_REG_DIVCNT: - value = _scheduleDiv(ds, value); - break; - case DS9_REG_DIV_NUMER_0: - case DS9_REG_DIV_NUMER_1: - case DS9_REG_DIV_NUMER_2: - case DS9_REG_DIV_NUMER_3: - case DS9_REG_DIV_DENOM_0: - case DS9_REG_DIV_DENOM_1: - case DS9_REG_DIV_DENOM_2: - case DS9_REG_DIV_DENOM_3: - ds->memory.io9[DS9_REG_DIVCNT >> 1] = _scheduleDiv(ds, ds->memory.io9[DS9_REG_DIVCNT >> 1]); - break; - case DS9_REG_SQRTCNT: - value = _scheduleSqrt(ds, value); - break; - case DS9_REG_SQRT_PARAM_0: - case DS9_REG_SQRT_PARAM_1: - case DS9_REG_SQRT_PARAM_2: - case DS9_REG_SQRT_PARAM_3: - ds->memory.io9[DS9_REG_SQRTCNT >> 1] = _scheduleSqrt(ds, ds->memory.io9[DS9_REG_SQRTCNT >> 1]); - break; + // Math + case DS9_REG_DIVCNT: + value = _scheduleDiv(ds, value); + break; + case DS9_REG_DIV_NUMER_0: + case DS9_REG_DIV_NUMER_1: + case DS9_REG_DIV_NUMER_2: + case DS9_REG_DIV_NUMER_3: + case DS9_REG_DIV_DENOM_0: + case DS9_REG_DIV_DENOM_1: + case DS9_REG_DIV_DENOM_2: + case DS9_REG_DIV_DENOM_3: + ds->memory.io9[DS9_REG_DIVCNT >> 1] = _scheduleDiv(ds, ds->memory.io9[DS9_REG_DIVCNT >> 1]); + break; + case DS9_REG_SQRTCNT: + value = _scheduleSqrt(ds, value); + break; + case DS9_REG_SQRT_PARAM_0: + case DS9_REG_SQRT_PARAM_1: + case DS9_REG_SQRT_PARAM_2: + case DS9_REG_SQRT_PARAM_3: + ds->memory.io9[DS9_REG_SQRTCNT >> 1] = _scheduleSqrt(ds, ds->memory.io9[DS9_REG_SQRTCNT >> 1]); + break; - default: - { - uint32_t v2 = DSIOWrite(&ds->ds9, address, value); - if (v2 & 0x10000) { - value = v2; - break; - } else if (v2 & 0x20000) { + default: + { + uint32_t v2 = DSIOWrite(&ds->ds9, address, value); + if (v2 & 0x10000) { + value = v2; + break; + } else if (v2 & 0x20000) { + return; + } + } + mLOG(DS_IO, STUB, "Stub DS9 I/O register write: %06X:%04X", address, value); + if (address >= DS7_REG_MAX) { + mLOG(DS_IO, GAME_ERROR, "Write to unused DS9 I/O register: %06X:%04X", address, value); return; } + break; } - mLOG(DS_IO, STUB, "Stub DS9 I/O register write: %06X:%04X", address, value); - if (address >= DS7_REG_MAX) { - mLOG(DS_IO, GAME_ERROR, "Write to unused DS9 I/O register: %06X:%04X", address, value); - return; - } - break; } ds->memory.io9[address >> 1] = value; }
M
src/ds/memory.c
→
src/ds/memory.c
@@ -526,8 +526,6 @@ address += 4; \
} \ } - - uint32_t DS7LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) { struct DS* ds = (struct DS*) cpu->master; struct DSMemory* memory = &ds->memory;@@ -589,7 +587,6 @@ }
return address | addressMisalign; } - uint32_t DS7StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) { struct DS* ds = (struct DS*) cpu->master;@@ -733,6 +730,9 @@ break;
case DS_REGION_IO: value = DS9IORead32(ds, address & 0x00FFFFFC); break; + case DS9_REGION_PALETTE_RAM: + LOAD_32(value, address & (DS9_SIZE_PALETTE_RAM - 4), ds->video.palette); + break; case DS_REGION_VRAM: { unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET); int i = 0;@@ -745,6 +745,9 @@ }
} break; } + case DS9_REGION_OAM: + LOAD_32(value, address & (DS9_SIZE_OAM - 4), ds->video.oam.raw); + break; case DS9_REGION_BIOS: // TODO: Fix undersized BIOS // TODO: Fix masking@@ -803,6 +806,9 @@ mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
case DS_REGION_IO: value = DS9IORead(ds, address & DS_OFFSET_MASK); break; + case DS9_REGION_PALETTE_RAM: + LOAD_16(value, address & (DS9_SIZE_PALETTE_RAM - 2), ds->video.palette); + break; case DS_REGION_VRAM: { unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET); int i = 0;@@ -815,6 +821,9 @@ }
} break; } + case DS9_REGION_OAM: + LOAD_16(value, address & (DS9_SIZE_OAM - 2), ds->video.oam.raw); + break; case DS9_REGION_BIOS: // TODO: Fix undersized BIOS // TODO: Fix masking@@ -929,6 +938,9 @@ break;
case DS_REGION_IO: DS9IOWrite32(ds, address & DS_OFFSET_MASK, value); break; + case DS9_REGION_PALETTE_RAM: + STORE_32(value, address & (DS9_SIZE_PALETTE_RAM - 4), ds->video.palette); + break; case DS_REGION_VRAM: { unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET); int i = 0;@@ -939,6 +951,9 @@ }
} break; } + case DS9_REGION_OAM: + STORE_32(value, address & (DS9_SIZE_OAM - 4), ds->video.oam.raw); + break; default: if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) { STORE_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);@@ -989,6 +1004,9 @@ break;
case DS_REGION_IO: DS9IOWrite(ds, address & DS_OFFSET_MASK, value); break; + case DS9_REGION_PALETTE_RAM: + STORE_16(value, address & (DS9_SIZE_PALETTE_RAM - 2), ds->video.palette); + break; case DS_REGION_VRAM: { unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET); int i = 0;@@ -999,6 +1017,9 @@ }
} break; } + case DS9_REGION_OAM: + STORE_16(value, address & (DS9_SIZE_OAM - 2), ds->video.oam.raw); + break; default: if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) { STORE_16(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);@@ -1113,6 +1134,9 @@ });
break; case DS_REGION_IO: LDM_LOOP(value = DS9IORead32(ds, address)); + break; + case DS9_REGION_PALETTE_RAM: + LDM_LOOP(LOAD_32(value, address & (DS9_SIZE_PALETTE_RAM - 1), ds->video.palette)); break; case DS_REGION_VRAM: LDM_LOOP(unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);@@ -1126,6 +1150,9 @@ value |= newValue;
} }); break; + case DS9_REGION_OAM: + LDM_LOOP(LOAD_32(value, address & (DS9_SIZE_OAM - 1), ds->video.oam.raw)); + break; default: LDM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) { LOAD_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);@@ -1200,6 +1227,9 @@ } else {
mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address); }); break; + case DS9_REGION_PALETTE_RAM: + STM_LOOP(STORE_32(value, address & (DS9_SIZE_PALETTE_RAM - 1), ds->video.palette)); + break; case DS_REGION_VRAM: STM_LOOP(unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET); int i = 0;@@ -1208,6 +1238,9 @@ if (mask & (1 << i)) {
STORE_32(value, address & _vramMask[i], memory->vramBank[i]); } }); + break; + case DS9_REGION_OAM: + STM_LOOP(STORE_32(value, address & (DS9_SIZE_OAM - 1), ds->video.oam.raw)); break; default: STM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
M
src/ds/renderers/software.c
→
src/ds/renderers/software.c
@@ -18,22 +18,44 @@ void DSVideoSoftwareRendererCreate(struct DSVideoSoftwareRenderer* renderer) {
renderer->d.init = DSVideoSoftwareRendererInit; renderer->d.reset = DSVideoSoftwareRendererReset; renderer->d.deinit = DSVideoSoftwareRendererDeinit; + renderer->d.writeVideoRegister = DSVideoSoftwareRendererWriteVideoRegister; renderer->d.drawScanline = DSVideoSoftwareRendererDrawScanline; renderer->d.finishFrame = DSVideoSoftwareRendererFinishFrame; renderer->d.getPixels = DSVideoSoftwareRendererGetPixels; renderer->d.putPixels = DSVideoSoftwareRendererPutPixels; + + renderer->engA.d.cache = NULL; + GBAVideoSoftwareRendererCreate(&renderer->engA); + renderer->engB.d.cache = NULL; + GBAVideoSoftwareRendererCreate(&renderer->engB); } static void DSVideoSoftwareRendererInit(struct DSVideoRenderer* renderer) { + struct DSVideoSoftwareRenderer* softwareRenderer = (struct DSVideoSoftwareRenderer*) renderer; + softwareRenderer->engA.d.palette = &renderer->palette[0]; + softwareRenderer->engA.d.oam = &renderer->oam->oam[0]; + // TODO: VRAM + softwareRenderer->engB.d.palette = &renderer->palette[512]; + softwareRenderer->engB.d.oam = &renderer->oam->oam[1]; + // TODO: VRAM + + DSVideoSoftwareRendererReset(renderer); } static void DSVideoSoftwareRendererReset(struct DSVideoRenderer* renderer) { + struct DSVideoSoftwareRenderer* softwareRenderer = (struct DSVideoSoftwareRenderer*) renderer; + softwareRenderer->engA.d.reset(&softwareRenderer->engA.d); + softwareRenderer->engB.d.reset(&softwareRenderer->engB.d); } static void DSVideoSoftwareRendererDeinit(struct DSVideoRenderer* renderer) { + struct DSVideoSoftwareRenderer* softwareRenderer = (struct DSVideoSoftwareRenderer*) renderer; + softwareRenderer->engA.d.deinit(&softwareRenderer->engA.d); + softwareRenderer->engB.d.deinit(&softwareRenderer->engB.d); } static uint16_t DSVideoSoftwareRendererWriteVideoRegister(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value) { + mLOG(DS_VIDEO, STUB, "Stub video register write: %04X:%04X", address, value); return value; }
M
src/ds/video.c
→
src/ds/video.c
@@ -158,7 +158,9 @@
void DSVideoAssociateRenderer(struct DSVideo* video, struct DSVideoRenderer* renderer) { video->renderer->deinit(video->renderer); video->renderer = renderer; + renderer->palette = video->palette; renderer->vram = video->vram; + renderer->oam = &video->oam; video->renderer->init(video->renderer); }