DS Video: Start implementing capture

This commit is contained in:
Vicki Pfau 2017-03-04 02:54:03 -08:00
parent 830921a14c
commit 6103d49697
7 changed files with 92 additions and 7 deletions

View File

@ -143,7 +143,7 @@ struct DSGXRenderer {
void (*invalidateTex)(struct DSGXRenderer* renderer, int slot); void (*invalidateTex)(struct DSGXRenderer* renderer, int slot);
void (*setRAM)(struct DSGXRenderer* renderer, struct DSGXVertex* verts, struct DSGXPolygon* polys, unsigned polyCount, bool wSort); void (*setRAM)(struct DSGXRenderer* renderer, struct DSGXVertex* verts, struct DSGXPolygon* polys, unsigned polyCount, bool wSort);
void (*drawScanline)(struct DSGXRenderer* renderer, int y); void (*drawScanline)(struct DSGXRenderer* renderer, int y);
void (*getScanline)(struct DSGXRenderer* renderer, int y, color_t** output); void (*getScanline)(struct DSGXRenderer* renderer, int y, const color_t** output);
uint16_t* tex[4]; uint16_t* tex[4];
uint16_t* texPal[6]; uint16_t* texPal[6];

View File

@ -60,6 +60,18 @@ DECL_BITS(DSRegisterDISPCNT, ScreenBase, 27, 3);
DECL_BIT(DSRegisterDISPCNT, BgExtPalette, 30); DECL_BIT(DSRegisterDISPCNT, BgExtPalette, 30);
DECL_BIT(DSRegisterDISPCNT, ObjExtPalette, 31); DECL_BIT(DSRegisterDISPCNT, ObjExtPalette, 31);
DECL_BITFIELD(DSRegisterDISPCAPCNT, uint32_t);
DECL_BITS(DSRegisterDISPCAPCNT, EVA, 0, 4);
DECL_BITS(DSRegisterDISPCAPCNT, EVB, 8, 4);
DECL_BITS(DSRegisterDISPCAPCNT, WriteBlock, 16, 2);
DECL_BITS(DSRegisterDISPCAPCNT, WriteOffset, 18, 2);
DECL_BITS(DSRegisterDISPCAPCNT, CaptureSize, 20, 2);
DECL_BIT(DSRegisterDISPCAPCNT, SourceA, 24);
DECL_BIT(DSRegisterDISPCAPCNT, SourceB, 25);
DECL_BITS(DSRegisterDISPCAPCNT, ReadOffset, 26, 2);
DECL_BITS(DSRegisterDISPCAPCNT, CaptureSource, 29, 2);
DECL_BIT(DSRegisterDISPCAPCNT, Enable, 31);
DECL_BITFIELD(DSRegisterPOWCNT1, uint16_t); DECL_BITFIELD(DSRegisterPOWCNT1, uint16_t);
// TODO // TODO
DECL_BIT(DSRegisterPOWCNT1, Swap, 15); DECL_BIT(DSRegisterPOWCNT1, Swap, 15);
@ -109,8 +121,8 @@ struct DSVideo {
struct mTimingEvent event7; struct mTimingEvent event7;
struct mTimingEvent event9; struct mTimingEvent event9;
// VCOUNT
int vcount; int vcount;
bool inCapture;
uint16_t palette[1024]; uint16_t palette[1024];
uint16_t* vram; uint16_t* vram;

View File

@ -19,7 +19,7 @@ static void DSGXDummyRendererDeinit(struct DSGXRenderer* renderer);
static void DSGXDummyRendererInvalidateTex(struct DSGXRenderer* renderer, int slot); static void DSGXDummyRendererInvalidateTex(struct DSGXRenderer* renderer, int slot);
static void DSGXDummyRendererSetRAM(struct DSGXRenderer* renderer, struct DSGXVertex* verts, struct DSGXPolygon* polys, unsigned polyCount, bool wSort); static void DSGXDummyRendererSetRAM(struct DSGXRenderer* renderer, struct DSGXVertex* verts, struct DSGXPolygon* polys, unsigned polyCount, bool wSort);
static void DSGXDummyRendererDrawScanline(struct DSGXRenderer* renderer, int y); static void DSGXDummyRendererDrawScanline(struct DSGXRenderer* renderer, int y);
static void DSGXDummyRendererGetScanline(struct DSGXRenderer* renderer, int y, color_t** output); static void DSGXDummyRendererGetScanline(struct DSGXRenderer* renderer, int y, const color_t** output);
static void DSGXWriteFIFO(struct DSGX* gx, struct DSGXEntry entry); static void DSGXWriteFIFO(struct DSGX* gx, struct DSGXEntry entry);
@ -1281,7 +1281,7 @@ static void DSGXDummyRendererDrawScanline(struct DSGXRenderer* renderer, int y)
// Nothing to do // Nothing to do
} }
static void DSGXDummyRendererGetScanline(struct DSGXRenderer* renderer, int y, color_t** output) { static void DSGXDummyRendererGetScanline(struct DSGXRenderer* renderer, int y, const color_t** output) {
UNUSED(renderer); UNUSED(renderer);
UNUSED(y); UNUSED(y);
*output = NULL; *output = NULL;

View File

@ -20,7 +20,7 @@ static void DSGXSoftwareRendererDeinit(struct DSGXRenderer* renderer);
static void DSGXSoftwareRendererInvalidateTex(struct DSGXRenderer* renderer, int slot); static void DSGXSoftwareRendererInvalidateTex(struct DSGXRenderer* renderer, int slot);
static void DSGXSoftwareRendererSetRAM(struct DSGXRenderer* renderer, struct DSGXVertex* verts, struct DSGXPolygon* polys, unsigned polyCount, bool wSort); static void DSGXSoftwareRendererSetRAM(struct DSGXRenderer* renderer, struct DSGXVertex* verts, struct DSGXPolygon* polys, unsigned polyCount, bool wSort);
static void DSGXSoftwareRendererDrawScanline(struct DSGXRenderer* renderer, int y); static void DSGXSoftwareRendererDrawScanline(struct DSGXRenderer* renderer, int y);
static void DSGXSoftwareRendererGetScanline(struct DSGXRenderer* renderer, int y, color_t** output); static void DSGXSoftwareRendererGetScanline(struct DSGXRenderer* renderer, int y, const color_t** output);
static void _expandColor(uint16_t c15, uint8_t* r, uint8_t* g, uint8_t* b) { static void _expandColor(uint16_t c15, uint8_t* r, uint8_t* g, uint8_t* b) {
*r = ((c15 << 1) & 0x3E) | 1; *r = ((c15 << 1) & 0x3E) | 1;
@ -503,7 +503,7 @@ static void DSGXSoftwareRendererDrawScanline(struct DSGXRenderer* renderer, int
} }
} }
static void DSGXSoftwareRendererGetScanline(struct DSGXRenderer* renderer, int y, color_t** output) { static void DSGXSoftwareRendererGetScanline(struct DSGXRenderer* renderer, int y, const color_t** output) {
struct DSGXSoftwareRenderer* softwareRenderer = (struct DSGXSoftwareRenderer*) renderer; struct DSGXSoftwareRenderer* softwareRenderer = (struct DSGXSoftwareRenderer*) renderer;
*output = &softwareRenderer->scanlineCache[DS_VIDEO_HORIZONTAL_PIXELS * y]; *output = &softwareRenderer->scanlineCache[DS_VIDEO_HORIZONTAL_PIXELS * y];
} }

View File

@ -433,6 +433,14 @@ void DS9IOWrite(struct DS* ds, uint32_t address, uint16_t value) {
} else { } else {
uint16_t oldValue; uint16_t oldValue;
switch (address) { switch (address) {
// Other video
case DS9_REG_DISPCAPCNT_LO:
value &= 0x1F1F;
break;
case DS9_REG_DISPCAPCNT_HI:
value &= 0xEF3F;
break;
// VRAM control // VRAM control
case DS9_REG_VRAMCNT_A: case DS9_REG_VRAMCNT_A:
case DS9_REG_VRAMCNT_C: case DS9_REG_VRAMCNT_C:

View File

@ -384,7 +384,7 @@ static void DSVideoSoftwareRendererDrawGBAScanline(struct GBAVideoRenderer* rend
} }
if (TEST_LAYER_ENABLED(0)) { if (TEST_LAYER_ENABLED(0)) {
if (DSRegisterDISPCNTIs3D(softwareRenderer->dispcnt) && gx) { if (DSRegisterDISPCNTIs3D(softwareRenderer->dispcnt) && gx) {
color_t* scanline; const color_t* scanline;
gx->renderer->getScanline(gx->renderer, y, &scanline); gx->renderer->getScanline(gx->renderer, y, &scanline);
uint32_t flags = (softwareRenderer->bg[0].priority << OFFSET_PRIORITY) | FLAG_IS_BACKGROUND; uint32_t flags = (softwareRenderer->bg[0].priority << OFFSET_PRIORITY) | FLAG_IS_BACKGROUND;
flags |= FLAG_TARGET_2 * softwareRenderer->bg[0].target2; flags |= FLAG_TARGET_2 * softwareRenderer->bg[0].target2;

View File

@ -6,6 +6,7 @@
#include <mgba/internal/ds/video.h> #include <mgba/internal/ds/video.h>
#include <mgba/core/sync.h> #include <mgba/core/sync.h>
#include <mgba/internal/arm/macros.h>
#include <mgba/internal/ds/ds.h> #include <mgba/internal/ds/ds.h>
#include <mgba/internal/ds/memory.h> #include <mgba/internal/ds/memory.h>
#include <mgba/internal/gba/video.h> #include <mgba/internal/gba/video.h>
@ -210,6 +211,65 @@ void DSVideoDeinit(struct DSVideo* video) {
mappedMemoryFree(video->vram, DS_SIZE_VRAM); mappedMemoryFree(video->vram, DS_SIZE_VRAM);
} }
static void _performCapture(struct DSVideo* video, int y) {
DSRegisterDISPCAPCNT dispcap = video->p->ds9.memory.io[DS9_REG_DISPCAPCNT_LO >> 1];
dispcap |= video->p->ds9.memory.io[DS9_REG_DISPCAPCNT_HI >> 1] << 16;
// TODO: Check mode
int block = DSRegisterDISPCAPCNTGetWriteBlock(dispcap);
if (!video->p->memory.vramMode[block][4]) {
return;
}
uint16_t* vram = &video->vram[0x10000 * block + DSRegisterDISPCAPCNTGetWriteOffset(dispcap) * 0x4000];
const color_t* pixelsA;
int width = DS_VIDEO_HORIZONTAL_PIXELS;
switch (DSRegisterDISPCAPCNTGetCaptureSize(dispcap)) {
case 0:
width = DS_VIDEO_HORIZONTAL_PIXELS / 2;
break;
case 1:
if (y >= 64) {
return;
}
case 2:
if (y >= 128) {
return;
}
default:
break;
}
video->p->gx.renderer->getScanline(video->p->gx.renderer, y, &pixelsA);
/*if (DSRegisterDISPCAPCNTIsSourceA(dispcap)) {
// TODO: Process scanline regardless of output type
video->p->gx.renderer->getScanline(video->p->gx.renderer, y, &pixelsA);
} else {
size_t stride;
const void* pixels;
video->renderer->getPixels(video->renderer, &stride, &pixels);
pixelsA = &((const color_t*) pixels)[stride * y];
}*/
uint16_t pixel;
int x;
// TODO: Blending
for (x = 0; x < width; ++x) {
color_t colorA = pixelsA[x];
#ifdef COLOR_16_BIT
#ifdef COLOR_5_6_5
pixel = colorA & 0x1F;
pixel |= (colorA & 0xFFC0) >> 1;
#else
pixel = colorA;
#endif
#else
pixel = (colorA >> 9) & 0x7C00;
pixel |= (colorA >> 6) & 0x03E0;
pixel |= (colorA >> 3) & 0x001F;
#endif
STORE_16(pixel, (x + y * DS_VIDEO_HORIZONTAL_PIXELS) * 2, vram);
}
}
void _startHdraw7(struct mTiming* timing, void* context, uint32_t cyclesLate) { void _startHdraw7(struct mTiming* timing, void* context, uint32_t cyclesLate) {
struct DSVideo* video = context; struct DSVideo* video = context;
GBARegisterDISPSTAT dispstat = video->p->ds7.memory.io[DS_REG_DISPSTAT >> 1]; GBARegisterDISPSTAT dispstat = video->p->ds7.memory.io[DS_REG_DISPSTAT >> 1];
@ -285,9 +345,11 @@ void _startHdraw9(struct mTiming* timing, void* context, uint32_t cyclesLate) {
switch (video->vcount) { switch (video->vcount) {
case 0: case 0:
DSFrameStarted(video->p); DSFrameStarted(video->p);
video->inCapture = DSRegisterDISPCAPCNTIsEnable(video->p->ds9.memory.io[DS9_REG_DISPCAPCNT_HI >> 1] << 16);
break; break;
case DS_VIDEO_VERTICAL_PIXELS: case DS_VIDEO_VERTICAL_PIXELS:
video->p->ds9.memory.io[DS_REG_DISPSTAT >> 1] = GBARegisterDISPSTATFillInVblank(dispstat); video->p->ds9.memory.io[DS_REG_DISPSTAT >> 1] = GBARegisterDISPSTATFillInVblank(dispstat);
video->p->ds9.memory.io[DS9_REG_DISPCAPCNT_HI >> 1] = DSRegisterDISPCAPCNTClearEnable(video->p->ds9.memory.io[DS9_REG_DISPCAPCNT_HI >> 1] << 16) >> 16;
if (video->frameskipCounter <= 0) { if (video->frameskipCounter <= 0) {
video->renderer->finishFrame(video->renderer); video->renderer->finishFrame(video->renderer);
DSGXFlush(&video->p->gx); DSGXFlush(&video->p->gx);
@ -329,6 +391,9 @@ void _startHblank9(struct mTiming* timing, void* context, uint32_t cyclesLate) {
video->p->gx.renderer->drawScanline(video->p->gx.renderer, video->vcount + 48 - DS_VIDEO_VERTICAL_TOTAL_PIXELS); video->p->gx.renderer->drawScanline(video->p->gx.renderer, video->vcount + 48 - DS_VIDEO_VERTICAL_TOTAL_PIXELS);
} }
} }
if (video->inCapture) {
_performCapture(video, video->vcount);
}
if (GBARegisterDISPSTATIsHblankIRQ(dispstat)) { if (GBARegisterDISPSTATIsHblankIRQ(dispstat)) {
DSRaiseIRQ(video->p->ds9.cpu, video->p->ds9.memory.io, DS_IRQ_HBLANK); DSRaiseIRQ(video->p->ds9.cpu, video->p->ds9.memory.io, DS_IRQ_HBLANK);