Merge pull request #5791 from Cacodemon345/voodoo3-overlay

YUV overlays on Voodoo 3/Banshee now display correctly
This commit is contained in:
Miran Grča
2025-07-13 14:18:41 +02:00
committed by GitHub
3 changed files with 417 additions and 115 deletions

View File

@@ -1262,11 +1262,6 @@ svga_do_render(svga_t *svga)
if (!svga->override) {
svga->render_line_offset = svga->start_retrace_latch - svga->crtc[0x4];
svga->render(svga);
svga->x_add = svga->left_overscan;
svga_render_overscan_left(svga);
svga_render_overscan_right(svga);
svga->x_add = svga->left_overscan - svga->scrollcache;
}
if (svga->overlay_on) {
@@ -1293,6 +1288,13 @@ svga_do_render(svga_t *svga)
if (svga->hwcursor_on && svga->interlace)
svga->hwcursor_on--;
}
if (!svga->override) {
svga->x_add = svga->left_overscan;
svga_render_overscan_left(svga);
svga_render_overscan_right(svga);
svga->x_add = svga->left_overscan - svga->scrollcache;
}
}
void

View File

@@ -18,6 +18,7 @@
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
@@ -121,6 +122,8 @@ typedef struct banshee_t {
uint32_t vidProcCfg;
uint32_t vidScreenSize;
uint32_t vidSerialParallelPort;
uint32_t vidChromaKeyMin;
uint32_t vidChromaKeyMax;
uint32_t agpReqSize;
uint32_t agpHostAddressHigh;
@@ -153,6 +156,8 @@ typedef struct banshee_t {
uint8_t pci_slot;
uint8_t irq_state;
bool chroma_key_enabled;
void *i2c, *i2c_ddc, *ddc;
} banshee_t;
@@ -186,6 +191,8 @@ enum {
Video_hwCurC0 = 0x68,
Video_hwCurC1 = 0x6c,
Video_vidSerialParallelPort = 0x78,
Video_vidChromaKeyMin = 0x8c,
Video_vidChromaKeyMax = 0x90,
Video_vidScreenSize = 0x98,
Video_vidOverlayStartCoords = 0x9c,
Video_vidOverlayEndScreenCoords = 0xa0,
@@ -946,6 +953,14 @@ banshee_ext_outl(uint16_t addr, uint32_t val, void *priv)
i2c_gpio_set(banshee->i2c, !!(val & VIDSERIAL_I2C_SCK_W), !!(val & VIDSERIAL_I2C_SDA_W));
break;
case Video_vidChromaKeyMin:
banshee->vidChromaKeyMin = val;
break;
case Video_vidChromaKeyMax:
banshee->vidChromaKeyMax = val;
break;
case Video_vidScreenSize:
banshee->vidScreenSize = val;
voodoo->h_disp = (val & 0xfff) + 1;
@@ -1253,6 +1268,12 @@ banshee_ext_inl(uint16_t addr, void *priv)
#endif
break;
case Video_vidChromaKeyMin:
ret = banshee->vidChromaKeyMin;
break;
case Video_vidChromaKeyMax:
ret = banshee->vidChromaKeyMax;
break;
case Video_vidScreenSize:
ret = banshee->vidScreenSize;
break;
@@ -2634,12 +2655,97 @@ voodoo_generate_vb_filters(voodoo_t *voodoo, int fcr, int fcg)
}
}
/* 1 = render overlay, 0 = render desktop */
static bool
banshee_chroma_key(banshee_t* banshee, uint32_t x, uint32_t y)
{
uint32_t src_addr_desktop = banshee->desktop_addr + y * (banshee->vidDesktopOverlayStride & 0x3fff);
bool res = true;
uint8_t chromaKeyMaxIndex = banshee->vidChromaKeyMax & 0xff;
uint8_t chromaKeyMinIndex = banshee->vidChromaKeyMin & 0xff;
uint32_t desktop_pixel = 0;
uint8_t desktop_r = 0;
uint8_t desktop_g = 0;
uint8_t desktop_b = 0;
uint32_t prev_desktop_y = banshee->desktop_y - 1;
if (!banshee->chroma_key_enabled)
return true;
if (y > 2048)
return true;
if (!(banshee->vidProcCfg & (1 << 5))) {
return true;
}
switch (VIDPROCCFG_DESKTOP_PIX_FORMAT) {
case PIX_FORMAT_8:
{
desktop_pixel = banshee->svga.vram[src_addr_desktop + x];
res = (desktop_pixel & 0xFF) >= chromaKeyMinIndex && (desktop_pixel & 0xFF) <= chromaKeyMaxIndex;
break;
}
case PIX_FORMAT_RGB565:
{
if (banshee->vidProcCfg & VIDPROCCFG_DESKTOP_TILE) {
uint32_t addr = 0;
if (prev_desktop_y & 0x80000000)
return false;
if (banshee->vidProcCfg & VIDPROCCFG_HALF_MODE)
addr = banshee->desktop_addr + ((prev_desktop_y >> 1) & 31) * 128 + ((prev_desktop_y >> 6) * banshee->desktop_stride_tiled);
else
addr = banshee->desktop_addr + (prev_desktop_y & 31) * 128 + ((prev_desktop_y >> 5) * banshee->desktop_stride_tiled);
addr += 128 * 32 * (x >> 6);
addr += (x & 63) * 2;
desktop_pixel = *(uint16_t*)&banshee->svga.vram[addr & banshee->svga.vram_mask];
} else {
desktop_pixel = *(uint16_t*)&banshee->svga.vram[(src_addr_desktop + x * 2) & banshee->svga.vram_mask];
}
desktop_r = (desktop_pixel & 0x1f);
desktop_g = (desktop_pixel & 0x7e0) >> 5;
desktop_b = (desktop_pixel & 0xf800) >> 11;
res = (desktop_r >= ((banshee->vidChromaKeyMin >> 11) & 0x1F) && desktop_r <= ((banshee->vidChromaKeyMax >> 11) & 0x1F)) &&
(desktop_g >= ((banshee->vidChromaKeyMin >> 5) & 0x3F) && desktop_g <= ((banshee->vidChromaKeyMax >> 5) & 0x3F)) &&
(desktop_b >= ((banshee->vidChromaKeyMin) & 0x1F) && desktop_b <= ((banshee->vidChromaKeyMax) & 0x1F));
break;
}
case PIX_FORMAT_RGB24:
{
desktop_r = banshee->svga.vram[(src_addr_desktop + x * 3) & banshee->svga.vram_mask];
desktop_g = banshee->svga.vram[(src_addr_desktop + x * 3 + 1) & banshee->svga.vram_mask];
desktop_b = banshee->svga.vram[(src_addr_desktop + x * 3 + 2) & banshee->svga.vram_mask];
res = (desktop_r >= ((banshee->vidChromaKeyMin >> 16) & 0xFF) && desktop_r <= ((banshee->vidChromaKeyMax >> 16) & 0xFF)) &&
(desktop_g >= ((banshee->vidChromaKeyMin >> 8) & 0xFF) && desktop_g <= ((banshee->vidChromaKeyMax >> 8) & 0xFF)) &&
(desktop_b >= ((banshee->vidChromaKeyMin) & 0xFF) && desktop_b <= ((banshee->vidChromaKeyMax) & 0xFF));
break;
}
case PIX_FORMAT_RGB32:
{
desktop_r = banshee->svga.vram[(src_addr_desktop + x * 4) & banshee->svga.vram_mask];
desktop_g = banshee->svga.vram[(src_addr_desktop + x * 4 + 1) & banshee->svga.vram_mask];
desktop_b = banshee->svga.vram[(src_addr_desktop + x * 4 + 2) & banshee->svga.vram_mask];
res = (desktop_r >= ((banshee->vidChromaKeyMin >> 16) & 0xFF) && desktop_r <= ((banshee->vidChromaKeyMax >> 16) & 0xFF)) &&
(desktop_g >= ((banshee->vidChromaKeyMin >> 8) & 0xFF) && desktop_g <= ((banshee->vidChromaKeyMax >> 8) & 0xFF)) &&
(desktop_b >= ((banshee->vidChromaKeyMin) & 0xFF) && desktop_b <= ((banshee->vidChromaKeyMax) & 0xFF));
break;
}
}
res ^= !!(banshee->vidProcCfg & (1 << 6));
return res;
}
static void
banshee_overlay_draw(svga_t *svga, int displine)
{
banshee_t *banshee = (banshee_t *) svga->priv;
voodoo_t *voodoo = banshee->voodoo;
uint32_t *p;
bool chroma_test_passed = true;
int x;
int y = voodoo->overlay.src_y >> 20;
uint32_t src_addr = svga->overlay_latch.addr + ((banshee->vidProcCfg & VIDPROCCFG_OVERLAY_TILE) ? ((y & 31) * 128 + (y >> 5) * svga->overlay_latch.pitch) : y * svga->overlay_latch.pitch);
@@ -2654,6 +2760,8 @@ banshee_overlay_draw(svga_t *svga, int displine)
voodoo->overlay.src_y += (1 << 20);
return;
}
chroma_test_passed = banshee_chroma_key(banshee, svga->overlay_latch.x, displine - svga->y_add);
if ((voodoo->overlay.src_y >> 20) < 2048)
voodoo->dirty_line[voodoo->overlay.src_y >> 20] = 0;
@@ -2671,7 +2779,8 @@ banshee_overlay_draw(svga_t *svga, int displine)
if (skip_filtering) {
/*No scaling or filtering required, just write straight to output buffer*/
OVERLAY_SAMPLE(p);
if (chroma_test_passed)
OVERLAY_SAMPLE(p);
} else {
OVERLAY_SAMPLE(banshee->overlay_buffer[0]);
@@ -2688,25 +2797,31 @@ banshee_overlay_draw(svga_t *svga, int displine)
((0x10000 - x_coeff) * y_coeff) >> 16,
(x_coeff * y_coeff) >> 16
};
uint32_t samp0 = banshee->overlay_buffer[0][src_x >> 20];
uint32_t samp1 = banshee->overlay_buffer[0][(src_x >> 20) + 1];
uint32_t samp2 = banshee->overlay_buffer[1][src_x >> 20];
uint32_t samp3 = banshee->overlay_buffer[1][(src_x >> 20) + 1];
int r = (((samp0 >> 16) & 0xff) * coeffs[0] + ((samp1 >> 16) & 0xff) * coeffs[1] + ((samp2 >> 16) & 0xff) * coeffs[2] + ((samp3 >> 16) & 0xff) * coeffs[3]) >> 16;
int g = (((samp0 >> 8) & 0xff) * coeffs[0] + ((samp1 >> 8) & 0xff) * coeffs[1] + ((samp2 >> 8) & 0xff) * coeffs[2] + ((samp3 >> 8) & 0xff) * coeffs[3]) >> 16;
int b = ((samp0 & 0xff) * coeffs[0] + (samp1 & 0xff) * coeffs[1] + (samp2 & 0xff) * coeffs[2] + (samp3 & 0xff) * coeffs[3]) >> 16;
p[x] = (r << 16) | (g << 8) | b;
uint32_t samp0 = banshee->overlay_buffer[0][src_x >> 20];
uint32_t samp1 = banshee->overlay_buffer[0][(src_x >> 20) + 1];
uint32_t samp2 = banshee->overlay_buffer[1][src_x >> 20];
uint32_t samp3 = banshee->overlay_buffer[1][(src_x >> 20) + 1];
int r = (((samp0 >> 16) & 0xff) * coeffs[0] + ((samp1 >> 16) & 0xff) * coeffs[1] + ((samp2 >> 16) & 0xff) * coeffs[2] + ((samp3 >> 16) & 0xff) * coeffs[3]) >> 16;
int g = (((samp0 >> 8) & 0xff) * coeffs[0] + ((samp1 >> 8) & 0xff) * coeffs[1] + ((samp2 >> 8) & 0xff) * coeffs[2] + ((samp3 >> 8) & 0xff) * coeffs[3]) >> 16;
int b = ((samp0 & 0xff) * coeffs[0] + (samp1 & 0xff) * coeffs[1] + (samp2 & 0xff) * coeffs[2] + (samp3 & 0xff) * coeffs[3]) >> 16;
chroma_test_passed = banshee_chroma_key(banshee, svga->overlay_latch.x + x, displine - svga->y_add);
if (chroma_test_passed)
p[x] = (r << 16) | (g << 8) | b;
src_x += voodoo->overlay.vidOverlayDudx;
}
} else {
for (x = 0; x < svga->overlay_latch.cur_xsize; x++) {
uint32_t samp0 = banshee->overlay_buffer[0][src_x >> 20];
uint32_t samp1 = banshee->overlay_buffer[1][src_x >> 20];
int r = (((samp0 >> 16) & 0xff) * (0x10000 - y_coeff) + ((samp1 >> 16) & 0xff) * y_coeff) >> 16;
int g = (((samp0 >> 8) & 0xff) * (0x10000 - y_coeff) + ((samp1 >> 8) & 0xff) * y_coeff) >> 16;
int b = ((samp0 & 0xff) * (0x10000 - y_coeff) + (samp1 & 0xff) * y_coeff) >> 16;
p[x] = (r << 16) | (g << 8) | b;
uint32_t samp0 = banshee->overlay_buffer[0][src_x >> 20];
uint32_t samp1 = banshee->overlay_buffer[1][src_x >> 20];
int r = (((samp0 >> 16) & 0xff) * (0x10000 - y_coeff) + ((samp1 >> 16) & 0xff) * y_coeff) >> 16;
int g = (((samp0 >> 8) & 0xff) * (0x10000 - y_coeff) + ((samp1 >> 8) & 0xff) * y_coeff) >> 16;
int b = ((samp0 & 0xff) * (0x10000 - y_coeff) + (samp1 & 0xff) * y_coeff) >> 16;
chroma_test_passed = banshee_chroma_key(banshee, svga->overlay_latch.x + x, displine - svga->y_add);
if (chroma_test_passed)
p[x] = (r << 16) | (g << 8) | b;
}
}
break;
@@ -2761,21 +2876,30 @@ banshee_overlay_draw(svga_t *svga, int displine)
fil3[x * 3 + 2] = vb_filter_v1_rb[fil[x * 3 + 2]][fil[(x - 1) * 3 + 2]];
}
for (x = 0; x < svga->overlay_latch.cur_xsize; x++) {
fil[x * 3] = vb_filter_v1_rb[fil[x * 3]][fil3[(x + 1) * 3]];
fil[x * 3 + 1] = vb_filter_v1_g[fil[x * 3 + 1]][fil3[(x + 1) * 3 + 1]];
fil[x * 3 + 2] = vb_filter_v1_rb[fil[x * 3 + 2]][fil3[(x + 1) * 3 + 2]];
p[x] = (fil[x * 3 + 2] << 16) | (fil[x * 3 + 1] << 8) | fil[x * 3];
fil[x * 3] = vb_filter_v1_rb[fil[x * 3]][fil3[(x + 1) * 3]];
fil[x * 3 + 1] = vb_filter_v1_g[fil[x * 3 + 1]][fil3[(x + 1) * 3 + 1]];
fil[x * 3 + 2] = vb_filter_v1_rb[fil[x * 3 + 2]][fil3[(x + 1) * 3 + 2]];
chroma_test_passed = banshee_chroma_key(banshee, svga->overlay_latch.x + x, displine - svga->y_add);
if (chroma_test_passed)
p[x] = (fil[x * 3 + 2] << 16) | (fil[x * 3 + 1] << 8) | fil[x * 3];
}
} else /* filter disabled by emulator option */
{
if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) {
for (x = 0; x < svga->overlay_latch.cur_xsize; x++) {
p[x] = banshee->overlay_buffer[0][src_x >> 20];
chroma_test_passed = banshee_chroma_key(banshee, svga->overlay_latch.x + x, displine - svga->y_add);
if (chroma_test_passed)
p[x] = banshee->overlay_buffer[0][src_x >> 20];
src_x += voodoo->overlay.vidOverlayDudx;
}
} else {
for (x = 0; x < svga->overlay_latch.cur_xsize; x++)
p[x] = banshee->overlay_buffer[0][x];
for (x = 0; x < svga->overlay_latch.cur_xsize; x++) {
chroma_test_passed = banshee_chroma_key(banshee, svga->overlay_latch.x + x, displine - svga->y_add);
if (chroma_test_passed)
p[x] = banshee->overlay_buffer[0][x];
}
}
}
break;
@@ -2830,25 +2954,35 @@ banshee_overlay_draw(svga_t *svga, int displine)
if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) /* 2x2 on a scaled low res */
{
for (x = 0; x < svga->overlay_latch.cur_xsize; x++) {
p[x] = (fil[(src_x >> 20) * 3 + 2] << 16) | (fil[(src_x >> 20) * 3 + 1] << 8) | fil[(src_x >> 20) * 3];
chroma_test_passed = banshee_chroma_key(banshee, svga->overlay_latch.x + x, displine - svga->y_add);
if (chroma_test_passed)
p[x] = (fil[(src_x >> 20) * 3 + 2] << 16) | (fil[(src_x >> 20) * 3 + 1] << 8) | fil[(src_x >> 20) * 3];
src_x += voodoo->overlay.vidOverlayDudx;
}
} else {
for (x = 0; x < svga->overlay_latch.cur_xsize; x++) {
p[x] = (fil[x * 3 + 2] << 16) | (fil[x * 3 + 1] << 8) | fil[x * 3];
chroma_test_passed = banshee_chroma_key(banshee, svga->overlay_latch.x + x, displine - svga->y_add);
if (chroma_test_passed)
p[x] = (fil[x * 3 + 2] << 16) | (fil[x * 3 + 1] << 8) | fil[x * 3];
}
}
} else /* filter disabled by emulator option */
{
if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) {
for (x = 0; x < svga->overlay_latch.cur_xsize; x++) {
p[x] = banshee->overlay_buffer[0][src_x >> 20];
chroma_test_passed = banshee_chroma_key(banshee, svga->overlay_latch.x + x, displine - svga->y_add);
if (chroma_test_passed)
p[x] = banshee->overlay_buffer[0][src_x >> 20];
src_x += voodoo->overlay.vidOverlayDudx;
}
} else {
for (x = 0; x < svga->overlay_latch.cur_xsize; x++)
p[x] = banshee->overlay_buffer[0][x];
for (x = 0; x < svga->overlay_latch.cur_xsize; x++) {
chroma_test_passed = banshee_chroma_key(banshee, svga->overlay_latch.x + x, displine - svga->y_add);
if (chroma_test_passed)
p[x] = banshee->overlay_buffer[0][x];
}
}
}
break;
@@ -2857,13 +2991,18 @@ banshee_overlay_draw(svga_t *svga, int displine)
default:
if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) {
for (x = 0; x < svga->overlay_latch.cur_xsize; x++) {
p[x] = banshee->overlay_buffer[0][src_x >> 20];
chroma_test_passed = banshee_chroma_key(banshee, svga->overlay_latch.x + x, displine - svga->y_add);
if (chroma_test_passed)
p[x] = banshee->overlay_buffer[0][src_x >> 20];
src_x += voodoo->overlay.vidOverlayDudx;
}
} else {
for (x = 0; x < svga->overlay_latch.cur_xsize; x++)
p[x] = banshee->overlay_buffer[0][x];
for (x = 0; x < svga->overlay_latch.cur_xsize; x++) {
chroma_test_passed = banshee_chroma_key(banshee, svga->overlay_latch.x + x, displine - svga->y_add);
if (chroma_test_passed)
p[x] = banshee->overlay_buffer[0][x];
}
}
break;
}
@@ -3262,6 +3401,8 @@ banshee_init_common(const device_t *info, char *fn, int has_sgram, int type, int
banshee->agp = agp;
banshee->has_bios = !!fn;
banshee->chroma_key_enabled = device_get_config_int("chromakey");
if (banshee->has_bios) {
rom_init(&banshee->bios_rom, fn, 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL);
mem_mapping_disable(&banshee->bios_rom.mapping);
@@ -3692,6 +3833,17 @@ static const device_config_t banshee_sgram_config[] = {
.selection = { { 0 } },
.bios = { { 0 } }
},
{
.name = "chromakey",
.description = "Video chroma-keying",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 1,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{
.name = "dithersub",
.description = "Dither subtraction",
@@ -3758,6 +3910,17 @@ static const device_config_t banshee_sgram_16mbonly_config[] = {
.selection = { { 0 } },
.bios = { { 0 } }
},
{
.name = "chromakey",
.description = "Video chroma-keying",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 1,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{
.name = "dithersub",
.description = "Dither subtraction",
@@ -3824,6 +3987,17 @@ static const device_config_t banshee_sdram_config[] = {
.selection = { { 0 } },
.bios = { { 0 } }
},
{
.name = "chromakey",
.description = "Video chroma-keying",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 1,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{
.name = "dithersub",
.description = "Dither subtraction",

View File

@@ -917,7 +917,19 @@ do_screen_to_screen_stretch_line(voodoo_t *voodoo, uint8_t *src_p, int src_x, in
const uint8_t *pattern_mono = (uint8_t *) voodoo->banshee_blt.colorPattern;
int use_pattern_trans = (voodoo->banshee_blt.command & (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO)) == (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO);
const uint32_t *colorPattern = voodoo->banshee_blt.colorPattern;
int src_colorkey;
switch (voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) {
case SRC_FORMAT_COL_8_BPP:
src_colorkey = COLORKEY_8;
break;
case SRC_FORMAT_COL_16_BPP:
src_colorkey = COLORKEY_16;
break;
default:
src_colorkey = COLORKEY_32;
break;
}
#if 0
int error_y = voodoo->banshee_blt.dstSizeY / 2;
@@ -925,104 +937,218 @@ do_screen_to_screen_stretch_line(voodoo_t *voodoo, uint8_t *src_p, int src_x, in
bansheeblt_log(" srcXY=%i,%i srcsizeXY=%i,%i\n", voodoo->banshee_blt.srcX, voodoo->banshee_blt.srcY, voodoo->banshee_blt.srcSizeX, voodoo->banshee_blt.srcSizeY);
bansheeblt_log(" dstXY=%i,%i dstsizeXY=%i,%i\n", voodoo->banshee_blt.dstX, voodoo->banshee_blt.dstY, voodoo->banshee_blt.dstSizeX, voodoo->banshee_blt.dstSizeY);*/
#endif
if (dst_y >= clip->y_min && dst_y < clip->y_max) {
#if 0
int src_x = voodoo->banshee_blt.srcX;
#endif
int dst_x = voodoo->banshee_blt.dstX;
int pat_x = voodoo->banshee_blt.patoff_x + voodoo->banshee_blt.dstX;
uint8_t pattern_mask = pattern_mono[pat_y & 7];
int error_x = voodoo->banshee_blt.dstSizeX / 2;
if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == (voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK)) {
if (dst_y >= clip->y_min && dst_y < clip->y_max) {
int dst_x = voodoo->banshee_blt.dstX;
int pat_x = voodoo->banshee_blt.patoff_x + voodoo->banshee_blt.dstX;
uint8_t pattern_mask = pattern_mono[pat_y & 7];
int error_x = voodoo->banshee_blt.dstSizeX / 2;
#if 0
bansheeblt_log(" Plot dest line %03i : src line %03i\n", dst_y, src_y);
#endif
for (voodoo->banshee_blt.cur_x = 0; voodoo->banshee_blt.cur_x < voodoo->banshee_blt.dstSizeX; voodoo->banshee_blt.cur_x++) {
int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7 - (pat_x & 7)))) : 1;
for (voodoo->banshee_blt.cur_x = 0; voodoo->banshee_blt.cur_x < voodoo->banshee_blt.dstSizeX; voodoo->banshee_blt.cur_x++) {
int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7 - (pat_x & 7)))) : 1;
if (dst_x >= clip->x_min && dst_x < clip->x_max && pattern_trans) {
switch (voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK) {
case DST_FORMAT_COL_8_BPP:
{
uint32_t dst_addr = get_addr(voodoo, dst_x, dst_y, 0, 0); //(voodoo->banshee_blt.dstBaseAddr + dst_x + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask;
uint32_t src = src_p[src_x];
uint32_t dest = voodoo->vram[dst_addr];
uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? ((pattern_mask & (1 << (7 - (pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : colorPattern[(pat_x & 7) + (pat_y & 7) * 8];
if (dst_x >= clip->x_min && dst_x < clip->x_max && pattern_trans) {
switch (voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK) {
case DST_FORMAT_COL_8_BPP:
{
uint32_t dst_addr = get_addr(voodoo, dst_x, dst_y, 0, 0); //(voodoo->banshee_blt.dstBaseAddr + dst_x + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask;
uint32_t src = src_p[src_x];
uint32_t dest = voodoo->vram[dst_addr];
uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? ((pattern_mask & (1 << (7 - (pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : colorPattern[(pat_x & 7) + (pat_y & 7) * 8];
if (dst_addr > voodoo->fb_mask)
if (dst_addr > voodoo->fb_mask)
break;
voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_8, COLORKEY_8);
voodoo->changedvram[dst_addr >> 12] = changeframecount;
break;
}
case DST_FORMAT_COL_16_BPP:
{
uint32_t dst_addr = get_addr(voodoo, dst_x * 2, dst_y, 0, 0); //(voodoo->banshee_blt.dstBaseAddr + dst_x*2 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask;
uint32_t src = *(uint16_t *) &src_p[src_x * 2];
uint32_t dest = *(uint16_t *) &voodoo->vram[dst_addr];
uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? ((pattern_mask & (1 << (7 - (pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : colorPattern[(pat_x & 7) + (pat_y & 7) * 8];
voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_8, COLORKEY_8);
#if 0
bansheeblt_log("%i,%i : sdp=%02x,%02x,%02x res=%02x\n", voodoo->banshee_blt.cur_x, voodoo->banshee_blt.cur_y, src, dest, pattern, voodoo->vram[dst_addr]);
#endif
voodoo->changedvram[dst_addr >> 12] = changeframecount;
break;
}
case DST_FORMAT_COL_16_BPP:
{
uint32_t dst_addr = get_addr(voodoo, dst_x * 2, dst_y, 0, 0); //(voodoo->banshee_blt.dstBaseAddr + dst_x*2 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask;
uint32_t src = *(uint16_t *) &src_p[src_x * 2];
uint32_t dest = *(uint16_t *) &voodoo->vram[dst_addr];
uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? ((pattern_mask & (1 << (7 - (pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : colorPattern[(pat_x & 7) + (pat_y & 7) * 8];
if (dst_addr > voodoo->fb_mask)
break;
if (dst_addr > voodoo->fb_mask)
*(uint16_t *) &voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_16, COLORKEY_16);
voodoo->changedvram[dst_addr >> 12] = changeframecount;
break;
}
case DST_FORMAT_COL_24_BPP:
{
uint32_t dst_addr = get_addr(voodoo, dst_x * 3, dst_y, 0, 0); //(voodoo->banshee_blt.dstBaseAddr + dst_x*3 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask;
uint32_t src = *(uint32_t *) &src_p[src_x * 3];
uint32_t dest = *(uint32_t *) &voodoo->vram[dst_addr];
uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? ((pattern_mask & (1 << (7 - (pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : colorPattern[(pat_x & 7) + (pat_y & 7) * 8];
*(uint16_t *) &voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_16, COLORKEY_16);
#if 0
bansheeblt_log("%i,%i : sdp=%02x,%02x,%02x res=%02x\n", voodoo->banshee_blt.cur_x, voodoo->banshee_blt.cur_y, src, dest, pattern, *(uint16_t *)&voodoo->vram[dst_addr]);
#endif
voodoo->changedvram[dst_addr >> 12] = changeframecount;
break;
}
case DST_FORMAT_COL_24_BPP:
{
uint32_t dst_addr = get_addr(voodoo, dst_x * 3, dst_y, 0, 0); //(voodoo->banshee_blt.dstBaseAddr + dst_x*3 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask;
uint32_t src = *(uint32_t *) &src_p[src_x * 3];
uint32_t dest = *(uint32_t *) &voodoo->vram[dst_addr];
uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? ((pattern_mask & (1 << (7 - (pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : colorPattern[(pat_x & 7) + (pat_y & 7) * 8];
if (dst_addr > voodoo->fb_mask)
break;
if (dst_addr > voodoo->fb_mask)
*(uint32_t *) &voodoo->vram[dst_addr] = (MIX(voodoo, dest, src, pattern, COLORKEY_32, COLORKEY_32) & 0xffffff) | (*(uint32_t *) &voodoo->vram[dst_addr] & 0xff000000);
voodoo->changedvram[dst_addr >> 12] = changeframecount;
break;
}
case DST_FORMAT_COL_32_BPP:
{
uint32_t dst_addr = get_addr(voodoo, dst_x * 4, dst_y, 0, 0); //(voodoo->banshee_blt.dstBaseAddr + dst_x*4 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask;
uint32_t src = *(uint32_t *) &src_p[src_x * 4];
uint32_t dest = *(uint32_t *) &voodoo->vram[dst_addr];
uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? ((pattern_mask & (1 << (7 - (pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : colorPattern[(pat_x & 7) + (pat_y & 7) * 8];
*(uint32_t *) &voodoo->vram[dst_addr] = (MIX(voodoo, dest, src, pattern, COLORKEY_32, COLORKEY_32) & 0xffffff) | (*(uint32_t *) &voodoo->vram[dst_addr] & 0xff000000);
#if 0
bansheeblt_log("%i,%i : sdp=%02x,%02x,%02x res=%02x\n", voodoo->banshee_blt.cur_x, voodoo->banshee_blt.cur_y, src, dest, pattern, voodoo->vram[dst_addr]);
#endif
voodoo->changedvram[dst_addr >> 12] = changeframecount;
break;
}
case DST_FORMAT_COL_32_BPP:
{
uint32_t dst_addr = get_addr(voodoo, dst_x * 4, dst_y, 0, 0); //(voodoo->banshee_blt.dstBaseAddr + dst_x*4 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask;
uint32_t src = *(uint32_t *) &src_p[src_x * 4];
uint32_t dest = *(uint32_t *) &voodoo->vram[dst_addr];
uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? ((pattern_mask & (1 << (7 - (pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : colorPattern[(pat_x & 7) + (pat_y & 7) * 8];
if (dst_addr > voodoo->fb_mask)
break;
if (dst_addr > voodoo->fb_mask)
*(uint32_t *) &voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_32, COLORKEY_32);
voodoo->changedvram[dst_addr >> 12] = changeframecount;
break;
}
*(uint32_t *) &voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_32, COLORKEY_32);
#if 0
bansheeblt_log("%i,%i : sdp=%02x,%02x,%02x res=%02x\n", voodoo->banshee_blt.cur_x, voodoo->banshee_blt.cur_y, src, dest, pattern, voodoo->vram[dst_addr]);
#endif
voodoo->changedvram[dst_addr >> 12] = changeframecount;
default:
break;
}
default:
break;
}
}
}
error_x -= voodoo->banshee_blt.srcSizeX;
while (error_x < 0) {
error_x += voodoo->banshee_blt.dstSizeX;
src_x++;
error_x -= voodoo->banshee_blt.srcSizeX;
while (error_x < 0) {
error_x += voodoo->banshee_blt.dstSizeX;
src_x++;
}
dst_x++;
pat_x++;
}
}
} else {
/* Color conversion required. */
if (dst_y >= clip->y_min && dst_y < clip->y_max) {
int dst_x = voodoo->banshee_blt.dstX;
int pat_x = voodoo->banshee_blt.patoff_x + voodoo->banshee_blt.dstX;
uint8_t pattern_mask = pattern_mono[pat_y & 7];
int error_x = voodoo->banshee_blt.dstSizeX / 2;
for (voodoo->banshee_blt.cur_x = 0; voodoo->banshee_blt.cur_x < voodoo->banshee_blt.dstSizeX; voodoo->banshee_blt.cur_x++) {
int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7 - (pat_x & 7)))) : 1;
int src_x_real = (src_x * voodoo->banshee_blt.src_bpp) >> 3;
if (dst_x >= clip->x_min && dst_x < clip->x_max && pattern_trans) {
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:
{
uint8_t src_byte = src_p[src_x_real];
src_data = (src_byte & (0x80 >> (src_x & 7))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack;
if (voodoo->banshee_blt.command & COMMAND_TRANS_MONO)
transparent = !(src_byte & (0x80 >> (src_x & 7)));
#if 0
bansheeblt_log(" 1bpp src_byte=%02x src_x=%i src_data=%x transparent=%i\n", src_byte, src_x, src_data, transparent);
#endif
break;
}
case SRC_FORMAT_COL_8_BPP:
{
src_data = src_p[src_x_real];
break;
}
case SRC_FORMAT_COL_16_BPP:
{
uint16_t src_16 = *(uint16_t *) &src_p[src_x_real];
int r = (src_16 >> 11);
int g = (src_16 >> 5) & 0x3f;
int b = src_16 & 0x1f;
r = (r << 3) | (r >> 2);
g = (g << 2) | (g >> 4);
b = (b << 3) | (b >> 2);
src_data = (r << 16) | (g << 8) | b;
break;
}
case SRC_FORMAT_COL_24_BPP:
{
src_data = *(uint32_t *) &src_p[src_x_real];
break;
}
case SRC_FORMAT_COL_32_BPP:
{
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;
}
case SRC_FORMAT_COL_UYVY:
{
src_data_yuv = *(uint32_t *) &src_p[src_x_real];
src_data_yuv = ((src_data_yuv & 0xFF00) >> 8) | ((src_data_yuv & 0xFF) << 8) |
((src_data_yuv & 0xFF000000) >> 8) | ((src_data_yuv & 0xFF0000) << 8);
break;
}
default:
fatal("banshee_do_screen_to_screen_stretch_blt: unknown srcFormat %08x\n", voodoo->banshee_blt.srcFormat);
}
if ((voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK) == DST_FORMAT_COL_16_BPP && (voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) != SRC_FORMAT_COL_1_BPP) {
int r = src_data >> 16;
int g = (src_data >> 8) & 0xff;
int b = src_data & 0xff;
src_data = (b >> 3) | ((g >> 2) << 5) | ((r >> 3) << 11);
}
if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_YUYV
|| (voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_UYVY) {
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, 0xFF, rgbcol[0], src_colorkey);
}
dst_x++;
if (!transparent) {
PLOT(voodoo, dst_x, dst_y, pat_x, pat_y, pattern_mask, 0xFF, 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, 0xFF, rgbcol & 0xffff, src_colorkey);
}
dst_x++;
if (!transparent) {
PLOT(voodoo, dst_x, dst_y, pat_x, pat_y, pattern_mask, 0xFF, rgbcol >> 16, src_colorkey);
}
} else
fatal("banshee_do_screen_to_screen_stretch_blt: unknown dstFormat %08x\n", voodoo->banshee_blt.dstFormat);
} else {
if (!transparent)
PLOT(voodoo, dst_x, dst_y, pat_x, pat_y, pattern_mask, 0xFF, src_data, src_colorkey);
}
}
error_x -= voodoo->banshee_blt.srcSizeX;
while (error_x < 0) {
error_x += voodoo->banshee_blt.dstSizeX;
src_x++;
}
dst_x++;
pat_x++;
}
dst_x++;
pat_x++;
}
}