From b2c22c9f4a11b519b11816de04fa7961e2cc3d18 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 6 Nov 2022 23:54:36 +0100 Subject: [PATCH] Added Voodoo Banshee/3 YUV -> 16/24/32-bit RGB blits, fixes #2246. --- src/video/vid_voodoo_banshee_blitter.c | 143 ++++++++++++++++++++++++- 1 file changed, 138 insertions(+), 5 deletions(-) diff --git a/src/video/vid_voodoo_banshee_blitter.c b/src/video/vid_voodoo_banshee_blitter.c index 8a9b24337..ed1b57e63 100644 --- a/src/video/vid_voodoo_banshee_blitter.c +++ b/src/video/vid_voodoo_banshee_blitter.c @@ -1,6 +1,6 @@ /*Current issues : - missing screen->screen scaled blits with format conversion - - missing YUV blits + - missing YUV blits (YUV -> 32-bit, 24-bit, or 16-bit RGB now done) - missing linestyle - missing wait for vsync - missing reversible lines @@ -303,6 +303,7 @@ update_src_stride(voodoo_t *voodoo) bpp = 24; break; case SRC_FORMAT_COL_32_BPP: + case SRC_FORMAT_COL_YUYV: bpp = 32; break; @@ -399,6 +400,86 @@ banshee_do_rectfill(voodoo_t *voodoo) end_command(voodoo); } +void DECODE_YUYV422(uint32_t *buf, uint8_t *src) +{ + do { + int wp = 0; + + uint8_t y1, y2; + int8_t Cr, Cb; + int dR, dG, dB; + int r, g, b; + + y1 = src[0]; + Cr = src[1] - 0x80; + y2 = src[2]; + Cb = src[3] - 0x80; + + dR = (359 * Cr) >> 8; + dG = (88 * Cb + 183 * Cr) >> 8; + dB = (453 * Cb) >> 8; + + r = y1 + dR; + r = CLAMP(r); + g = y1 - dG; + g = CLAMP(g); + b = y1 + dB; + b = CLAMP(b); + buf[wp++] = r | (g << 8) | (b << 16); + + r = y2 + dR; + r = CLAMP(r); + g = y2 - dG; + g = CLAMP(g); + b = y2 + dB; + b = CLAMP(b); + buf[wp++] = r | (g << 8) | (b << 16); + } while (0); +} + +void DECODE_YUYV422_16BPP(uint16_t *buf, uint8_t *src) +{ + do { + int wp = 0; + + uint8_t y1, y2; + int8_t Cr, Cb; + int dR, dG, dB; + int r, g, b; + + y1 = src[0]; + Cr = src[1] - 0x80; + y2 = src[2]; + Cb = src[3] - 0x80; + + dR = (359 * Cr) >> 8; + dG = (88 * Cb + 183 * Cr) >> 8; + dB = (453 * Cb) >> 8; + + r = y1 + dR; + r = CLAMP(r); + r >>= 3; + g = y1 - dG; + g = CLAMP(g); + g >>= 2; + b = y1 + dB; + b = CLAMP(b); + b >>= 3; + buf[wp++] = r | (g << 5) | (b << 11); + + r = y2 + dR; + r = CLAMP(r); + r >>= 3; + g = y2 - dG; + g = CLAMP(g); + g >>= 2; + b = y2 + dB; + b = CLAMP(b); + b >>= 3; + buf[wp++] = r | (g << 5) | (b << 11); + } while (0); +} + static void do_screen_to_screen_line(voodoo_t *voodoo, uint8_t *src_p, int use_x_dir, int src_x, int src_tiled) { @@ -513,8 +594,9 @@ do_screen_to_screen_line(voodoo_t *voodoo, uint8_t *src_p, int use_x_dir, int sr src_x_real = (src_x_real & 127) + ((src_x_real >> 7) * 128 * 32); if (dst_x >= clip->x_min && dst_x < clip->x_max && pattern_trans) { - uint32_t src_data = 0; - int transparent = 0; + uint32_t src_data = 0; + uint32_t src_data_yuv = 0; /* Used in YUYV-to-RGB convesions. */ + int transparent = 0; switch (voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) { case SRC_FORMAT_COL_1_BPP: @@ -554,6 +636,11 @@ do_screen_to_screen_line(voodoo_t *voodoo, uint8_t *src_p, int use_x_dir, int sr src_data = *(uint32_t *) &src_p[src_x_real]; break; } + case SRC_FORMAT_COL_YUYV: + { + src_data_yuv = *(uint32_t *) &src_p[src_x_real]; + break; + } default: fatal("banshee_do_screen_to_screen_blt: unknown srcFormat %08x\n", voodoo->banshee_blt.srcFormat); @@ -567,9 +654,54 @@ do_screen_to_screen_line(voodoo_t *voodoo, uint8_t *src_p, int use_x_dir, int sr src_data = (b >> 3) | ((g >> 2) << 5) | ((r >> 3) << 11); } - if (!transparent) - PLOT(voodoo, dst_x, dst_y, pat_x, pat_y, pattern_mask, rop, src_data, src_colorkey); + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_YUYV) { + if (((voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK) == DST_FORMAT_COL_24_BPP) || + ((voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK) == DST_FORMAT_COL_32_BPP)) { + uint32_t rgbcol[2] = { 0, 0 }; + DECODE_YUYV422(rgbcol, (uint8_t *) &src_data_yuv); + + bansheeblt_log("YUV -> 24 bpp or 32 bpp\n"); + + if (!transparent) { + PLOT(voodoo, dst_x, dst_y, pat_x, pat_y, pattern_mask, rop, rgbcol[0], src_colorkey); + } + + if (use_x_dir) { + dst_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + } else { + dst_x++; + } + + if (!transparent) { + PLOT(voodoo, dst_x, dst_y, pat_x, pat_y, pattern_mask, rop, rgbcol[1], src_colorkey); + } + } else if ((voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK) == DST_FORMAT_COL_16_BPP) { + uint32_t rgbcol = 0; + DECODE_YUYV422_16BPP((uint16_t *) &rgbcol, (uint8_t *) &src_data_yuv); + + bansheeblt_log("YUV -> 16 bpp\n"); + + if (!transparent) { + PLOT(voodoo, dst_x, dst_y, pat_x, pat_y, pattern_mask, rop, rgbcol & 0xffff, src_colorkey); + } + + if (use_x_dir) { + dst_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + } else { + dst_x++; + } + + if (!transparent) { + PLOT(voodoo, dst_x, dst_y, pat_x, pat_y, pattern_mask, rop, rgbcol >> 16, src_colorkey); + } + } else + fatal("banshee_do_screen_to_screen_blt: unknown dstFormat %08x\n", voodoo->banshee_blt.dstFormat); + } else { + if (!transparent) + PLOT(voodoo, dst_x, dst_y, pat_x, pat_y, pattern_mask, rop, src_data, src_colorkey); + } } + if (use_x_dir) { src_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; dst_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; @@ -1183,6 +1315,7 @@ voodoo_2d_reg_writel(voodoo_t *voodoo, uint32_t addr, uint32_t val) voodoo->banshee_blt.src_bpp = 24; break; case SRC_FORMAT_COL_32_BPP: + case SRC_FORMAT_COL_YUYV: voodoo->banshee_blt.src_bpp = 32; break; case SRC_FORMAT_COL_16_BPP: