This commit is contained in:
2026-06-21 17:16:17 -05:00
parent f41ebd69b4
commit 16c27e0124
2 changed files with 58 additions and 11 deletions
+24 -1
View File
@@ -25,12 +25,29 @@ errorret_t displaySaturnInit(void) {
VDP2_TVMD_HORZ_NORMAL_A,
VDP2_TVMD_VERT_224
);
vdp2_tvmd_display_set();
/* Back-screen color shown where no VDP1/VDP2 plane draws a pixel.
* MSB=1 so VDP2 treats it as direct RGB in mixed-color mode. */
vdp2_scrn_back_color_set(
VDP2_VRAM_ADDR(3, 0x01FFFE),
RGB1555(1, 0, 3, 15)
);
/* Sprite priority 0 → invisible in VDP2. Set slot 0 to priority 6 so
* VDP1 pixels are composited above the back-screen. */
vdp2_sprite_priority_set(0, 6);
/* Disable all NBG/RBG scroll planes; game content drawn entirely via VDP1. */
vdp2_scrn_display_set(VDP2_SCRN_DISP_NONE);
vdp2_tvmd_display_set();
errorChain(renderSaturnInit());
/* Commit all VDP2 shadow registers to hardware before the first frame. */
vdp2_sync();
vdp2_sync_wait();
errorOk();
}
@@ -45,6 +62,12 @@ errorret_t displaySaturnSwap(void) {
vdp1_sync();
vdp2_sync();
vdp2_sync_wait();
/* Wait for VDP1's VBlank-OUT handler to complete. In auto mode VDP1 begins
* rendering at VBlank-IN; vdp2_sync_wait() returns shortly after that point,
* while VDP1 is still reading from VDP1 VRAM. vdp1_sync_wait() blocks until
* VBlank-OUT, by which time VDP1 has finished and swapped framebuffers. This
* prevents the next frame's DMA from overwriting VDP1 VRAM mid-render. */
vdp1_sync_wait();
DISPLAY.whichBuffer ^= 1;
errorOk();
}
+34 -10
View File
@@ -85,6 +85,16 @@ _Static_assert(sizeof(saturncmd_t) == sizeof(vdp1_cmdt_t),
#define SATURNCMD_PMOD_RGB_DIRECT (5u << 3) /* RGB1555 in COLR, no palette */
#define SATURNCMD_PMOD_SPD (0x0040u) /* do not skip index 0 */
#define SATURNCMD_PMOD_ECD (0x0080u) /* end-code disable */
/* Bit 15 of PMOD: forces the MSB of every pixel written to the VDP1 framebuffer
* to 1. In VDP2 mixed-color mode (SPCLMD=1, set by vdp1_env_default_set), a
* framebuffer pixel with MSB=1 is treated as a direct RGB555 color; MSB=0 is a
* CRAM palette index. Always set this for direct-color drawing. */
#define SATURNCMD_PMOD_MSB (0x8000u)
/* Last 16-word-aligned CRAM slot (word 2032 of 2048): reserved for the clear
* polygon color. Placed well above any texture palette range (max 8 × 256
* = 2048 words, but we only have a handful of textures in practice). */
#define SATURN_CLEAR_CRAM_ADDR (0x07F0u)
/* ---- Texture table ------------------------------------------------------- */
@@ -118,15 +128,23 @@ static float saturnViewTgtX = 0.0f, saturnViewTgtY = 0.0f, saturnViewTgtZ = 0.0f
/* ---- Helpers ------------------------------------------------------------- */
/* Convert color_t RGBA → VDP1/VDP2 RGB1555. */
/* Convert color_t RGBA → VDP1/VDP2 RGB1555 (no MSB).
* Saturn RGB1555: bit[15]=MSB, bits[14:10]=R, bits[9:5]=G, bits[4:0]=B. */
static uint16_t toRGB1555(color_t c) {
return (uint16_t)(
((uint16_t)(c.b >> 3) << 10) |
((uint16_t)(c.r >> 3) << 10) |
((uint16_t)(c.g >> 3) << 5) |
((uint16_t)(c.r >> 3))
((uint16_t)(c.b >> 3))
);
}
/* Convert color_t → RGB1555 with bit[15]=1 (direct-color flag).
* For VDP1 polygon CMDCOLR: bit[15]=1 tells VDP1 to use the color as direct
* RGB555 rather than a CRAM palette index. */
static uint16_t toRGB1555Direct(color_t c) {
return 0x8000u | toRGB1555(c);
}
/* Write palette into VDP2 CRAM at the texture's slot.
* CRAM is mapped at 0x25F00000. Each 256-entry slot = 512 bytes. */
static void uploadPalette(saturntexentry_t *e) {
@@ -368,8 +386,8 @@ errorret_t renderSaturnFlush(ropbuffer_t *buf) {
sc = &saturnCmdBuf[0];
memoryZero(sc, sizeof(saturncmd_t));
sc->ctrl = SATURNCMD_CTRL_SYSCLIP;
sc->xb = (int16_t)(DUSK_DISPLAY_WIDTH - 1);
sc->yb = (int16_t)(DUSK_DISPLAY_HEIGHT - 1);
sc->xc = (int16_t)(DUSK_DISPLAY_WIDTH - 1);
sc->yc = (int16_t)(DUSK_DISPLAY_HEIGHT - 1);
/* [1] User clip mirrors full screen; disabled per-command by default. */
sc = &saturnCmdBuf[1];
@@ -394,14 +412,20 @@ errorret_t renderSaturnFlush(ropbuffer_t *buf) {
switch(op) {
case ROP_CLEAR: {
const ropclear_t *c = (const ropclear_t *)hdr;
/* Fill the entire screen with a solid RGB polygon.
* RGB direct mode (PMOD = SATURNCMD_PMOD_RGB_DIRECT) places the
* RGB1555 color in COLR directly — no palette lookup required. */
/* VDP1 polygon CM=0: CMDCOLR is a CRAM word address (16-aligned),
* not a direct color value. Write the desired RGB1555 color into our
* reserved CRAM slot so VDP1 reads it during rasterization.
* PMOD MSB_ENABLE then ORs bit[15]=1 into the framebuffer pixel so
* VDP2 (SPCLMD=1) treats it as direct RGB555 rather than a palette
* index. */
volatile uint16_t *cram = (volatile uint16_t *)0x25F00000;
cram[SATURN_CLEAR_CRAM_ADDR] = toRGB1555(c->color);
saturncmd_t *poly = allocCmd();
if(poly) {
poly->ctrl = SATURNCMD_CTRL_POLYGON;
poly->pmod = SATURNCMD_PMOD_RGB_DIRECT;
poly->colr = toRGB1555(c->color);
poly->pmod = SATURNCMD_PMOD_MSB | SATURNCMD_PMOD_ECD | SATURNCMD_PMOD_SPD;
poly->colr = SATURN_CLEAR_CRAM_ADDR;
poly->xa = 0;
poly->ya = 0;
poly->xb = (int16_t)(DUSK_DISPLAY_WIDTH - 1);