mirror of https://github.com/mgba-emu/mgba.git
DS Video: Start implementing capture
This commit is contained in:
parent
830921a14c
commit
6103d49697
|
@ -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];
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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];
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue