reworked palette and buffer handling due to some 32X bugs

This commit is contained in:
kub 2019-03-22 23:03:26 +01:00
parent 23eef37f25
commit b1a047c926
13 changed files with 236 additions and 130 deletions

View file

@ -11,6 +11,9 @@ int (*PicoScan32xBegin)(unsigned int num);
int (*PicoScan32xEnd)(unsigned int num);
int Pico32xDrawMode;
void *DrawLineDestBase32x;
int DrawLineDestIncrement32x;
static void convert_pal555(int invert_prio)
{
unsigned int *ps = (void *)Pico32xMem->pal;
@ -228,13 +231,11 @@ void PicoDraw32xLayer(int offs, int lines, int md_bg)
int lines_sft_offs;
int which_func;
Pico.est.DrawLineDest = (char *)DrawLineDestBase + offs * DrawLineDestIncrement;
Pico.est.DrawLineDest = (char *)DrawLineDestBase32x + offs * DrawLineDestIncrement32x;
dram = Pico32xMem->dram[Pico32x.vdp_regs[0x0a/2] & P32XV_FS];
if (Pico32xDrawMode == PDM32X_BOTH) {
if (Pico.m.dirtyPal)
PicoDrawUpdateHighPal();
}
if (Pico32xDrawMode == PDM32X_BOTH)
PicoDrawUpdateHighPal();
if ((Pico32x.vdp_regs[0] & P32XV_Mx) == 2)
{
@ -273,20 +274,21 @@ do_it:
void PicoDraw32xLayerMdOnly(int offs, int lines)
{
int have_scan = PicoScan32xBegin != NULL && PicoScan32xEnd != NULL;
unsigned short *dst = (void *)((char *)DrawLineDestBase + offs * DrawLineDestIncrement);
unsigned short *dst = (void *)((char *)DrawLineDestBase32x + offs * DrawLineDestIncrement32x);
unsigned char *pmd = Pico.est.Draw2FB + 328 * offs + 8;
unsigned short *pal = Pico.est.HighPal;
int poffs = 0, plen = 320;
int l, p;
if (!(Pico.video.reg[12] & 1)) {
// 32col mode
// 32col mode. for some render modes MD pixel data carries an offset
if (!(PicoIn.opt & (POPT_ALT_RENDERER|POPT_DIS_32C_BORDER)))
pmd += 32;
poffs = 32;
plen = 256;
}
if (Pico.m.dirtyPal)
PicoDrawUpdateHighPal();
PicoDrawUpdateHighPal();
dst += poffs;
for (l = 0; l < lines; l++) {
@ -300,7 +302,7 @@ void PicoDraw32xLayerMdOnly(int offs, int lines)
dst[p + 2] = pal[*pmd++];
dst[p + 3] = pal[*pmd++];
}
dst = (void *)((char *)dst + DrawLineDestIncrement);
dst = (void *)((char *)dst + DrawLineDestIncrement32x);
pmd += 328 - plen;
if (have_scan)
PicoScan32xEnd(l + offs);
@ -314,16 +316,32 @@ void PicoDrawSetOutFormat32x(pdso_t which, int use_32x_line_mode)
Pico32xNativePal = Pico32xMem->pal_native;
#endif
if (which == PDF_RGB555 && use_32x_line_mode) {
// we'll draw via FinalizeLine32xRGB555 (rare)
if (which == PDF_RGB555) {
// need CLUT pixels in PicoDraw2FB for layer transparency
PicoDrawSetInternalBuf(Pico.est.Draw2FB, 328);
PicoDrawSetOutBufMD(DrawLineDestBase32x, DrawLineDestIncrement32x);
} else {
// use the same layout as alt renderer
PicoDrawSetInternalBuf(NULL, 0);
Pico32xDrawMode = PDM32X_OFF;
return;
PicoDrawSetOutBufMD(Pico.est.Draw2FB + 8, 328);
}
// use the same layout as alt renderer
PicoDrawSetInternalBuf(Pico.est.Draw2FB, 328);
Pico32xDrawMode = (which == PDF_RGB555) ? PDM32X_32X_ONLY : PDM32X_BOTH;
if (use_32x_line_mode)
// we'll draw via FinalizeLine32xRGB555 (rare)
Pico32xDrawMode = PDM32X_OFF;
else
// in RGB555 mode the 32x layer is drawn over the MD layer, in the other
// modes 32x and MD layer are merged together by the 32x renderer
Pico32xDrawMode = (which == PDF_RGB555) ? PDM32X_32X_ONLY : PDM32X_BOTH;
}
void PicoDrawSetOutBuf32X(void *dest, int increment)
{
DrawLineDestBase32x = dest;
DrawLineDestIncrement32x = increment;
// in RGB555 mode this buffer is also used by the MD renderer
if (Pico32xDrawMode != PDM32X_BOTH)
PicoDrawSetOutBufMD(DrawLineDestBase32x, DrawLineDestIncrement32x);
}
// vim:shiftwidth=2:ts=2:expandtab

View file

@ -1239,6 +1239,49 @@ void BackFill(int reg7, int sh, struct PicoEState *est)
// --------------------------------------------
void PicoDoHighPal555_8bit(int sh, int line, struct PicoEState *est)
{
unsigned int *spal, *dpal;
unsigned int cnt = (sh ? 1 : est->SonicPalCount+1);
unsigned int t, i;
// reset dirty only if there are no outstanding changes
if (Pico.m.dirtyPal == 2)
Pico.m.dirtyPal = 0;
// In Sonic render mode palettes were backuped in SonicPal
spal = (void *)est->SonicPal;
dpal = (void *)est->HighPal;
// additional palettes stored after in-frame changes
for (i = 0; i < cnt * 0x40 / 2; i++) {
t = spal[i];
#ifdef USE_BGR555
t = ((t & 0x000e000e)<< 1) | ((t & 0x00e000e0)<<3) | ((t & 0x0e000e00)<<4);
#else
t = ((t & 0x000e000e)<<12) | ((t & 0x00e000e0)<<3) | ((t & 0x0e000e00)>>7);
#endif
// treat it like it was 4-bit per channel, since in s/h mode it somewhat is that.
// otherwise intensity difference between this and s/h will be wrong
t |= (t >> 4) & 0x08610861; // 0x18e318e3
dpal[i] = t;
}
// norm: xxx0, sh: 0xxx, hi: 0xxx + 7
if (sh)
{
// shadowed pixels
for (i = 0; i < 0x40 / 2; i++)
dpal[0x40/2 | i] = dpal[0xc0/2 | i] = (dpal[i] >> 1) & 0x738e738e;
// hilighted pixels
for (i = 0; i < 0x40 / 2; i++) {
t = ((dpal[i] >> 1) & 0x738e738e) + 0x738e738e; // 0x7bef7bef;
t |= (t >> 4) & 0x08610861;
dpal[0x80/2 | i] = t;
}
}
}
#ifndef _ASM_DRAW_C
void PicoDoHighPal555(int sh, int line, struct PicoEState *est)
{
@ -1285,8 +1328,7 @@ void FinalizeLine555(int sh, int line, struct PicoEState *est)
unsigned short *pal=est->HighPal;
int len;
if (Pico.m.dirtyPal)
PicoDoHighPal555(sh, line, est);
PicoDrawUpdateHighPal();
if (Pico.video.reg[12]&1) {
len = 320;
@ -1315,22 +1357,21 @@ void FinalizeLine555(int sh, int line, struct PicoEState *est)
static void FinalizeLine8bit(int sh, int line, struct PicoEState *est)
{
unsigned char *pd = est->DrawLineDest;
int len, rs = est->rendstatus;
static int dirty_count;
int len;
static int dirty_line;
if (!sh && Pico.m.dirtyPal == 1)
if (Pico.m.dirtyPal == 1)
{
// a hack for mid-frame palette changes
if (!(rs & PDRAW_SONIC_MODE))
dirty_count = 1;
else dirty_count++;
rs |= PDRAW_SONIC_MODE;
est->rendstatus = rs;
if (dirty_count == 3) {
blockcpy(est->HighPal, PicoMem.cram, 0x40*2);
} else if (dirty_count == 11) {
blockcpy(est->HighPal+0x40, PicoMem.cram, 0x40*2);
if (!(est->rendstatus & PDRAW_SONIC_MODE) || line - dirty_line > 4) {
// store a maximum of 3 additional palettes in SonicPal
if (est->SonicPalCount < 3)
est->SonicPalCount ++;
dirty_line = line;
est->rendstatus |= PDRAW_SONIC_MODE;
}
blockcpy(est->SonicPal+est->SonicPalCount*0x40, PicoMem.cram, 0x40*2);
Pico.m.dirtyPal = 2;
}
if (Pico.video.reg[12]&1) {
@ -1341,12 +1382,9 @@ static void FinalizeLine8bit(int sh, int line, struct PicoEState *est)
len = 256;
}
if (!sh && (rs & PDRAW_SONIC_MODE)) {
if (dirty_count >= 11) {
blockcpy_or(pd, est->HighCol+8, len, 0x80);
} else {
blockcpy_or(pd, est->HighCol+8, len, 0x40);
}
if (!sh && (est->rendstatus & PDRAW_SONIC_MODE)) {
// select active backup palette
blockcpy_or(pd, est->HighCol+8, len, est->SonicPalCount*0x40);
} else {
blockcpy(pd, est->HighCol+8, len);
}
@ -1478,6 +1516,7 @@ static int DrawDisplay(int sh)
PICO_INTERNAL void PicoFrameStart(void)
{
int offs = 8, lines = 224;
int dirty = ((Pico.est.rendstatus & PDRAW_SONIC_MODE) || Pico.m.dirtyPal);
// prepare to do this frame
Pico.est.rendstatus = 0;
@ -1503,11 +1542,16 @@ PICO_INTERNAL void PicoFrameStart(void)
Pico.est.DrawScanline = 0;
skip_next_line = 0;
if (FinalizeLine == FinalizeLine8bit) {
// make a backup of the current palette in case Sonic mode is detected later
Pico.est.SonicPalCount = 0;
Pico.m.dirtyPal = (dirty ? 2 : 0); // mark as dirty but already copied
blockcpy(Pico.est.SonicPal, PicoMem.cram, 0x40*2);
}
if (PicoIn.opt & POPT_ALT_RENDERER)
return;
if (Pico.m.dirtyPal)
Pico.m.dirtyPal = 2; // reset dirty if needed
PrepareSprites(1);
}
@ -1598,15 +1642,21 @@ void PicoDrawSync(int to, int blank_last_line)
void PicoDrawUpdateHighPal(void)
{
struct PicoEState *est = &Pico.est;
int sh = (Pico.video.reg[0xC] & 8) >> 3; // shadow/hilight?
if (PicoIn.opt & POPT_ALT_RENDERER)
sh = 0; // no s/h support
if (Pico.m.dirtyPal) {
int sh = (Pico.video.reg[0xC] & 8) >> 3; // shadow/hilight?
if ((PicoIn.opt & POPT_ALT_RENDERER) | (est->rendstatus & PDRAW_SONIC_MODE))
sh = 0; // no s/h support
PicoDoHighPal555(sh, 0, &Pico.est);
if (est->rendstatus & PDRAW_SONIC_MODE) {
// FIXME?
memcpy(est->HighPal + 0x40, est->HighPal, 0x40*2);
memcpy(est->HighPal + 0x80, est->HighPal, 0x40*2);
if (FinalizeLine == FinalizeLine8bit)
PicoDoHighPal555_8bit(sh, 0, est);
else
PicoDoHighPal555(sh, 0, est);
// cover for sprite priority bits if not in s/h or sonic mode
if (!sh && !(est->rendstatus & PDRAW_SONIC_MODE)) {
blockcpy(est->HighPal+0x40, est->HighPal, 0x40*2);
blockcpy(est->HighPal+0x80, est->HighPal, 0x80*2);
}
}
}
@ -1629,17 +1679,33 @@ void PicoDrawSetOutFormat(pdso_t which, int use_32x_line_mode)
FinalizeLine = NULL;
break;
}
PicoDrawSetOutFormat32x(which, use_32x_line_mode);
if (PicoIn.AHW & PAHW_32X)
PicoDrawSetOutFormat32x(which, use_32x_line_mode);
PicoDrawSetOutputMode4(which);
rendstatus_old = -1;
}
void PicoDrawSetOutBufMD(void *dest, int increment)
{
if (dest != NULL) {
DrawLineDestBase = dest;
DrawLineDestIncrement = increment;
Pico.est.DrawLineDest = DrawLineDestBase + Pico.est.DrawScanline * increment;
}
else {
DrawLineDestBase = DefOutBuff;
DrawLineDestIncrement = 0;
Pico.est.DrawLineDest = DefOutBuff;
}
}
// note: may be called on the middle of frame
void PicoDrawSetOutBuf(void *dest, int increment)
{
DrawLineDestBase = dest;
DrawLineDestIncrement = increment;
Pico.est.DrawLineDest = (char *)DrawLineDestBase + Pico.est.DrawScanline * increment;
if (PicoIn.AHW & PAHW_32X)
PicoDrawSetOutBuf32X(dest, increment);
else
PicoDrawSetOutBufMD(dest, increment);
}
void PicoDrawSetInternalBuf(void *dest, int increment)
@ -1652,6 +1718,7 @@ void PicoDrawSetInternalBuf(void *dest, int increment)
else {
HighColBase = DefHighCol;
HighColIncrement = 0;
Pico.est.HighCol = DefHighCol;
}
}

View file

@ -1498,11 +1498,9 @@ vidConvCpyRGB565: @ void *to, void *from, int pixels
PicoDoHighPal555:
stmfd sp!, {r4-r10,lr}
mov r10,r2 @ est
mov r1, #0
ldr r8, [r10, #OFS_EST_Pico]
PicoDoHighPal555_nopush:
orr r9, r1, r0, lsl #31 @ 0:called from FinalizeLine555, 31: s/h
mov r9, r0
add r0, r10, #OFS_EST_HighPal
@ -1517,7 +1515,7 @@ PicoDoHighPal555_nopush:
vidConvCpyRGB565_local
tst r9, #(1<<31)
cmp r9, #0
beq PicoDoHighPal555_end
add r3, r10, #OFS_EST_HighPal
@ -1560,11 +1558,7 @@ PicoDoHighPal555_nopush:
mov r0, #1
PicoDoHighPal555_end:
tst r9, #1
ldmeqfd sp!, {r4-r10,pc}
ldr r8, [r10, #OFS_EST_Pico]
b FinalizeLineRGB555_pal_done
ldmfd sp!, {r4-r10,pc}
@ void FinalizeLine555(int sh, int line, struct PicoEState *est)
@ -1576,19 +1570,11 @@ FinalizeLine555:
mov r10,r2 @ est
ldr r8, [r10, #OFS_EST_Pico]
ldrb r2, [r8, #OFS_Pico_m_dirtyPal]
mov r1, #1
tst r2, r2
bne PicoDoHighPal555_nopush
bl PicoDrawUpdateHighPal
FinalizeLineRGB555_pal_done:
add r3, r10, #OFS_EST_HighPal
ldr r12, [r10, #OFS_EST_rendstatus]
eors r0, r0, #1 @ sh is 0
mov lr, #0xff
tstne r12,#PDRAW_ACC_SPRITES
movne lr, #0x3f
ldr r1, [r10, #OFS_EST_HighCol]
ldr r0, [r10, #OFS_EST_DrawLineDest]

View file

@ -356,6 +356,8 @@ struct PicoEState
unsigned int *PicoOpt;
unsigned char *Draw2FB;
unsigned short HighPal[0x100];
unsigned short SonicPal[0x100];
int SonicPalCount;
};
struct PicoMem
@ -923,6 +925,7 @@ void p32x_sh2_poll_event(SH2 *sh2, unsigned int flags, unsigned int m68k_cycles)
// 32x/draw.c
void PicoDrawSetOutFormat32x(pdso_t which, int use_32x_line_mode);
void PicoDrawSetOutBuf32X(void *dest, int increment);
void FinalizeLine32xRGB555(int sh, int line, struct PicoEState *est);
void PicoDraw32xLayer(int offs, int lines, int mdbg);
void PicoDraw32xLayerMdOnly(int offs, int lines);

View file

@ -41,7 +41,7 @@ static void VideoWrite(u16 d)
if (a - ((unsigned)(Pico.video.reg[5]&0x7f) << 9) < 0x400)
Pico.est.rendstatus |= PDRAW_DIRTY_SPRITES;
break;
case 3: Pico.m.dirtyPal = 1;
case 3: if (PicoMem.cram [(a >> 1) & 0x3f] != d) Pico.m.dirtyPal = 1;
PicoMem.cram [(a >> 1) & 0x3f] = d; break;
case 5: PicoMem.vsram[(a >> 1) & 0x3f] = d; break;
case 0x81:
@ -441,7 +441,7 @@ PICO_INTERNAL_ASM void PicoVideoWrite(unsigned int a,unsigned short d)
break;
case 0x0c:
// renderers should update their palettes if sh/hi mode is changed
if ((d^dold)&8) Pico.m.dirtyPal = 2;
if ((d^dold)&8) Pico.m.dirtyPal = 1;
break;
}
return;