/*Current issues : - missing screen->screen scaled blits with format conversion - missing YUV blits (YUV -> 32-bit, 24-bit, or 16-bit RGB now done) - missing linestyle - missing wait for vsync - missing reversible lines Notes : - 16 bpp runs with tiled framebuffer - to aid 3D? 8 and 32 bpp use linear */ #include #include #include #include #include #include #include #include #define HAVE_STDARG_H #include <86box/86box.h> #include "cpu.h" #include <86box/machine.h> #include <86box/device.h> #include <86box/mem.h> #include <86box/timer.h> #include <86box/device.h> #include <86box/plat.h> #include <86box/thread.h> #include <86box/video.h> #include <86box/vid_svga.h> #include <86box/vid_voodoo_common.h> #include <86box/vid_voodoo_banshee_blitter.h> #include <86box/vid_voodoo_render.h> #define COMMAND_CMD_MASK (0xf) #define COMMAND_CMD_NOP (0 << 0) #define COMMAND_CMD_SCREEN_TO_SCREEN_BLT (1 << 0) #define COMMAND_CMD_SCREEN_TO_SCREEN_STRETCH_BLT (2 << 0) #define COMMAND_CMD_HOST_TO_SCREEN_BLT (3 << 0) #define COMMAND_CMD_HOST_TO_SCREEN_STRETCH_BLT (4 << 0) #define COMMAND_CMD_RECTFILL (5 << 0) #define COMMAND_CMD_LINE (6 << 0) #define COMMAND_CMD_POLYLINE (7 << 0) #define COMMAND_CMD_POLYFILL (8 << 0) #define COMMAND_INITIATE (1 << 8) #define COMMAND_INC_X_START (1 << 10) #define COMMAND_INC_Y_START (1 << 11) #define COMMAND_STIPPLE_LINE (1 << 12) #define COMMAND_PATTERN_MONO (1 << 13) #define COMMAND_DX (1 << 14) #define COMMAND_DY (1 << 15) #define COMMAND_TRANS_MONO (1 << 16) #define COMMAND_PATOFF_X_MASK (7 << 17) #define COMMAND_PATOFF_X_SHIFT (17) #define COMMAND_PATOFF_Y_MASK (7 << 20) #define COMMAND_PATOFF_Y_SHIFT (20) #define COMMAND_CLIP_SEL (1 << 23) #define CMDEXTRA_SRC_COLORKEY (1 << 0) #define CMDEXTRA_DST_COLORKEY (1 << 1) #define CMDEXTRA_FORCE_PAT_ROW0 (1 << 3) #define SRC_FORMAT_STRIDE_MASK (0x1fff) #define SRC_FORMAT_COL_MASK (0xf << 16) #define SRC_FORMAT_COL_1_BPP (0 << 16) #define SRC_FORMAT_COL_8_BPP (1 << 16) #define SRC_FORMAT_COL_16_BPP (3 << 16) #define SRC_FORMAT_COL_24_BPP (4 << 16) #define SRC_FORMAT_COL_32_BPP (5 << 16) #define SRC_FORMAT_COL_YUYV (8 << 16) #define SRC_FORMAT_COL_UYVY (9 << 16) #define SRC_FORMAT_BYTE_SWIZZLE (1 << 20) #define SRC_FORMAT_WORD_SWIZZLE (1 << 21) #define SRC_FORMAT_PACKING_MASK (3 << 22) #define SRC_FORMAT_PACKING_STRIDE (0 << 22) #define SRC_FORMAT_PACKING_BYTE (1 << 22) #define SRC_FORMAT_PACKING_WORD (2 << 22) #define SRC_FORMAT_PACKING_DWORD (3 << 22) #define DST_FORMAT_STRIDE_MASK (0x1fff) #define DST_FORMAT_COL_MASK (0xf << 16) #define DST_FORMAT_COL_8_BPP (1 << 16) #define DST_FORMAT_COL_16_BPP (3 << 16) #define DST_FORMAT_COL_24_BPP (4 << 16) #define DST_FORMAT_COL_32_BPP (5 << 16) #define BRES_ERROR_MASK (0xffff) #define BRES_ERROR_USE (1 << 31) enum { COLORKEY_8, COLORKEY_16, COLORKEY_32 }; #ifdef ENABLE_BANSHEEBLT_LOG int bansheeblt_do_log = ENABLE_BANSHEEBLT_LOG; static void bansheeblt_log(const char *fmt, ...) { va_list ap; if (bansheeblt_do_log) { va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); } } #else # define bansheeblt_log(fmt, ...) #endif static int colorkey(voodoo_t *voodoo, uint32_t src, int src_notdst, int color_format) { uint32_t min = src_notdst ? voodoo->banshee_blt.srcColorkeyMin : voodoo->banshee_blt.dstColorkeyMin; uint32_t max = src_notdst ? voodoo->banshee_blt.srcColorkeyMax : voodoo->banshee_blt.dstColorkeyMax; if (!(voodoo->banshee_blt.commandExtra & (src_notdst ? CMDEXTRA_SRC_COLORKEY : CMDEXTRA_DST_COLORKEY))) return 0; switch (color_format) { case COLORKEY_8: return ((src & 0xff) >= (min & 0xff)) && ((src & 0xff) <= (max & 0xff)); case COLORKEY_16: { int r = (src >> 11) & 0x1f; int r_min = (min >> 11) & 0x1f; int r_max = (max >> 11) & 0x1f; int g = (src >> 5) & 0x3f; int g_min = (min >> 5) & 0x3f; int g_max = (max >> 5) & 0x3f; int b = src & 0x1f; int b_min = min & 0x1f; int b_max = max & 0x1f; return (r >= r_min) && (r <= r_max) && (g >= g_min) && (g <= g_max) && (b >= b_min) && (b <= b_max); } case COLORKEY_32: { int r = (src >> 16) & 0xff; int r_min = (min >> 16) & 0xff; int r_max = (max >> 16) & 0xff; int g = (src >> 8) & 0xff; int g_min = (min >> 8) & 0xff; int g_max = (max >> 8) & 0xff; int b = src & 0xff; int b_min = min & 0xff; int b_max = max & 0xff; return (r >= r_min) && (r <= r_max) && (g >= g_min) && (g <= g_max) && (b >= b_min) && (b <= b_max); } default: return 0; } } static uint32_t MIX(voodoo_t *voodoo, uint32_t dest, uint32_t src, uint32_t pattern, int colour_format_src, int colour_format_dest) { int rop_nr = 0; uint32_t result = 0; uint32_t rop; if (colorkey(voodoo, src, 1, colour_format_src)) rop_nr |= 2; if (colorkey(voodoo, dest, 0, colour_format_dest)) rop_nr |= 1; rop = voodoo->banshee_blt.rops[rop_nr]; if (rop & 0x01) result |= (~pattern & ~src & ~dest); if (rop & 0x02) result |= (~pattern & ~src & dest); if (rop & 0x04) result |= (~pattern & src & ~dest); if (rop & 0x08) result |= (~pattern & src & dest); if (rop & 0x10) result |= (pattern & ~src & ~dest); if (rop & 0x20) result |= (pattern & ~src & dest); if (rop & 0x40) result |= (pattern & src & ~dest); if (rop & 0x80) result |= (pattern & src & dest); return result; } static uint32_t get_addr(voodoo_t *voodoo, int x, int y, int src_notdst, uint32_t src_stride) { uint32_t stride = src_notdst ? src_stride : voodoo->banshee_blt.dst_stride; uint32_t base_addr = src_notdst ? voodoo->banshee_blt.srcBaseAddr : voodoo->banshee_blt.dstBaseAddr; if (src_notdst ? voodoo->banshee_blt.srcBaseAddr_tiled : voodoo->banshee_blt.dstBaseAddr_tiled) return (base_addr + (x & 127) + ((x >> 7) * 128 * 32) + ((y & 31) * 128) + (y >> 5) * stride) & voodoo->fb_mask; else return (base_addr + x + y * stride) & voodoo->fb_mask; } static void PLOT(voodoo_t *voodoo, int x, int y, int pat_x, int pat_y, uint8_t pattern_mask, UNUSED(uint8_t rop), uint32_t src, int src_colorkey) { switch (voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK) { case DST_FORMAT_COL_8_BPP: { uint32_t addr = get_addr(voodoo, x, y, 0, 0); //(voodoo->banshee_blt.dstBaseAddr + x + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; uint32_t dest = voodoo->vram[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) : voodoo->banshee_blt.colorPattern8[(pat_x & 7) + (pat_y & 7) * 8]; if (addr > voodoo->fb_mask) break; voodoo->vram[addr] = MIX(voodoo, dest, src, pattern, src_colorkey, COLORKEY_8); voodoo->changedvram[addr >> 12] = changeframecount; break; } case DST_FORMAT_COL_16_BPP: { uint32_t addr = get_addr(voodoo, x * 2, y, 0, 0); //(voodoo->banshee_blt.dstBaseAddr + x*2 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; uint32_t dest = *(uint16_t *) &voodoo->vram[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) : voodoo->banshee_blt.colorPattern16[(pat_x & 7) + (pat_y & 7) * 8]; if (addr > voodoo->fb_mask) break; *(uint16_t *) &voodoo->vram[addr] = MIX(voodoo, dest, src, pattern, src_colorkey, COLORKEY_16); voodoo->changedvram[addr >> 12] = changeframecount; break; } case DST_FORMAT_COL_24_BPP: { uint32_t addr = get_addr(voodoo, x * 3, y, 0, 0); //(voodoo->banshee_blt.dstBaseAddr + x*3 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; uint32_t dest = *(uint32_t *) &voodoo->vram[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) : voodoo->banshee_blt.colorPattern24[(pat_x & 7) + (pat_y & 7) * 8]; if (addr > voodoo->fb_mask) break; *(uint32_t *) &voodoo->vram[addr] = (MIX(voodoo, dest, src, pattern, src_colorkey, COLORKEY_32) & 0xffffff) | (dest & 0xff000000); voodoo->changedvram[addr >> 12] = changeframecount; break; } case DST_FORMAT_COL_32_BPP: { uint32_t addr = get_addr(voodoo, x * 4, y, 0, 0); //(voodoo->banshee_blt.dstBaseAddr + x*4 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; uint32_t dest = *(uint32_t *) &voodoo->vram[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) : voodoo->banshee_blt.colorPattern[(pat_x & 7) + (pat_y & 7) * 8]; if (addr > voodoo->fb_mask) break; *(uint32_t *) &voodoo->vram[addr] = MIX(voodoo, dest, src, pattern, src_colorkey, COLORKEY_32); voodoo->changedvram[addr >> 12] = changeframecount; break; } default: break; } } static void PLOT_LINE(voodoo_t *voodoo, int x, int y, UNUSED(uint8_t rop), uint32_t pattern, int src_colorkey) { switch (voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK) { case DST_FORMAT_COL_8_BPP: { uint32_t addr = get_addr(voodoo, x, y, 0, 0); //(voodoo->banshee_blt.dstBaseAddr + x + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; uint32_t dest = voodoo->vram[addr]; if (addr > voodoo->fb_mask) break; voodoo->vram[addr] = MIX(voodoo, dest, voodoo->banshee_blt.colorFore, pattern, src_colorkey, COLORKEY_8); voodoo->changedvram[addr >> 12] = changeframecount; break; } case DST_FORMAT_COL_16_BPP: { uint32_t addr = get_addr(voodoo, x * 2, y, 0, 0); //(voodoo->banshee_blt.dstBaseAddr + x*2 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; uint32_t dest = *(uint16_t *) &voodoo->vram[addr]; if (addr > voodoo->fb_mask) break; *(uint16_t *) &voodoo->vram[addr] = MIX(voodoo, dest, voodoo->banshee_blt.colorFore, pattern, src_colorkey, COLORKEY_16); voodoo->changedvram[addr >> 12] = changeframecount; break; } case DST_FORMAT_COL_24_BPP: { uint32_t addr = get_addr(voodoo, x * 3, y, 0, 0); //(voodoo->banshee_blt.dstBaseAddr + x*3 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; uint32_t dest = *(uint32_t *) &voodoo->vram[addr]; if (addr > voodoo->fb_mask) break; *(uint32_t *) &voodoo->vram[addr] = (MIX(voodoo, dest, voodoo->banshee_blt.colorFore, pattern, src_colorkey, COLORKEY_32) & 0xffffff) | (dest & 0xff000000); voodoo->changedvram[addr >> 12] = changeframecount; break; } case DST_FORMAT_COL_32_BPP: { uint32_t addr = get_addr(voodoo, x * 4, y, 0, 0); //(voodoo->banshee_blt.dstBaseAddr + x*4 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; uint32_t dest = *(uint32_t *) &voodoo->vram[addr]; if (addr > voodoo->fb_mask) break; *(uint32_t *) &voodoo->vram[addr] = MIX(voodoo, dest, voodoo->banshee_blt.colorFore, pattern, src_colorkey, COLORKEY_32); voodoo->changedvram[addr >> 12] = changeframecount; break; } default: break; } } static void update_src_stride(voodoo_t *voodoo) { int bpp; switch (voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) { case SRC_FORMAT_COL_1_BPP: bpp = 1; break; case SRC_FORMAT_COL_8_BPP: bpp = 8; break; case SRC_FORMAT_COL_16_BPP: bpp = 16; break; case SRC_FORMAT_COL_24_BPP: bpp = 24; break; case SRC_FORMAT_COL_32_BPP: case SRC_FORMAT_COL_YUYV: case SRC_FORMAT_COL_UYVY: bpp = 32; break; default: bpp = 16; break; } switch (voodoo->banshee_blt.srcFormat & SRC_FORMAT_PACKING_MASK) { case SRC_FORMAT_PACKING_STRIDE: voodoo->banshee_blt.src_stride_src = voodoo->banshee_blt.src_stride; // voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK; voodoo->banshee_blt.src_stride_dest = voodoo->banshee_blt.src_stride; // voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK; voodoo->banshee_blt.host_data_size_src = (voodoo->banshee_blt.srcSizeX * bpp + 7) >> 3; voodoo->banshee_blt.host_data_size_dest = (voodoo->banshee_blt.dstSizeX * bpp + 7) >> 3; #if 0 bansheeblt_log("Stride packing %08x %08x bpp=%i dstSizeX=%i\n", voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest, bpp, voodoo->banshee_blt.dstSizeX); #endif break; case SRC_FORMAT_PACKING_BYTE: voodoo->banshee_blt.src_stride_src = (voodoo->banshee_blt.srcSizeX * bpp + 7) >> 3; voodoo->banshee_blt.src_stride_dest = (voodoo->banshee_blt.dstSizeX * bpp + 7) >> 3; voodoo->banshee_blt.host_data_size_src = voodoo->banshee_blt.src_stride_src; voodoo->banshee_blt.host_data_size_dest = voodoo->banshee_blt.src_stride_dest; #if 0 bansheeblt_log("Byte packing %08x %08x\n", voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest); #endif break; case SRC_FORMAT_PACKING_WORD: voodoo->banshee_blt.src_stride_src = ((voodoo->banshee_blt.srcSizeX * bpp + 15) >> 4) * 2; voodoo->banshee_blt.src_stride_dest = ((voodoo->banshee_blt.dstSizeX * bpp + 15) >> 4) * 2; voodoo->banshee_blt.host_data_size_src = voodoo->banshee_blt.src_stride_src; voodoo->banshee_blt.host_data_size_dest = voodoo->banshee_blt.src_stride_dest; #if 0 bansheeblt_log("Word packing %08x %08x\n", voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest); #endif break; case SRC_FORMAT_PACKING_DWORD: voodoo->banshee_blt.src_stride_src = ((voodoo->banshee_blt.srcSizeX * bpp + 31) >> 5) * 4; voodoo->banshee_blt.src_stride_dest = ((voodoo->banshee_blt.dstSizeX * bpp + 31) >> 5) * 4; voodoo->banshee_blt.host_data_size_src = voodoo->banshee_blt.src_stride_src; voodoo->banshee_blt.host_data_size_dest = voodoo->banshee_blt.src_stride_dest; #if 0 bansheeblt_log("Dword packing %08x %08x\n", voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest); #endif break; default: break; } } static void end_command(voodoo_t *voodoo) { /*Update dest coordinates if required*/ if (voodoo->banshee_blt.command & COMMAND_INC_X_START) { voodoo->banshee_blt.dstXY &= ~0x0000ffff; voodoo->banshee_blt.dstXY |= (voodoo->banshee_blt.dstX & 0xffff); } if (voodoo->banshee_blt.command & COMMAND_INC_Y_START) { voodoo->banshee_blt.dstXY &= ~0xffff0000; voodoo->banshee_blt.dstXY |= (voodoo->banshee_blt.dstY << 16); } } static void banshee_do_rectfill(voodoo_t *voodoo) { const clip_t *clip = &voodoo->banshee_blt.clip[(voodoo->banshee_blt.command & COMMAND_CLIP_SEL) ? 1 : 0]; int dst_y = voodoo->banshee_blt.dstY; const uint8_t *pattern_mono = (uint8_t *) voodoo->banshee_blt.colorPattern; int pat_y = (voodoo->banshee_blt.commandExtra & CMDEXTRA_FORCE_PAT_ROW0) ? 0 : (voodoo->banshee_blt.patoff_y + voodoo->banshee_blt.dstY); int use_pattern_trans = (voodoo->banshee_blt.command & (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO)) == (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO); uint8_t rop = voodoo->banshee_blt.command >> 24; #if 0 bansheeblt_log("banshee_do_rectfill: size=%i,%i dst=%i,%i\n", voodoo->banshee_blt.dstSizeX, voodoo->banshee_blt.dstSizeY, voodoo->banshee_blt.dstX, voodoo->banshee_blt.dstY); bansheeblt_log("clipping: %i,%i -> %i,%i\n", clip->x_min, clip->y_min, clip->x_max, clip->y_max); bansheeblt_log("colorFore=%08x\n", voodoo->banshee_blt.colorFore); #endif for (voodoo->banshee_blt.cur_y = 0; voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY; voodoo->banshee_blt.cur_y++) { int dst_x = voodoo->banshee_blt.dstX; if (dst_y >= clip->y_min && dst_y < clip->y_max) { int pat_x = voodoo->banshee_blt.patoff_x + voodoo->banshee_blt.dstX; uint8_t pattern_mask = pattern_mono[pat_y & 7]; 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) PLOT(voodoo, dst_x, dst_y, pat_x, pat_y, pattern_mask, rop, voodoo->banshee_blt.colorFore, COLORKEY_32); dst_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; pat_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; } } dst_y += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; if (!(voodoo->banshee_blt.commandExtra & CMDEXTRA_FORCE_PAT_ROW0)) pat_y += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; } end_command(voodoo); } void DECODE_YUYV422(uint32_t *buf, uint8_t *src) { do { int wp = 0; uint8_t y1; uint8_t y2; int8_t Cr; int8_t Cb; int dR; int dG; int dB; int r; int g; int 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; uint8_t y2; int8_t Cr; int8_t Cb; int dR; int dG; int dB; int r; int g; int 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) { const clip_t *clip = &voodoo->banshee_blt.clip[(voodoo->banshee_blt.command & COMMAND_CLIP_SEL) ? 1 : 0]; int dst_y = voodoo->banshee_blt.dstY; int pat_y = (voodoo->banshee_blt.commandExtra & CMDEXTRA_FORCE_PAT_ROW0) ? 0 : (voodoo->banshee_blt.patoff_y + voodoo->banshee_blt.dstY); 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); uint8_t rop = voodoo->banshee_blt.command >> 24; 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 bansheeblt_log("do_screen_to_screen_line: srcFormat=%08x dst=%08x\n", voodoo->banshee_blt.srcFormat, voodoo->banshee_blt.dstFormat); #endif if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == (voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK)) { /*No 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]; 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 (src_tiled) 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) { 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_real]; 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) : voodoo->banshee_blt.colorPattern8[(pat_x & 7) + (pat_y & 7) * 8]; 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); // dst_addr = (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_real]; 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) : voodoo->banshee_blt.colorPattern16[(pat_x & 7) + (pat_y & 7) * 8]; if (dst_addr > voodoo->fb_mask) break; *(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); // dst_addr = (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_real]; 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) : voodoo->banshee_blt.colorPattern24[(pat_x & 7) + (pat_y & 7) * 8]; if (dst_addr > voodoo->fb_mask) break; *(uint32_t *) &voodoo->vram[dst_addr] = (MIX(voodoo, dest, src, pattern, COLORKEY_32, COLORKEY_32) & 0xffffff) | (dest & 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); // dst_addr = (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_real]; 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) : voodoo->banshee_blt.colorPattern[(pat_x & 7) + (pat_y & 7) * 8]; if (dst_addr > voodoo->fb_mask) break; *(uint32_t *) &voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_32, COLORKEY_32); voodoo->changedvram[dst_addr >> 12] = changeframecount; break; } default: break; } } if (use_x_dir) { src_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; dst_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; pat_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; } else { src_x++; dst_x++; pat_x++; } } } voodoo->banshee_blt.srcY += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; voodoo->banshee_blt.dstY += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; } else { /*Conversion required*/ 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]; 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 (src_tiled) 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; 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_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, 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; pat_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; } else { src_x++; dst_x++; pat_x++; } } } voodoo->banshee_blt.srcY += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; voodoo->banshee_blt.dstY += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; } } static void banshee_do_screen_to_screen_blt(voodoo_t *voodoo) { #if 0 bansheeblt_log("screen_to_screen: %08x %08x %08x\n", voodoo->banshee_blt.srcFormat, voodoo->banshee_blt.src_stride, voodoo->banshee_blt.src_stride_dest); return; #endif for (voodoo->banshee_blt.cur_y = 0; voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY; voodoo->banshee_blt.cur_y++) { uint32_t src_addr = get_addr(voodoo, 0, voodoo->banshee_blt.srcY, 1, voodoo->banshee_blt.src_stride_dest); #if 0 if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) bansheeblt_log(" srcY=%i src_addr=%08x\n", voodoo->banshee_blt.srcY, src_addr); #endif do_screen_to_screen_line(voodoo, &voodoo->vram[src_addr], 1, voodoo->banshee_blt.srcX, voodoo->banshee_blt.srcBaseAddr_tiled); } end_command(voodoo); } static void banshee_do_host_to_screen_blt(voodoo_t *voodoo, UNUSED(int count), uint32_t data) { #if 0 if (voodoo->banshee_blt.dstBaseAddr == 0xee5194) bansheeblt_log("banshee_do_host_to_screen_blt: data=%08x host_data_count=%i src_stride_dest=%i host_data_size_dest=%i\n", data, voodoo->banshee_blt.host_data_count, voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest); #endif if (voodoo->banshee_blt.srcFormat & SRC_FORMAT_BYTE_SWIZZLE) data = (data >> 24) | ((data >> 8) & 0xff00) | ((data << 8) & 0xff0000) | (data << 24); if (voodoo->banshee_blt.srcFormat & SRC_FORMAT_WORD_SWIZZLE) data = (data >> 16) | (data << 16); if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_PACKING_MASK) == SRC_FORMAT_PACKING_STRIDE) { int last_byte; if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) last_byte = ((voodoo->banshee_blt.srcX & 31) + voodoo->banshee_blt.dstSizeX + 7) >> 3; else last_byte = (voodoo->banshee_blt.srcX & 3) + voodoo->banshee_blt.host_data_size_dest; *(uint32_t *) &voodoo->banshee_blt.host_data[voodoo->banshee_blt.host_data_count] = data; voodoo->banshee_blt.host_data_count += 4; if (voodoo->banshee_blt.host_data_count >= last_byte) { #if 0 bansheeblt_log(" %i %i srcX=%i srcFormat=%08x\n", voodoo->banshee_blt.cur_y, voodoo->banshee_blt.dstSizeY, voodoo->banshee_blt.srcX); #endif if (voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY) { if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) do_screen_to_screen_line(voodoo, &voodoo->banshee_blt.host_data[(voodoo->banshee_blt.srcX >> 3) & 3], 0, voodoo->banshee_blt.srcX & 7, 0); else do_screen_to_screen_line(voodoo, &voodoo->banshee_blt.host_data[voodoo->banshee_blt.srcX & 3], 0, 0, 0); voodoo->banshee_blt.cur_y++; if (voodoo->banshee_blt.cur_y == voodoo->banshee_blt.dstSizeY) end_command(voodoo); } if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) voodoo->banshee_blt.srcX += (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK) << 3; else voodoo->banshee_blt.srcX += (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK); voodoo->banshee_blt.host_data_count = 0; } } else { *(uint32_t *) &voodoo->banshee_blt.host_data[voodoo->banshee_blt.host_data_count] = data; voodoo->banshee_blt.host_data_count += 4; while (voodoo->banshee_blt.host_data_count >= voodoo->banshee_blt.src_stride_dest) { voodoo->banshee_blt.host_data_count -= voodoo->banshee_blt.src_stride_dest; #if 0 bansheeblt_log(" %i %i\n", voodoo->banshee_blt.cur_y, voodoo->banshee_blt.dstSizeY); #endif if (voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY) { do_screen_to_screen_line(voodoo, voodoo->banshee_blt.host_data, 0, 0, 0); voodoo->banshee_blt.cur_y++; if (voodoo->banshee_blt.cur_y == voodoo->banshee_blt.dstSizeY) end_command(voodoo); } if (voodoo->banshee_blt.host_data_count) { #if 0 bansheeblt_log(" remaining=%i\n", voodoo->banshee_blt.host_data_count); #endif *(uint32_t *) &voodoo->banshee_blt.host_data[0] = data >> (4 - voodoo->banshee_blt.host_data_count) * 8; } } } } static void do_screen_to_screen_stretch_line(voodoo_t *voodoo, uint8_t *src_p, int src_x, int *src_y) { const clip_t *clip = &voodoo->banshee_blt.clip[(voodoo->banshee_blt.command & COMMAND_CLIP_SEL) ? 1 : 0]; #if 0 int src_y = voodoo->banshee_blt.srcY; #endif int dst_y = voodoo->banshee_blt.dstY; int pat_y = (voodoo->banshee_blt.commandExtra & CMDEXTRA_FORCE_PAT_ROW0) ? 0 : (voodoo->banshee_blt.patoff_y + voodoo->banshee_blt.dstY); 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; #if 0 int error_y = voodoo->banshee_blt.dstSizeY / 2; bansheeblt_log("banshee_do_screen_to_screen_stretch_blt:\n"); 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 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; 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) break; 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; *(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; *(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; *(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; break; } default: break; } } error_x -= voodoo->banshee_blt.srcSizeX; while (error_x < 0) { error_x += voodoo->banshee_blt.dstSizeX; src_x++; } dst_x++; pat_x++; } } voodoo->banshee_blt.bres_error_0 -= voodoo->banshee_blt.srcSizeY; while (voodoo->banshee_blt.bres_error_0 < 0) { voodoo->banshee_blt.bres_error_0 += voodoo->banshee_blt.dstSizeY; if (src_y) (*src_y) += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; } voodoo->banshee_blt.dstY += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; #if 0 pat_y += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; #endif } static void banshee_do_screen_to_screen_stretch_blt(voodoo_t *voodoo) { #if 0 bansheeblt_log("screen_to_screen: %08x %08x %08x\n", voodoo->banshee_blt.srcFormat, voodoo->banshee_blt.src_stride, voodoo->banshee_blt.src_stride_dest); return; #endif for (voodoo->banshee_blt.cur_y = 0; voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY; voodoo->banshee_blt.cur_y++) { uint32_t src_addr = get_addr(voodoo, 0, voodoo->banshee_blt.srcY, 1, voodoo->banshee_blt.src_stride_src); //(voodoo->banshee_blt.srcBaseAddr + voodoo->banshee_blt.srcY*voodoo->banshee_blt.src_stride_src) & voodoo->fb_mask; #if 0 bansheeblt_log("scale_blit %i %08x %08x\n", voodoo->banshee_blt.cur_y, src_addr, voodoo->banshee_blt.command); if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) bansheeblt_log(" srcY=%i src_addr=%08x\n", voodoo->banshee_blt.srcY, src_addr); #endif do_screen_to_screen_stretch_line(voodoo, &voodoo->vram[src_addr], voodoo->banshee_blt.srcX, &voodoo->banshee_blt.srcY); } end_command(voodoo); } static void banshee_do_host_to_screen_stretch_blt(voodoo_t *voodoo, UNUSED(int count), uint32_t data) { #if 0 if (voodoo->banshee_blt.dstBaseAddr == 0xee5194) bansheeblt_log("banshee_do_host_to_screen_blt: data=%08x host_data_count=%i src_stride_dest=%i host_data_size_dest=%i\n", data, voodoo->banshee_blt.host_data_count, voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest); #endif if (voodoo->banshee_blt.srcFormat & SRC_FORMAT_BYTE_SWIZZLE) data = (data >> 24) | ((data >> 8) & 0xff00) | ((data << 8) & 0xff0000) | (data << 24); if (voodoo->banshee_blt.srcFormat & SRC_FORMAT_WORD_SWIZZLE) data = (data >> 16) | (data << 16); if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_PACKING_MASK) == SRC_FORMAT_PACKING_STRIDE) { int last_byte = (voodoo->banshee_blt.srcX & 3) + voodoo->banshee_blt.host_data_size_src; *(uint32_t *) &voodoo->banshee_blt.host_data[voodoo->banshee_blt.host_data_count] = data; voodoo->banshee_blt.host_data_count += 4; if (voodoo->banshee_blt.host_data_count >= last_byte) { #if 0 bansheeblt_log(" %i %i srcX=%i srcFormat=%08x\n", voodoo->banshee_blt.cur_y, voodoo->banshee_blt.dstSizeY, voodoo->banshee_blt.srcX); #endif if (voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY) { if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) do_screen_to_screen_stretch_line(voodoo, &voodoo->banshee_blt.host_data[(voodoo->banshee_blt.srcX >> 3) & 3], voodoo->banshee_blt.srcX & 7, NULL); else do_screen_to_screen_stretch_line(voodoo, &voodoo->banshee_blt.host_data[voodoo->banshee_blt.srcX & 3], 0, NULL); voodoo->banshee_blt.cur_y++; if (voodoo->banshee_blt.cur_y == voodoo->banshee_blt.dstSizeY) end_command(voodoo); } if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) voodoo->banshee_blt.srcX += (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK) << 3; else voodoo->banshee_blt.srcX += (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK); voodoo->banshee_blt.host_data_count = 0; } } else { *(uint32_t *) &voodoo->banshee_blt.host_data[voodoo->banshee_blt.host_data_count] = data; voodoo->banshee_blt.host_data_count += 4; while (voodoo->banshee_blt.host_data_count >= voodoo->banshee_blt.src_stride_src) { voodoo->banshee_blt.host_data_count -= voodoo->banshee_blt.src_stride_src; #if 0 bansheeblt_log(" %i %i\n", voodoo->banshee_blt.cur_y, voodoo->banshee_blt.dstSizeY); #endif if (voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY) { do_screen_to_screen_stretch_line(voodoo, voodoo->banshee_blt.host_data, 0, NULL); voodoo->banshee_blt.cur_y++; if (voodoo->banshee_blt.cur_y == voodoo->banshee_blt.dstSizeY) end_command(voodoo); } if (voodoo->banshee_blt.host_data_count) { #if 0 bansheeblt_log(" remaining=%i\n", voodoo->banshee_blt.host_data_count); #endif *(uint32_t *) &voodoo->banshee_blt.host_data[0] = data >> (4 - voodoo->banshee_blt.host_data_count) * 8; } } } } static void step_line(voodoo_t *voodoo) { if (voodoo->banshee_blt.line_pix_pos == voodoo->banshee_blt.line_rep_cnt) { voodoo->banshee_blt.line_pix_pos = 0; if (voodoo->banshee_blt.line_bit_pos == voodoo->banshee_blt.line_bit_mask_size) voodoo->banshee_blt.line_bit_pos = 0; else voodoo->banshee_blt.line_bit_pos++; } else voodoo->banshee_blt.line_pix_pos++; } static void banshee_do_line(voodoo_t *voodoo, int draw_last_pixel) { const clip_t *clip = &voodoo->banshee_blt.clip[(voodoo->banshee_blt.command & COMMAND_CLIP_SEL) ? 1 : 0]; uint8_t rop = voodoo->banshee_blt.command >> 24; int dx = ABS(voodoo->banshee_blt.dstX - voodoo->banshee_blt.srcX); int dy = ABS(voodoo->banshee_blt.dstY - voodoo->banshee_blt.srcY); int x_inc = (voodoo->banshee_blt.dstX > voodoo->banshee_blt.srcX) ? 1 : -1; int y_inc = (voodoo->banshee_blt.dstY > voodoo->banshee_blt.srcY) ? 1 : -1; int x = voodoo->banshee_blt.srcX; int y = voodoo->banshee_blt.srcY; int error; uint32_t stipple = (voodoo->banshee_blt.command & COMMAND_STIPPLE_LINE) ? voodoo->banshee_blt.lineStipple : ~0; if (dx > dy) /*X major*/ { error = dx / 2; while (x != voodoo->banshee_blt.dstX) { int mask = stipple & (1 << voodoo->banshee_blt.line_bit_pos); int pattern_trans = (voodoo->banshee_blt.command & COMMAND_TRANS_MONO) ? mask : 1; if (y >= clip->y_min && y < clip->y_max && x >= clip->x_min && x < clip->x_max && pattern_trans) PLOT_LINE(voodoo, x, y, rop, mask ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack, COLORKEY_32); error -= dy; if (error < 0) { error += dx; y += y_inc; } x += x_inc; step_line(voodoo); } } else /*Y major*/ { error = dy / 2; while (y != voodoo->banshee_blt.dstY) { int mask = stipple & (1 << voodoo->banshee_blt.line_bit_pos); int pattern_trans = (voodoo->banshee_blt.command & COMMAND_TRANS_MONO) ? mask : 1; if (y >= clip->y_min && y < clip->y_max && x >= clip->x_min && x < clip->x_max && pattern_trans) PLOT_LINE(voodoo, x, y, rop, mask ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack, COLORKEY_32); error -= dx; if (error < 0) { error += dy; x += x_inc; } y += y_inc; step_line(voodoo); } } if (draw_last_pixel) { int mask = stipple & (1 << voodoo->banshee_blt.line_bit_pos); int pattern_trans = (voodoo->banshee_blt.command & COMMAND_TRANS_MONO) ? mask : 1; if (y >= clip->y_min && y < clip->y_max && x >= clip->x_min && x < clip->x_max && pattern_trans) PLOT_LINE(voodoo, x, y, rop, mask ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack, COLORKEY_32); } voodoo->banshee_blt.srcXY = (x & 0xffff) | (y << 16); voodoo->banshee_blt.srcX = x; voodoo->banshee_blt.srcY = y; } static void banshee_polyfill_start(voodoo_t *voodoo) { voodoo->banshee_blt.lx[0] = voodoo->banshee_blt.srcX; voodoo->banshee_blt.ly[0] = voodoo->banshee_blt.srcY; voodoo->banshee_blt.rx[0] = voodoo->banshee_blt.dstX; voodoo->banshee_blt.ry[0] = voodoo->banshee_blt.dstY; voodoo->banshee_blt.lx[1] = voodoo->banshee_blt.srcX; voodoo->banshee_blt.ly[1] = voodoo->banshee_blt.srcY; voodoo->banshee_blt.rx[1] = voodoo->banshee_blt.dstX; voodoo->banshee_blt.ry[1] = voodoo->banshee_blt.dstY; voodoo->banshee_blt.lx_cur = voodoo->banshee_blt.srcX; voodoo->banshee_blt.rx_cur = voodoo->banshee_blt.dstX; } static void banshee_polyfill_continue(voodoo_t *voodoo, uint32_t data) { const clip_t *clip = &voodoo->banshee_blt.clip[(voodoo->banshee_blt.command & COMMAND_CLIP_SEL) ? 1 : 0]; 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); uint8_t rop = voodoo->banshee_blt.command >> 24; int y = MAX(voodoo->banshee_blt.ly[0], voodoo->banshee_blt.ry[0]); int y_end; #if 0 bansheeblt_log("Polyfill : data %08x\n", data); #endif /*if r1.y>=l1.y, next vertex is left*/ if (voodoo->banshee_blt.ry[1] >= voodoo->banshee_blt.ly[1]) { voodoo->banshee_blt.lx[1] = ((int32_t) (data << 19)) >> 19; voodoo->banshee_blt.ly[1] = ((int32_t) (data << 3)) >> 19; voodoo->banshee_blt.dx[0] = ABS(voodoo->banshee_blt.lx[1] - voodoo->banshee_blt.lx[0]); voodoo->banshee_blt.dy[0] = ABS(voodoo->banshee_blt.ly[1] - voodoo->banshee_blt.ly[0]); voodoo->banshee_blt.x_inc[0] = (voodoo->banshee_blt.lx[1] > voodoo->banshee_blt.lx[0]) ? 1 : -1; voodoo->banshee_blt.error[0] = voodoo->banshee_blt.dy[0] / 2; } else { voodoo->banshee_blt.rx[1] = ((int32_t) (data << 19)) >> 19; voodoo->banshee_blt.ry[1] = ((int32_t) (data << 3)) >> 19; voodoo->banshee_blt.dx[1] = ABS(voodoo->banshee_blt.rx[1] - voodoo->banshee_blt.rx[0]); voodoo->banshee_blt.dy[1] = ABS(voodoo->banshee_blt.ry[1] - voodoo->banshee_blt.ry[0]); voodoo->banshee_blt.x_inc[1] = (voodoo->banshee_blt.rx[1] > voodoo->banshee_blt.rx[0]) ? 1 : -1; voodoo->banshee_blt.error[1] = voodoo->banshee_blt.dy[1] / 2; } #if 0 bansheeblt_log(" verts now : %03i,%03i %03i,%03i\n", voodoo->banshee_blt.lx[0], voodoo->banshee_blt.ly[0], voodoo->banshee_blt.rx[0], voodoo->banshee_blt.ry[0]); bansheeblt_log(" %03i,%03i %03i,%03i\n", voodoo->banshee_blt.lx[1], voodoo->banshee_blt.ly[1], voodoo->banshee_blt.rx[1], voodoo->banshee_blt.ry[1]); bansheeblt_log(" left dx=%i dy=%i x_inc=%i error=%i\n", voodoo->banshee_blt.dx[0],voodoo->banshee_blt.dy[0],voodoo->banshee_blt.x_inc[0],voodoo->banshee_blt.error[0]); bansheeblt_log(" right dx=%i dy=%i x_inc=%i error=%i\n", voodoo->banshee_blt.dx[1],voodoo->banshee_blt.dy[1],voodoo->banshee_blt.x_inc[1],voodoo->banshee_blt.error[1]); #endif y_end = MIN(voodoo->banshee_blt.ly[1], voodoo->banshee_blt.ry[1]); #if 0 bansheeblt_log("Polyfill : draw spans from %i-%i\n", y, y_end); #endif for (; y < y_end; y++) { #if 0 bansheeblt_log(" %i: %i %i\n", y, voodoo->banshee_blt.lx_cur, voodoo->banshee_blt.rx_cur); #endif /*Draw span from lx_cur to rx_cur*/ if (y >= clip->y_min && y < clip->y_max) { int pat_y = (voodoo->banshee_blt.commandExtra & CMDEXTRA_FORCE_PAT_ROW0) ? 0 : (voodoo->banshee_blt.patoff_y + y); uint8_t pattern_mask = pattern_mono[pat_y & 7]; for (int x = voodoo->banshee_blt.lx_cur; x < voodoo->banshee_blt.rx_cur; x++) { int pat_x = voodoo->banshee_blt.patoff_x + x; int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7 - (pat_x & 7)))) : 1; if (x >= clip->x_min && x < clip->x_max && pattern_trans) PLOT(voodoo, x, y, pat_x, pat_y, pattern_mask, rop, voodoo->banshee_blt.colorFore, COLORKEY_32); } } voodoo->banshee_blt.error[0] -= voodoo->banshee_blt.dx[0]; while (voodoo->banshee_blt.error[0] < 0) { voodoo->banshee_blt.error[0] += voodoo->banshee_blt.dy[0]; voodoo->banshee_blt.lx_cur += voodoo->banshee_blt.x_inc[0]; } voodoo->banshee_blt.error[1] -= voodoo->banshee_blt.dx[1]; while (voodoo->banshee_blt.error[1] < 0) { voodoo->banshee_blt.error[1] += voodoo->banshee_blt.dy[1]; voodoo->banshee_blt.rx_cur += voodoo->banshee_blt.x_inc[1]; } } if (voodoo->banshee_blt.ry[1] == voodoo->banshee_blt.ly[1]) { voodoo->banshee_blt.lx[0] = voodoo->banshee_blt.lx[1]; voodoo->banshee_blt.ly[0] = voodoo->banshee_blt.ly[1]; voodoo->banshee_blt.rx[0] = voodoo->banshee_blt.rx[1]; voodoo->banshee_blt.ry[0] = voodoo->banshee_blt.ry[1]; } else if (voodoo->banshee_blt.ry[1] >= voodoo->banshee_blt.ly[1]) { voodoo->banshee_blt.lx[0] = voodoo->banshee_blt.lx[1]; voodoo->banshee_blt.ly[0] = voodoo->banshee_blt.ly[1]; } else { voodoo->banshee_blt.rx[0] = voodoo->banshee_blt.rx[1]; voodoo->banshee_blt.ry[0] = voodoo->banshee_blt.ry[1]; } } static void banshee_do_2d_blit(voodoo_t *voodoo, int count, uint32_t data) { switch (voodoo->banshee_blt.command & COMMAND_CMD_MASK) { case COMMAND_CMD_NOP: break; case COMMAND_CMD_SCREEN_TO_SCREEN_BLT: banshee_do_screen_to_screen_blt(voodoo); break; case COMMAND_CMD_SCREEN_TO_SCREEN_STRETCH_BLT: banshee_do_screen_to_screen_stretch_blt(voodoo); break; case COMMAND_CMD_HOST_TO_SCREEN_BLT: banshee_do_host_to_screen_blt(voodoo, count, data); break; case COMMAND_CMD_HOST_TO_SCREEN_STRETCH_BLT: banshee_do_host_to_screen_stretch_blt(voodoo, count, data); break; case COMMAND_CMD_RECTFILL: banshee_do_rectfill(voodoo); break; case COMMAND_CMD_LINE: banshee_do_line(voodoo, 1); break; case COMMAND_CMD_POLYLINE: banshee_do_line(voodoo, 0); break; default: fatal("banshee_do_2d_blit: unknown command=%08x\n", voodoo->banshee_blt.command); } } void voodoo_2d_reg_writel(voodoo_t *voodoo, uint32_t addr, uint32_t val) { #if 0 if ((addr & 0x1fc) != 0x80) bansheeblt_log("2D reg write %03x %08x\n", addr & 0x1fc, val); #endif switch (addr & 0x1fc) { case 0x08: voodoo->banshee_blt.clip0Min = val; voodoo->banshee_blt.clip[0].x_min = val & 0xfff; voodoo->banshee_blt.clip[0].y_min = (val >> 16) & 0xfff; break; case 0x0c: voodoo->banshee_blt.clip0Max = val; voodoo->banshee_blt.clip[0].x_max = val & 0xfff; voodoo->banshee_blt.clip[0].y_max = (val >> 16) & 0xfff; break; case 0x10: voodoo->banshee_blt.dstBaseAddr = val & 0xffffff; voodoo->banshee_blt.dstBaseAddr_tiled = val & 0x80000000; if (voodoo->banshee_blt.dstBaseAddr_tiled) voodoo->banshee_blt.dst_stride = (voodoo->banshee_blt.dstFormat & DST_FORMAT_STRIDE_MASK) * 128 * 32; else voodoo->banshee_blt.dst_stride = voodoo->banshee_blt.dstFormat & DST_FORMAT_STRIDE_MASK; #if 0 bansheeblt_log("dstBaseAddr=%08x\n", val); #endif break; case 0x14: voodoo->banshee_blt.dstFormat = val; if (voodoo->banshee_blt.dstBaseAddr_tiled) voodoo->banshee_blt.dst_stride = (voodoo->banshee_blt.dstFormat & DST_FORMAT_STRIDE_MASK) * 128 * 32; else voodoo->banshee_blt.dst_stride = voodoo->banshee_blt.dstFormat & DST_FORMAT_STRIDE_MASK; #if 0 bansheeblt_log("dstFormat=%08x\n", val); #endif break; case 0x18: voodoo->banshee_blt.srcColorkeyMin = val & 0xffffff; break; case 0x1c: voodoo->banshee_blt.srcColorkeyMax = val & 0xffffff; break; case 0x20: voodoo->banshee_blt.dstColorkeyMin = val & 0xffffff; break; case 0x24: voodoo->banshee_blt.dstColorkeyMax = val & 0xffffff; break; case 0x28: voodoo->banshee_blt.bresError0 = val; voodoo->banshee_blt.bres_error_0 = val & 0xffff; break; case 0x2c: voodoo->banshee_blt.bresError1 = val; voodoo->banshee_blt.bres_error_1 = val & 0xffff; break; case 0x30: voodoo->banshee_blt.rop = val; voodoo->banshee_blt.rops[1] = val & 0xff; voodoo->banshee_blt.rops[2] = (val >> 8) & 0xff; voodoo->banshee_blt.rops[3] = (val >> 16) & 0xff; #if 0 bansheeblt_log("rop=%08x\n", val); #endif break; case 0x34: voodoo->banshee_blt.srcBaseAddr = val & 0xffffff; voodoo->banshee_blt.srcBaseAddr_tiled = val & 0x80000000; if (voodoo->banshee_blt.srcBaseAddr_tiled) voodoo->banshee_blt.src_stride = (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK) * 128 * 32; else voodoo->banshee_blt.src_stride = voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK; update_src_stride(voodoo); #if 0 bansheeblt_log("srcBaseAddr=%08x\n", val); #endif break; case 0x38: voodoo->banshee_blt.commandExtra = val; #if 0 bansheeblt_log("commandExtra=%08x\n", val); #endif break; case 0x3c: voodoo->banshee_blt.lineStipple = val; break; case 0x40: voodoo->banshee_blt.lineStyle = val; voodoo->banshee_blt.line_rep_cnt = val & 0xff; voodoo->banshee_blt.line_bit_mask_size = (val >> 8) & 0x1f; voodoo->banshee_blt.line_pix_pos = (val >> 16) & 0xff; voodoo->banshee_blt.line_bit_pos = (val >> 24) & 0x1f; break; case 0x44: voodoo->banshee_blt.colorPattern[0] = val; #if 0 bansheeblt_log("colorPattern0=%08x\n", val); #endif voodoo->banshee_blt.colorPattern24[0] = val & 0xffffff; voodoo->banshee_blt.colorPattern24[1] = (voodoo->banshee_blt.colorPattern24[1] & 0xffff00) | (val >> 24); voodoo->banshee_blt.colorPattern16[0] = val & 0xffff; voodoo->banshee_blt.colorPattern16[1] = (val >> 16) & 0xffff; voodoo->banshee_blt.colorPattern8[0] = val & 0xff; voodoo->banshee_blt.colorPattern8[1] = (val >> 8) & 0xff; voodoo->banshee_blt.colorPattern8[2] = (val >> 16) & 0xff; voodoo->banshee_blt.colorPattern8[3] = (val >> 24) & 0xff; break; case 0x48: voodoo->banshee_blt.colorPattern[1] = val; #if 0 bansheeblt_log("colorPattern1=%08x\n", val); #endif voodoo->banshee_blt.colorPattern24[1] = (voodoo->banshee_blt.colorPattern24[1] & 0xff) | ((val & 0xffff) << 8); voodoo->banshee_blt.colorPattern24[2] = (voodoo->banshee_blt.colorPattern24[2] & 0xff0000) | (val >> 16); voodoo->banshee_blt.colorPattern16[2] = val & 0xffff; voodoo->banshee_blt.colorPattern16[3] = (val >> 16) & 0xffff; voodoo->banshee_blt.colorPattern8[4] = val & 0xff; voodoo->banshee_blt.colorPattern8[5] = (val >> 8) & 0xff; voodoo->banshee_blt.colorPattern8[6] = (val >> 16) & 0xff; voodoo->banshee_blt.colorPattern8[7] = (val >> 24) & 0xff; break; case 0x4c: voodoo->banshee_blt.clip1Min = val; voodoo->banshee_blt.clip[1].x_min = val & 0xfff; voodoo->banshee_blt.clip[1].y_min = (val >> 16) & 0xfff; break; case 0x50: voodoo->banshee_blt.clip1Max = val; voodoo->banshee_blt.clip[1].x_max = val & 0xfff; voodoo->banshee_blt.clip[1].y_max = (val >> 16) & 0xfff; break; case 0x54: voodoo->banshee_blt.srcFormat = val; if (voodoo->banshee_blt.srcBaseAddr_tiled) voodoo->banshee_blt.src_stride = (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK) * 128 * 32; else voodoo->banshee_blt.src_stride = voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK; update_src_stride(voodoo); switch (voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) { case SRC_FORMAT_COL_1_BPP: voodoo->banshee_blt.src_bpp = 1; break; case SRC_FORMAT_COL_8_BPP: voodoo->banshee_blt.src_bpp = 8; break; case SRC_FORMAT_COL_24_BPP: voodoo->banshee_blt.src_bpp = 24; break; case SRC_FORMAT_COL_32_BPP: case SRC_FORMAT_COL_YUYV: case SRC_FORMAT_COL_UYVY: voodoo->banshee_blt.src_bpp = 32; break; case SRC_FORMAT_COL_16_BPP: default: voodoo->banshee_blt.src_bpp = 16; break; } #if 0 bansheeblt_log("srcFormat=%08x\n", val); #endif break; case 0x58: voodoo->banshee_blt.srcSize = val; voodoo->banshee_blt.srcSizeX = voodoo->banshee_blt.srcSize & 0x1fff; voodoo->banshee_blt.srcSizeY = (voodoo->banshee_blt.srcSize >> 16) & 0x1fff; update_src_stride(voodoo); #if 0 bansheeblt_log("srcSize=%08x\n", val); #endif break; case 0x5c: voodoo->banshee_blt.srcXY = val; voodoo->banshee_blt.srcX = ((int32_t) (val << 19)) >> 19; voodoo->banshee_blt.srcY = ((int32_t) (val << 3)) >> 19; update_src_stride(voodoo); #if 0 bansheeblt_log("srcXY=%08x\n", val); #endif break; case 0x60: voodoo->banshee_blt.colorBack = val; break; case 0x64: voodoo->banshee_blt.colorFore = val; break; case 0x68: voodoo->banshee_blt.dstSize = val; voodoo->banshee_blt.dstSizeX = voodoo->banshee_blt.dstSize & 0x1fff; voodoo->banshee_blt.dstSizeY = (voodoo->banshee_blt.dstSize >> 16) & 0x1fff; update_src_stride(voodoo); #if 0 bansheeblt_log("dstSize=%08x\n", val); #endif break; case 0x6c: voodoo->banshee_blt.dstXY = val; voodoo->banshee_blt.dstX = ((int32_t) (val << 19)) >> 19; voodoo->banshee_blt.dstY = ((int32_t) (val << 3)) >> 19; #if 0 bansheeblt_log("dstXY=%08x\n", val); #endif break; case 0x70: voodoo_wait_for_render_thread_idle(voodoo); voodoo->banshee_blt.command = val; voodoo->banshee_blt.rops[0] = val >> 24; #if 0 bansheeblt_log("command=%x %08x\n", voodoo->banshee_blt.command & COMMAND_CMD_MASK, val); #endif voodoo->banshee_blt.patoff_x = (val & COMMAND_PATOFF_X_MASK) >> COMMAND_PATOFF_X_SHIFT; voodoo->banshee_blt.patoff_y = (val & COMMAND_PATOFF_Y_MASK) >> COMMAND_PATOFF_Y_SHIFT; voodoo->banshee_blt.cur_x = 0; voodoo->banshee_blt.cur_y = 0; voodoo->banshee_blt.dstX = ((int32_t) (voodoo->banshee_blt.dstXY << 19)) >> 19; voodoo->banshee_blt.dstY = ((int32_t) (voodoo->banshee_blt.dstXY << 3)) >> 19; voodoo->banshee_blt.srcX = ((int32_t) (voodoo->banshee_blt.srcXY << 19)) >> 19; voodoo->banshee_blt.srcY = ((int32_t) (voodoo->banshee_blt.srcXY << 3)) >> 19; voodoo->banshee_blt.old_srcX = voodoo->banshee_blt.srcX; voodoo->banshee_blt.host_data_remainder = 0; voodoo->banshee_blt.host_data_count = 0; switch (voodoo->banshee_blt.command & COMMAND_CMD_MASK) { #if 0 case COMMAND_CMD_SCREEN_TO_SCREEN_STRETCH_BLT: if (voodoo->banshee_blt.bresError0 & BRES_ERROR_USE) voodoo->banshee_blt.bres_error_0 = (int32_t)(int16_t)(voodoo->banshee_blt.bresError0 & BRES_ERROR_MASK); else voodoo->banshee_blt.bres_error_0 = voodoo->banshee_blt.dstSizeY / 2; if (voodoo->banshee_blt.bresError1 & BRES_ERROR_USE) voodoo->banshee_blt.bres_error_1 = (int32_t)(int16_t)(voodoo->banshee_blt.bresError1 & BRES_ERROR_MASK); else voodoo->banshee_blt.bres_error_1 = voodoo->banshee_blt.dstSizeX / 2; if (val & COMMAND_INITIATE) banshee_do_2d_blit(voodoo, -1, 0); break;*/ #endif case COMMAND_CMD_POLYFILL: if (val & COMMAND_INITIATE) { voodoo->banshee_blt.dstXY = voodoo->banshee_blt.srcXY; voodoo->banshee_blt.dstX = voodoo->banshee_blt.srcX; voodoo->banshee_blt.dstY = voodoo->banshee_blt.srcY; } banshee_polyfill_start(voodoo); break; default: if (val & COMMAND_INITIATE) { banshee_do_2d_blit(voodoo, -1, 0); #if 0 fatal("Initiate command!\n"); #endif } break; } break; case 0x80: case 0x84: case 0x88: case 0x8c: case 0x90: case 0x94: case 0x98: case 0x9c: case 0xa0: case 0xa4: case 0xa8: case 0xac: case 0xb0: case 0xb4: case 0xb8: case 0xbc: case 0xc0: case 0xc4: case 0xc8: case 0xcc: case 0xd0: case 0xd4: case 0xd8: case 0xdc: case 0xe0: case 0xe4: case 0xe8: case 0xec: case 0xf0: case 0xf4: case 0xf8: case 0xfc: #if 0 bansheeblt_log("launch %08x %08x %08x %08x\n", voodoo->banshee_blt.command, voodoo->banshee_blt.commandExtra, voodoo->banshee_blt.srcColorkeyMin, voodoo->banshee_blt.srcColorkeyMax); #endif switch (voodoo->banshee_blt.command & COMMAND_CMD_MASK) { case COMMAND_CMD_SCREEN_TO_SCREEN_BLT: voodoo->banshee_blt.srcXY = val; voodoo->banshee_blt.srcX = ((int32_t) (val << 19)) >> 19; voodoo->banshee_blt.srcY = ((int32_t) (val << 3)) >> 19; banshee_do_screen_to_screen_blt(voodoo); break; case COMMAND_CMD_HOST_TO_SCREEN_BLT: banshee_do_2d_blit(voodoo, 32, val); break; case COMMAND_CMD_HOST_TO_SCREEN_STRETCH_BLT: banshee_do_2d_blit(voodoo, 32, val); break; case COMMAND_CMD_RECTFILL: voodoo->banshee_blt.dstXY = val; voodoo->banshee_blt.dstX = ((int32_t) (val << 19)) >> 19; voodoo->banshee_blt.dstY = ((int32_t) (val << 3)) >> 19; banshee_do_rectfill(voodoo); break; case COMMAND_CMD_LINE: voodoo->banshee_blt.dstXY = val; voodoo->banshee_blt.dstX = ((int32_t) (val << 19)) >> 19; voodoo->banshee_blt.dstY = ((int32_t) (val << 3)) >> 19; banshee_do_line(voodoo, 1); break; case COMMAND_CMD_POLYLINE: voodoo->banshee_blt.dstXY = val; voodoo->banshee_blt.dstX = ((int32_t) (val << 19)) >> 19; voodoo->banshee_blt.dstY = ((int32_t) (val << 3)) >> 19; banshee_do_line(voodoo, 0); break; case COMMAND_CMD_POLYFILL: banshee_polyfill_continue(voodoo, val); break; default: fatal("launch area write, command=%08x\n", voodoo->banshee_blt.command); } break; case 0x100: case 0x104: case 0x108: case 0x10c: case 0x110: case 0x114: case 0x118: case 0x11c: case 0x120: case 0x124: case 0x128: case 0x12c: case 0x130: case 0x134: case 0x138: case 0x13c: case 0x140: case 0x144: case 0x148: case 0x14c: case 0x150: case 0x154: case 0x158: case 0x15c: case 0x160: case 0x164: case 0x168: case 0x16c: case 0x170: case 0x174: case 0x178: case 0x17c: case 0x180: case 0x184: case 0x188: case 0x18c: case 0x190: case 0x194: case 0x198: case 0x19c: case 0x1a0: case 0x1a4: case 0x1a8: case 0x1ac: case 0x1b0: case 0x1b4: case 0x1b8: case 0x1bc: case 0x1c0: case 0x1c4: case 0x1c8: case 0x1cc: case 0x1d0: case 0x1d4: case 0x1d8: case 0x1dc: case 0x1e0: case 0x1e4: case 0x1e8: case 0x1ec: case 0x1f0: case 0x1f4: case 0x1f8: case 0x1fc: voodoo->banshee_blt.colorPattern[(addr >> 2) & 63] = val; if ((addr & 0x1fc) < 0x1c0) { int base_addr = (addr & 0xfc) / 0xc; uintptr_t src_p = (uintptr_t) &voodoo->banshee_blt.colorPattern[base_addr * 3]; int col24 = base_addr * 4; voodoo->banshee_blt.colorPattern24[col24] = *(uint32_t *) src_p & 0xffffff; voodoo->banshee_blt.colorPattern24[col24 + 1] = *(uint32_t *) (src_p + 3) & 0xffffff; voodoo->banshee_blt.colorPattern24[col24 + 2] = *(uint32_t *) (src_p + 6) & 0xffffff; voodoo->banshee_blt.colorPattern24[col24 + 3] = *(uint32_t *) (src_p + 9) & 0xffffff; } if ((addr & 0x1fc) < 0x180) { voodoo->banshee_blt.colorPattern16[(addr >> 1) & 62] = val & 0xffff; voodoo->banshee_blt.colorPattern16[((addr >> 1) & 62) + 1] = (val >> 16) & 0xffff; } if ((addr & 0x1fc) < 0x140) { voodoo->banshee_blt.colorPattern8[addr & 60] = val & 0xff; voodoo->banshee_blt.colorPattern8[(addr & 60) + 1] = (val >> 8) & 0xff; voodoo->banshee_blt.colorPattern8[(addr & 60) + 2] = (val >> 16) & 0xff; voodoo->banshee_blt.colorPattern8[(addr & 60) + 3] = (val >> 24) & 0xff; } #if 0 bansheeblt_log("colorPattern%02x=%08x\n", (addr >> 2) & 63, val); #endif break; default: fatal("Unknown 2D reg write %03x %08x\n", addr & 0x1fc, val); } }