From 3e314ccdfb6b924652cc50bfc2edec779a3640d7 Mon Sep 17 00:00:00 2001 From: TomW Date: Sat, 26 Sep 2015 17:56:55 +0100 Subject: [PATCH] Implemented ViRGE 2D Polygon Fill command. Improvements to ViRGE line draw. --- src/vid_s3_virge.c | 131 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 118 insertions(+), 13 deletions(-) diff --git a/src/vid_s3_virge.c b/src/vid_s3_virge.c index 41cbeb7..6e8b7d7 100644 --- a/src/vid_s3_virge.c +++ b/src/vid_s3_virge.c @@ -143,6 +143,14 @@ typedef struct virge_t uint32_t pattern_8[8*8]; uint32_t pattern_16[8*8]; uint32_t pattern_32[8*8]; + + uint32_t prdx; + uint32_t prxstart; + uint32_t pldx; + uint32_t plxstart; + uint32_t pystart; + uint32_t pycnt; + uint32_t dest_l, dest_r; } s3d; s3d_t s3d_tri; @@ -237,6 +245,7 @@ enum CMD_SET_COMMAND_BITBLT = (0 << 27), CMD_SET_COMMAND_RECTFILL = (2 << 27), CMD_SET_COMMAND_LINE = (3 << 27), + CMD_SET_COMMAND_POLY = (5 << 27), CMD_SET_COMMAND_NOP = (15 << 27) }; @@ -790,10 +799,10 @@ static uint32_t s3_virge_mmio_read_l(uint32_t addr, void *p) case 0xa4e4: ret = (virge->s3d.dest_str << 16) | virge->s3d.src_str; break; - case 0xa4e8: + case 0xa4e8: case 0xace8: ret = virge->s3d.mono_pat_0; break; - case 0xa4ec: + case 0xa4ec: case 0xacec: ret = virge->s3d.mono_pat_1; break; case 0xa4f0: @@ -1080,16 +1089,16 @@ static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) virge->s3d.dest_str = (val >> 16) & 0xff8; virge->s3d.src_str = val & 0xff8; break; - case 0xa4e8: + case 0xa4e8: case 0xace8: virge->s3d.mono_pat_0 = val; break; - case 0xa4ec: + case 0xa4ec: case 0xacec: virge->s3d.mono_pat_1 = val; break; - case 0xa4f0: + case 0xa4f0: case 0xacf0: virge->s3d.pat_bg_clr = val; break; - case 0xa4f4: case 0xa8f4: + case 0xa4f4: case 0xa8f4: case 0xacf4: virge->s3d.pat_fg_clr = val; break; case 0xa4f8: @@ -1136,6 +1145,32 @@ static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) if (virge->s3d.cmd_set & CMD_SET_AE) s3_virge_bitblt(virge, -1, 0); break; + + case 0xad00: + virge->s3d.cmd_set = val; + if (!(val & CMD_SET_AE)) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xad68: + virge->s3d.prdx = val; + break; + case 0xad6c: + virge->s3d.prxstart = val; + break; + case 0xad70: + virge->s3d.pldx = val; + break; + case 0xad74: + virge->s3d.plxstart = val; + break; + case 0xad78: + virge->s3d.pystart = val & 0x7ff; + break; + case 0xad7c: + virge->s3d.pycnt = val & 0x300007ff; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; case 0xb4d4: virge->s3d_tri.z_base = val & 0x3ffff8; @@ -1651,17 +1686,30 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) virge->s3d.dest_y = virge->s3d.lystart; virge->s3d.h = virge->s3d.lycnt; virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; - if (virge->s3d.ldx >= 0) - virge->s3d.dest_x -= virge->s3d.ldx / 2; - else - virge->s3d.dest_x += virge->s3d.ldx / 2; - //virge->s3d.dest_dest_x = virge->s3d.dest_x + virge->s3d.ldx; } while (virge->s3d.h) { - int x = virge->s3d.dest_x >> 20; - int new_x = (virge->s3d.dest_x + virge->s3d.ldx) >> 20; + int x; + int new_x; + int first_pixel = 1; + x = virge->s3d.dest_x >> 20; + + if (virge->s3d.h == virge->s3d.lycnt && + ((virge->s3d.line_dir && x > virge->s3d.lxend0) || + (!virge->s3d.line_dir && x < virge->s3d.lxend0))) + x = virge->s3d.lxend0; + + if (virge->s3d.h == 1) + new_x = virge->s3d.lxend1 + (virge->s3d.line_dir ? 1 : -1); + else + new_x = (virge->s3d.dest_x + virge->s3d.ldx) >> 20; + + + if ((virge->s3d.line_dir && x > new_x) || + (!virge->s3d.line_dir && x < new_x)) + goto skip_line; + do { uint32_t dest_addr = virge->s3d.dest_base + (x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str); @@ -1669,6 +1717,16 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) uint32_t out = 0; int update = 1; + if ((virge->s3d.h == virge->s3d.lycnt || !first_pixel) && + ((virge->s3d.line_dir && x < virge->s3d.lxend0) || + (!virge->s3d.line_dir && x > virge->s3d.lxend0))) + update = 0; + + if ((virge->s3d.h == 1 || !first_pixel) && + ((virge->s3d.line_dir && x > virge->s3d.lxend1) || + (!virge->s3d.line_dir && x < virge->s3d.lxend1))) + update = 0; + CLIP(x, virge->s3d.dest_y); if (update) @@ -1685,14 +1743,61 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) x++; else if (x > new_x) x--; + first_pixel = 0; } while (x != new_x); +skip_line: virge->s3d.dest_x += virge->s3d.ldx; virge->s3d.dest_y--; virge->s3d.h--; } break; + case CMD_SET_COMMAND_POLY: + /*No source*/ + if (virge->s3d.pycnt & (1 << 28)) + virge->s3d.dest_r = virge->s3d.prxstart; + if (virge->s3d.pycnt & (1 << 29)) + virge->s3d.dest_l = virge->s3d.plxstart; + virge->s3d.h = virge->s3d.pycnt & 0x7ff; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + //pclog("Start poly - l=%08x r=%08x h=%i rop=%02x\n", virge->s3d.dest_l, virge->s3d.dest_r, virge->s3d.h, virge->s3d.rop); + while (virge->s3d.h) + { + int x = virge->s3d.dest_l >> 20; + int xend = virge->s3d.dest_r >> 20; + int y = virge->s3d.pystart & 0x7ff; + int xdir = (x < xend) ? 1 : -1; + //pclog(" %03i: %i - %i %08x-%08x\n", y, x, xend, virge->s3d.dest_l, virge->s3d.dest_r); + do + { + uint32_t dest_addr = virge->s3d.dest_base + (x * x_mul) + (y * virge->s3d.dest_str); + uint32_t source = 0, dest, pattern; + uint32_t out = 0; + int update = 1; + + CLIP(x, y); + + if (update) + { + READ(dest_addr, dest); + pattern = pattern_data[(y & 7)*8 + (x & 7)]; + MIX(); + + WRITE(dest_addr, out); + } + + x = (x + xdir) & 0x7ff; + } + while (x != (xend + xdir)); + + virge->s3d.dest_l += virge->s3d.pldx; + virge->s3d.dest_r += virge->s3d.prdx; + virge->s3d.h--; + virge->s3d.pystart = (virge->s3d.pystart - 1) & 0x7ff; + } + break; + default: fatal("s3_virge_bitblt : blit command %i %08x\n", (virge->s3d.cmd_set >> 27) & 0xf, virge->s3d.cmd_set); }