From 917a21b2936a5d4f114d12202a1489537bcc605b Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sat, 10 Oct 2020 17:15:35 +0300 Subject: [PATCH] PCem RTG updates and fixes. --- pcem/vid_cl5429.cpp | 91 +++++++++++++++++++++++---- pcem/vid_s3.cpp | 133 ++++++++++++++++++++++++++------------- pcem/vid_s3_virge.cpp | 81 ++++++++++++++++++++---- pcem/vid_svga.cpp | 55 ++++++++++------ pcem/vid_svga.h | 1 + pcem/vid_svga_render.cpp | 71 +++++++++++---------- 6 files changed, 312 insertions(+), 120 deletions(-) diff --git a/pcem/vid_cl5429.cpp b/pcem/vid_cl5429.cpp index 849ed71e..7ad082dc 100644 --- a/pcem/vid_cl5429.cpp +++ b/pcem/vid_cl5429.cpp @@ -767,10 +767,12 @@ void gd5429_out(uint16_t addr, uint8_t val, void *p) svga->crtc[svga->crtcreg] = val; if (svga->crtcreg == 0x11) { - if (!(val & 0x10)) - gd5429->vblank_irq = -1; - else if (gd5429->vblank_irq < 0) + if (!(val & 0x10)) { + if (gd5429->vblank_irq > 0) + gd5429->vblank_irq = -1; + } else if (gd5429->vblank_irq < 0) { gd5429->vblank_irq = 0; + } gd5429_update_irqs(gd5429); } @@ -1153,8 +1155,14 @@ void gd5429_recalctimings(svga_t *svga) svga->interlace = svga->crtc[0x1a] & 1; - if (svga->seqregs[7] & 0x01) + svga->horizontal_linedbl = svga->dispend * 9 / 10 >= svga->hdisp; + + if (svga->seqregs[7] & 0x01) { + if (svga->horizontal_linedbl) + svga->render = svga_render_8bpp_lowres; + else svga->render = svga_render_8bpp_highres; + } svga->ma_latch |= ((svga->crtc[0x1b] & 0x01) << 16) | (((svga->crtc[0x1b] >> 2) & 3) << 17); if (gd5429->type >= CL_TYPE_GD5436) { @@ -1170,23 +1178,35 @@ void gd5429_recalctimings(svga_t *svga) switch (gd5429->hidden_dac_reg & 0xf) { case 0x0: - svga->render = svga_render_15bpp_highres; + if (svga->horizontal_linedbl) + svga->render = svga_render_15bpp_lowres; + else + svga->render = svga_render_15bpp_highres; svga->bpp = 15; break; case 0x1: - svga->render = svga_render_16bpp_highres; + if (svga->horizontal_linedbl) + svga->render = svga_render_16bpp_lowres; + else + svga->render = svga_render_16bpp_highres; svga->bpp = 16; break; case 0x5: if (gd5429->type >= CL_TYPE_GD5434 && (svga->seqregs[7] & 8)) { - svga->render = svga_render_32bpp_highres; + if (svga->horizontal_linedbl) + svga->render = svga_render_32bpp_lowres; + else + svga->render = svga_render_32bpp_highres; svga->bpp = 32; svga->rowoffset *= 2; } else { - svga->render = svga_render_24bpp_highres; + if (svga->horizontal_linedbl) + svga->render = svga_render_24bpp_lowres; + else + svga->render = svga_render_24bpp_highres; svga->bpp = 24; } break; @@ -1194,7 +1214,10 @@ void gd5429_recalctimings(svga_t *svga) } else { - svga->render = svga_render_15bpp_highres; + if (svga->horizontal_linedbl) + svga->render = svga_render_15bpp_lowres; + else + svga->render = svga_render_15bpp_highres; svga->bpp = 15; } } @@ -1231,6 +1254,8 @@ void gd5429_hwcursor_draw(svga_t *svga, int displine) int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; int line_offset = (svga->seqregs[0x12] & 0x04) ? 16 : 4; + offset <<= svga->horizontal_linedbl; + if (svga->interlace && svga->hwcursor_oddeven) svga->hwcursor_latch.addr += line_offset; @@ -1886,23 +1911,31 @@ void gd5429_start_blit(uint32_t cpu_dat, int count, void *p) int fg_col = gd5429->blt.fg_col; int bg_col = gd5429->blt.bg_col; int x_max = 0; + int bplcnt = 0; + int bpp; + uint8_t dststore[4]; + int maskstore = 0; switch (gd5429->blt.depth) { case BLIT_DEPTH_8: x_max = 8; + bpp = 1; break; case BLIT_DEPTH_16: x_max = 16; blt_mask *= 2; + bpp = 2; break; case BLIT_DEPTH_24: x_max = 24; blt_mask *= 3; + bpp = 3; break; case BLIT_DEPTH_32: x_max = 32; blt_mask *= 4; + bpp = 4; break; } @@ -1924,8 +1957,8 @@ void gd5429_start_blit(uint32_t cpu_dat, int count, void *p) gd5429->blt.y_count = gd5429->blt.src_addr & 7; else gd5429->blt.y_count = 0; -// pclog("gd5429_start_blit : size %i, %i %i %02x %02x %02x %02x\n", -// gd5429->blt.width, gd5429->blt.height, gd5429->blt.x_count, gd5429->blt.rop, gd5429->blt.mode, gd5429->blt.extensions, gd5429->blt.mask); +// pclog("gd5429_start_blit : size %i, %i %i %02x %02x %02x %02x %d\n", +// gd5429->blt.width, gd5429->blt.height, gd5429->blt.x_count, gd5429->blt.rop, gd5429->blt.mode, gd5429->blt.extensions, gd5429->blt.mask, gd5429->blt.depth); if (gd5429->blt.mode & 0x04) { @@ -2135,6 +2168,40 @@ void gd5429_start_blit(uint32_t cpu_dat, int count, void *p) case 0xda: dst = ~(src & dst); break; } + dststore[bplcnt++] = dst; + maskstore |= mask; + if (bplcnt >= bpp) { + if (bpp == 1) { + if ((gd5429->blt.width_backup - gd5429->blt.width) >= blt_mask && + !((gd5429->blt.mode & 0x08) && !mask)) + svga->vram[gd5429->blt.dst_addr & svga->vram_mask] = dst; + } else if (bpp == 2) { + if ((gd5429->blt.width_backup - gd5429->blt.width) >= blt_mask && + !((gd5429->blt.mode & 0x08) && !maskstore)) { + svga->vram[(gd5429->blt.dst_addr + 0) & svga->vram_mask] = dststore[0]; + svga->vram[(gd5429->blt.dst_addr + 1) & svga->vram_mask] = dststore[1]; + } + } else if (bpp == 3) { + if ((gd5429->blt.width_backup - gd5429->blt.width) >= blt_mask && + !((gd5429->blt.mode & 0x08) && !maskstore)) { + svga->vram[(gd5429->blt.dst_addr + 0) & svga->vram_mask] = dststore[0]; + svga->vram[(gd5429->blt.dst_addr + 1) & svga->vram_mask] = dststore[1]; + svga->vram[(gd5429->blt.dst_addr + 2) & svga->vram_mask] = dststore[2]; + } + } else if (bpp == 3) { + if ((gd5429->blt.width_backup - gd5429->blt.width) >= blt_mask && + !((gd5429->blt.mode & 0x08) && !maskstore)) { + svga->vram[(gd5429->blt.dst_addr + 0) & svga->vram_mask] = dststore[0]; + svga->vram[(gd5429->blt.dst_addr + 1) & svga->vram_mask] = dststore[1]; + svga->vram[(gd5429->blt.dst_addr + 2) & svga->vram_mask] = dststore[2]; + svga->vram[(gd5429->blt.dst_addr + 3) & svga->vram_mask] = dststore[3]; + } + } + gd5429->blt.dst_addr += ((gd5429->blt.mode & 0x01) ? -bpp : bpp); + bplcnt = 0; + maskstore = 0; + } +#if 0 if (0 && gd5429->type <= CL_TYPE_GD5428) { if ((gd5429->blt.width_backup - gd5429->blt.width) >= blt_mask && @@ -2147,8 +2214,8 @@ void gd5429_start_blit(uint32_t cpu_dat, int count, void *p) !((gd5429->blt.mode & 0x08) && !mask)) svga->vram[gd5429->blt.dst_addr & svga->vram_mask] = dst; } - gd5429->blt.dst_addr += ((gd5429->blt.mode & 0x01) ? -1 : 1); +#endif gd5429->blt.x_count++; if (gd5429->blt.x_count == x_max) diff --git a/pcem/vid_s3.cpp b/pcem/vid_s3.cpp index 490a73b7..030dc59a 100644 --- a/pcem/vid_s3.cpp +++ b/pcem/vid_s3.cpp @@ -134,6 +134,7 @@ typedef struct s3_t fifo_entry_t fifo[FIFO_SIZE]; volatile int fifo_read_idx, fifo_write_idx; + volatile int fifo_thread_state; thread_t *fifo_thread; event_t *wake_fifo_thread; event_t *fifo_not_full_event; @@ -882,7 +883,8 @@ static void fifo_thread(void *param) { s3_t *s3 = (s3_t *)param; - while (1) + s3->fifo_thread_state = 1; + while (s3->fifo_thread_state > 0) { thread_set_event(s3->fifo_not_full_event); thread_wait_event(s3->wake_fifo_thread, -1); @@ -929,6 +931,7 @@ static void fifo_thread(void *param) s3->subsys_stat |= INT_FIFO_EMP; s3_update_irqs(s3); } + s3->fifo_thread_state = 0; } static void s3_vblank_start(svga_t *svga) @@ -1241,6 +1244,8 @@ void s3_recalctimings(svga_t *svga) svga->interlace = svga->crtc[0x42] & 0x20; //svga->clock = (cpuclock * (float)(1ull << 32)) / s3->getclock(clk_sel, s3->getclock_p); + svga->horizontal_linedbl = svga->dispend * 9 / 10 >= svga->hdisp; + switch (svga->crtc[0x67] >> 4) { case 3: case 5: case 7: @@ -1254,22 +1259,37 @@ void s3_recalctimings(svga_t *svga) switch (svga->bpp) { case 8: - svga->render = svga_render_8bpp_highres; + if (svga->horizontal_linedbl) + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; break; case 15: - svga->render = svga_render_15bpp_highres; + if (svga->horizontal_linedbl) + svga->render = svga_render_15bpp_lowres; + else + svga->render = svga_render_15bpp_highres; svga->hdisp /= 2; break; case 16: - svga->render = svga_render_16bpp_highres; + if (svga->horizontal_linedbl) + svga->render = svga_render_16bpp_lowres; + else + svga->render = svga_render_16bpp_highres; svga->hdisp /= 2; break; case 24: - svga->render = svga_render_24bpp_highres; + if (svga->horizontal_linedbl) + svga->render = svga_render_24bpp_lowres; + else + svga->render = svga_render_24bpp_highres; svga->hdisp /= 3; break; case 32: - svga->render = svga_render_32bpp_highres; + if (svga->horizontal_linedbl) + svga->render = svga_render_32bpp_lowres; + else + svga->render = svga_render_32bpp_highres; if (s3->chip != S3_TRIO32 && s3->chip != S3_TRIO64) svga->hdisp /= 4; break; @@ -1755,10 +1775,30 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat int compare_mode = (s3->accel.multifunc[0xe] >> 7) & 3; uint32_t rd_mask = s3->accel.rd_mask; int cmd = s3->accel.cmd >> 13; + uint32_t srcbase, dstbase; if ((s3->chip == S3_TRIO64) && (s3->accel.cmd & (1 << 11))) cmd |= 8; + // SRC-BASE/DST-BASE + if ((s3->accel.multifunc[13] >> 4) & 7) { + srcbase = 0x100000 * ((s3->accel.multifunc[13] >> 4) & 3); + } else { + srcbase = 0x100000 * ((s3->accel.multifunc[14] >> 2) & 3); + } + if ((s3->accel.multifunc[13] >> 0) & 7) { + dstbase = 0x100000 * ((s3->accel.multifunc[13] >> 0) & 3); + } else { + dstbase = 0x100000 * ((s3->accel.multifunc[14] >> 0) & 3); + } + if (s3->bpp == 1) { + srcbase >>= 1; + dstbase >>= 1; + } else if (s3->bpp == 3) { + srcbase >>= 2; + dstbase >>= 2; + } + // Amiga CGX4 driver sets all clipping values to FFF. if (clip_t == 0xfff) clip_t = 0; @@ -1766,9 +1806,9 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat clip_l = 0; s3->force_busy = 1; -//return; -// if (!cpu_input) pclog("Start S3 command %i %i, %i %i, %i (clip %i, %i to %i, %i %i)\n", s3->accel.cmd >> 13, s3->accel.cur_x, s3->accel.cur_y, s3->accel.maj_axis_pcnt & 0xfff, s3->accel.multifunc[0] & 0xfff, clip_l, clip_t, clip_r, clip_b, s3->accel.multifunc[0xe] & 0x20); -// else pclog(" S3 command %i, %i, %08x %08x\n", s3->accel.cmd >> 13, count, mix_dat, cpu_dat); + //return; + //if (!cpu_input) pclog("Start S3 command %i %i, %i %i, %i (clip %i, %i to %i, %i %i)\n", s3->accel.cmd >> 13, s3->accel.cur_x, s3->accel.cur_y, s3->accel.maj_axis_pcnt & 0xfff, s3->accel.multifunc[0] & 0xfff, clip_l, clip_t, clip_r, clip_b, s3->accel.multifunc[0xe] & 0x20); + //else pclog(" S3 command %i, %i, %08x %08x\n", s3->accel.cmd >> 13, count, mix_dat, cpu_dat); if (!cpu_input) s3->accel.dat_count = 0; if (cpu_input && (s3->accel.multifunc[0xa] & 0xc0) != 0x80) @@ -1827,8 +1867,8 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat { while (count-- && s3->accel.sy >= 0) { - if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && - s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) + if ((s3->accel.cx & 0xfff) >= clip_l && (s3->accel.cx & 0xfff) <= clip_r && + (s3->accel.cy & 0xfff) >= clip_t && (s3->accel.cy & 0xfff) <= clip_b) { switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { @@ -1877,8 +1917,8 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat { while (count-- && s3->accel.sy >= 0) { - if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && - s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) + if ((s3->accel.cx & 0xfff) >= clip_l && (s3->accel.cx & 0xfff) <= clip_r && + (s3->accel.cy & 0xfff) >= clip_t && (s3->accel.cy & 0xfff) <= clip_b) { switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { @@ -1962,7 +2002,7 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->accel.cy = s3->accel.cur_y; if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; - s3->accel.dest = s3->accel.cy * s3->width; + s3->accel.dest = dstbase + s3->accel.cy * s3->width; // pclog("Dest %08X (%i, %i) %04X %04X\n", s3->accel.dest, s3->accel.cx, s3->accel.cy, s3->accel.cur_x, s3->accel.cur_x & 0x1000); } @@ -1975,8 +2015,8 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat while (count-- && s3->accel.sy >= 0) { - if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && - s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) + if ((s3->accel.cx & 0xfff) >= clip_l && (s3->accel.cx & 0xfff) <= clip_r && + (s3->accel.cy & 0xfff) >= clip_t && (s3->accel.cy & 0xfff) <= clip_b) { switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { @@ -2022,7 +2062,7 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (s3->accel.cmd & 0x80) s3->accel.cy++; else s3->accel.cy--; - s3->accel.dest = s3->accel.cy * s3->width; + s3->accel.dest = dstbase + s3->accel.cy * s3->width; s3->accel.sy--; if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; @@ -2052,8 +2092,8 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->accel.cy = s3->accel.cur_y & 0xfff; if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; - s3->accel.src = s3->accel.cy * s3->width; - s3->accel.dest = s3->accel.dy * s3->width; + s3->accel.src = srcbase + s3->accel.cy * s3->width; + s3->accel.dest = dstbase + s3->accel.dy * s3->width; // pclog("Source %08X Dest %08X (%i, %i) - (%i, %i)\n", s3->accel.src, s3->accel.dest, s3->accel.cx, s3->accel.cy, s3->accel.dx, s3->accel.dy); } @@ -2072,8 +2112,8 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat { while (1) { - if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && - s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) + if ((s3->accel.dx & 0xfff) >= clip_l && (s3->accel.dx & 0xfff) <= clip_r && + (s3->accel.dy & 0xfff) >= clip_t && (s3->accel.dy & 0xfff) <= clip_b) { READ_SRC(s3->accel.src + s3->accel.cx, src_dat); READ_DST(s3->accel.dest + s3->accel.dx, dest_dat); @@ -2095,8 +2135,8 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->accel.cy++; s3->accel.dy++; - s3->accel.src = s3->accel.cy * s3->width; - s3->accel.dest = s3->accel.dy * s3->width; + s3->accel.src = srcbase + s3->accel.cy * s3->width; + s3->accel.dest = dstbase + s3->accel.dy * s3->width; s3->accel.sy--; @@ -2109,8 +2149,8 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat { while (count-- && s3->accel.sy >= 0) { - if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && - s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) + if ((s3->accel.dx & 0xfff) >= clip_l && (s3->accel.dx & 0xfff) <= clip_r && + (s3->accel.dy & 0xfff) >= clip_t && (s3->accel.dy & 0xfff) <= clip_b) { if (vram_mask) { @@ -2183,8 +2223,8 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->accel.dy--; } - s3->accel.src = s3->accel.cy * s3->width; - s3->accel.dest = s3->accel.dy * s3->width; + s3->accel.src = srcbase + s3->accel.cy * s3->width; + s3->accel.dest = dstbase + s3->accel.dy * s3->width; s3->accel.sy--; @@ -2217,12 +2257,12 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat // s3->accel.cy = (s3->accel.cy & ~7) | (s3->accel.dy & 7); s3->accel.pattern = (s3->accel.cy * s3->width) + s3->accel.cx; - s3->accel.dest = s3->accel.dy * s3->width; + s3->accel.dest = dstbase + s3->accel.dy * s3->width; s3->accel.cx = s3->accel.dx & 7; s3->accel.cy = s3->accel.dy & 7; - s3->accel.src = s3->accel.pattern + (s3->accel.cy * s3->width); + s3->accel.src = srcbase + s3->accel.pattern + (s3->accel.cy * s3->width); // pclog("Source %08X Dest %08X (%i, %i) - (%i, %i)\n", s3->accel.src, s3->accel.dest, s3->accel.cx, s3->accel.cy, s3->accel.dx, s3->accel.dy); // dumpregs(); @@ -2237,8 +2277,8 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat while (count-- && s3->accel.sy >= 0) { - if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && - s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) + if ((s3->accel.dx & 0xfff) >= clip_l && (s3->accel.dx & 0xfff) <= clip_r && + (s3->accel.dy & 0xfff) >= clip_t && (s3->accel.dy & 0xfff) <= clip_b) { if (vram_mask) { @@ -2310,8 +2350,8 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->accel.dy--; } - s3->accel.src = s3->accel.pattern + (s3->accel.cy * s3->width); - s3->accel.dest = s3->accel.dy * s3->width; + s3->accel.src = srcbase + s3->accel.pattern + (s3->accel.cy * s3->width); + s3->accel.dest = dstbase + s3->accel.dy * s3->width; s3->accel.sy--; @@ -2344,12 +2384,12 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat int y = s3->accel.poly_cy; int x_count = ABS((s3->accel.poly_cx2 >> 20) - s3->accel.poly_x) + 1; - s3->accel.dest = y * s3->width; + s3->accel.dest = dstbase + y * s3->width; while (x_count-- && count--) { - if (s3->accel.poly_x >= clip_l && s3->accel.poly_x <= clip_r && - s3->accel.poly_cy >= clip_t && s3->accel.poly_cy <= clip_b) + if ((s3->accel.poly_x & 0xfff) >= clip_l && (s3->accel.poly_x & 0xfff) <= clip_r && + (s3->accel.poly_cy & 0xfff) >= clip_t && (s3->accel.poly_cy & 0xfff) <= clip_b) { switch (frgd_mix) { @@ -2419,15 +2459,15 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat int y = s3->accel.poly_cy; int x_count = ABS((s3->accel.poly_cx2 >> 20) - s3->accel.poly_x) + 1; - s3->accel.src = s3->accel.pattern + ((y & 7) * s3->width); - s3->accel.dest = y * s3->width; + s3->accel.src = srcbase + s3->accel.pattern + ((y & 7) * s3->width); + s3->accel.dest = dstbase + y * s3->width; while (x_count-- && count--) { int pat_x = s3->accel.poly_x & 7; - if (s3->accel.poly_x >= clip_l && s3->accel.poly_x <= clip_r && - s3->accel.poly_cy >= clip_t && s3->accel.poly_cy <= clip_b) + if ((s3->accel.poly_x & 0xfff) >= clip_l && (s3->accel.poly_x & 0xfff) <= clip_r && + (s3->accel.poly_cy & 0xfff) >= clip_t && (s3->accel.poly_cy & 0xfff) <= clip_b) { if (vram_mask) { @@ -2493,7 +2533,9 @@ void s3_hwcursor_draw(svga_t *svga, int displine) int xx; int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; uint32_t fg = 0, bg = 0; - + + offset <<= svga->horizontal_linedbl; + switch (svga->bpp) { case 15: @@ -2907,7 +2949,14 @@ void s3_close(void *p) svga_close(&s3->svga); - thread_kill(s3->fifo_thread); + if (s3->fifo_thread_state) { + s3->fifo_thread_state = -1; + wake_fifo_thread(s3); + while (s3->fifo_thread_state == -1) { + thread_sleep(1); + } + thread_kill(s3->fifo_thread); + } thread_destroy_event(s3->wake_fifo_thread); thread_destroy_event(s3->fifo_not_full_event); diff --git a/pcem/vid_s3_virge.cpp b/pcem/vid_s3_virge.cpp index b1cb60aa..f7031c59 100644 --- a/pcem/vid_s3_virge.cpp +++ b/pcem/vid_s3_virge.cpp @@ -136,6 +136,7 @@ typedef struct virge_t int pixel_count, tri_count; thread_t *render_thread; + volatile int render_thread_state; event_t *wake_render_thread; event_t *wake_main_thread; event_t *not_full_event; @@ -229,12 +230,14 @@ typedef struct virge_t volatile int fifo_read_idx, fifo_write_idx; thread_t *fifo_thread; + volatile int fifo_thread_state; event_t *wake_fifo_thread; event_t *fifo_not_full_event; int virge_busy; uint8_t subsys_stat, subsys_cntl; + int vblank_irq; } virge_t; static inline void wake_fifo_thread(virge_t *virge) @@ -306,9 +309,16 @@ enum #define INT_3DF_EMP (1 << 6) #define INT_MASK 0xff +static int vsync_enabled(virge_t *virge) +{ + if ((virge->svga.crtc[0x32] & 0x10) && ((!(virge->svga.crtc[0x11] & 0x20) && virge->vblank_irq > 0) || (virge->subsys_stat & virge->subsys_cntl & INT_MASK))) + return 1; + return 0; +} + static void s3_virge_update_irqs(virge_t *virge) { - if ((virge->svga.crtc[0x32] & 0x10) && (virge->subsys_stat & virge->subsys_cntl & INT_MASK)) + if (vsync_enabled(virge)) pci_set_irq(virge->card, PCI_INTA); else pci_clear_irq(virge->card, PCI_INTA); @@ -363,6 +373,15 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *p) svga->crtc[svga->crtcreg] = val; switch (svga->crtcreg) { + case 0x11: + if (!(val & 0x10)) { + if (virge->vblank_irq > 0) + virge->vblank_irq = -1; + } else if (virge->vblank_irq < 0) { + virge->vblank_irq = 0; + } + s3_virge_update_irqs(virge); + break; case 0x31: virge->ma_ext = (virge->ma_ext & 0x1c) | ((val & 0x30) >> 4); break; @@ -493,6 +512,7 @@ static uint8_t s3_virge_in(uint16_t addr, void *p) case 0x3c2: ret = svga_in(addr, svga); ret |= (virge->subsys_stat & INT_VSY) ? 0x80 : 0x00; + ret |= virge->vblank_irq > 0 ? 0x80 : 0x00; break; //case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: // pclog("Read RAMDAC %04X %04X:%04X\n", addr, CS, pc); @@ -572,6 +592,7 @@ static void s3_virge_recalctimings(svga_t *svga) } } + svga->horizontal_linedbl = svga->dispend * 9 / 10 >= svga->hdisp; if ((svga->crtc[0x67] & 0xc) != 0xc) /*VGA mode*/ { @@ -586,19 +607,34 @@ static void s3_virge_recalctimings(svga_t *svga) switch (svga->bpp) { case 8: - svga->render = svga_render_8bpp_highres; + if (svga->horizontal_linedbl) + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; break; case 15: - svga->render = svga_render_15bpp_highres; + if (svga->horizontal_linedbl) + svga->render = svga_render_15bpp_lowres; + else + svga->render = svga_render_15bpp_highres; break; case 16: - svga->render = svga_render_16bpp_highres; + if (svga->horizontal_linedbl) + svga->render = svga_render_16bpp_lowres; + else + svga->render = svga_render_16bpp_highres; break; - case 24: - svga->render = svga_render_24bpp_highres; + case 24: + if (svga->horizontal_linedbl) + svga->render = svga_render_24bpp_lowres; + else + svga->render = svga_render_24bpp_highres; break; case 32: - svga->render = svga_render_32bpp_highres; + if (svga->horizontal_linedbl) + svga->render = svga_render_32bpp_lowres; + else + svga->render = svga_render_32bpp_highres; break; } } @@ -772,6 +808,9 @@ static void s3_virge_vblank_start(svga_t *svga) { virge_t *virge = (virge_t *)svga->p; + if (virge->vblank_irq >= 0) { + virge->vblank_irq = 1; + } virge->subsys_stat |= INT_VSY; s3_virge_update_irqs(virge); } @@ -987,7 +1026,8 @@ static void fifo_thread(void *param) { virge_t *virge = (virge_t *)param; - while (1) + virge->fifo_thread_state = 1; + while (virge->fifo_thread_state > 0) { thread_set_event(virge->fifo_not_full_event); thread_wait_event(virge->wake_fifo_thread, -1); @@ -1333,6 +1373,7 @@ static void fifo_thread(void *param) virge->subsys_stat |= INT_FIFO_EMP | INT_3DF_EMP; s3_virge_update_irqs(virge); } + virge->fifo_thread_state = 0; } static void s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type) @@ -3368,7 +3409,8 @@ static void render_thread(void *param) { virge_t *virge = (virge_t *)param; - while (1) + virge->render_thread_state = 1; + while (virge->render_thread_state > 0) { thread_wait_event(virge->wake_render_thread, -1); thread_reset_event(virge->wake_render_thread); @@ -3385,6 +3427,7 @@ static void render_thread(void *param) virge->subsys_stat |= INT_S3D_DONE; s3_virge_update_irqs(virge); } + virge->render_thread_state = 0; } static void queue_triangle(virge_t *virge) @@ -3412,6 +3455,8 @@ static void s3_virge_hwcursor_draw(svga_t *svga, int displine) int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; uint32_t fg, bg; + offset <<= svga->horizontal_linedbl; + // pclog("HWcursor %i %i %08x %08x\n", svga->hwcursor_latch.x, svga->hwcursor_latch.y, virge->hwcursor_col[0],virge->hwcursor_col[1]); switch (svga->bpp) { @@ -4057,12 +4102,26 @@ static void s3_virge_close(void *p) #endif #endif - thread_kill(virge->render_thread); + if (virge->render_thread_state) { + virge->render_thread_state = -1; + thread_set_event(virge->wake_render_thread); + while (virge->render_thread_state == -1) { + thread_sleep(1); + } + thread_kill(virge->render_thread); + } thread_destroy_event(virge->not_full_event); thread_destroy_event(virge->wake_main_thread); thread_destroy_event(virge->wake_render_thread); - thread_kill(virge->fifo_thread); + if (virge->fifo_thread_state) { + virge->fifo_thread_state = -1; + thread_set_event(virge->wake_fifo_thread); + while (virge->fifo_thread_state == -1) { + thread_sleep(1); + } + thread_kill(virge->fifo_thread); + } thread_destroy_event(virge->wake_fifo_thread); thread_destroy_event(virge->fifo_not_full_event); diff --git a/pcem/vid_svga.cpp b/pcem/vid_svga.cpp index 8cef1b55..5de0adc3 100644 --- a/pcem/vid_svga.cpp +++ b/pcem/vid_svga.cpp @@ -23,7 +23,10 @@ static svga_t *svga_pri; int svga_get_vtotal(void) { - return svga_pri->vtotal; + int v = svga_pri->vtotal; + if (svga_pri->crtc[0x17] & 4) + v *= 2; + return v; } void *svga_get_object(void) @@ -316,24 +319,34 @@ void svga_recalctimings(svga_t *svga) svga->split = svga->crtc[0x18]; svga->vblankstart = svga->crtc[0x15]; - if (svga->crtc[7] & 1) svga->vtotal |= 0x100; - if (svga->crtc[7] & 32) svga->vtotal |= 0x200; + if (svga->crtc[7] & 1) + svga->vtotal |= 0x100; + if (svga->crtc[7] & 0x20) + svga->vtotal |= 0x200; svga->vtotal += 2; - if (svga->crtc[7] & 2) svga->dispend |= 0x100; - if (svga->crtc[7] & 64) svga->dispend |= 0x200; + if (svga->crtc[7] & 2) + svga->dispend |= 0x100; + if (svga->crtc[7] & 0x40) + svga->dispend |= 0x200; svga->dispend++; - if (svga->crtc[7] & 4) svga->vsyncstart |= 0x100; - if (svga->crtc[7] & 128) svga->vsyncstart |= 0x200; + if (svga->crtc[7] & 4) + svga->vsyncstart |= 0x100; + if (svga->crtc[7] & 0x80) + svga->vsyncstart |= 0x200; svga->vsyncstart++; - if (svga->crtc[7] & 0x10) svga->split|=0x100; - if (svga->crtc[9] & 0x40) svga->split|=0x200; + if (svga->crtc[7] & 0x10) + svga->split|=0x100; + if (svga->crtc[9] & 0x40) + svga->split|=0x200; svga->split++; - if (svga->crtc[7] & 0x08) svga->vblankstart |= 0x100; - if (svga->crtc[9] & 0x20) svga->vblankstart |= 0x200; + if (svga->crtc[7] & 0x08) + svga->vblankstart |= 0x100; + if (svga->crtc[9] & 0x20) + svga->vblankstart |= 0x200; svga->vblankstart++; svga->hdisp = svga->crtc[1]; @@ -347,6 +360,8 @@ void svga_recalctimings(svga_t *svga) svga->clock = (svga->vidclock) ? VGACONST2 : VGACONST1; svga->lowres = svga->attrregs[0x10] & 0x40; + + svga->horizontal_linedbl = 0; svga->interlace = 0; @@ -354,6 +369,7 @@ void svga_recalctimings(svga_t *svga) svga->hdisp_time = svga->hdisp; svga->render = svga_render_blank; + if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) /*Text mode*/ { if (svga->seqregs[1] & 8) /*40 column*/ @@ -600,7 +616,7 @@ int svga_poll(void *p) svga->hsync_divisor = !svga->hsync_divisor; if (svga->hsync_divisor && (svga->crtc[0x17] & 4)) - return 1; + return eod; svga->vc++; svga->vc &= 2047; @@ -702,8 +718,12 @@ int svga_poll(void *p) svga->render == svga_render_15bpp_lowres || svga->render == svga_render_16bpp_lowres || svga->render == svga_render_24bpp_lowres || - svga->render == svga_render_32bpp_lowres) + svga->render == svga_render_32bpp_lowres) { + if (svga->horizontal_linedbl) + svga->video_res_x *= 2; + else svga->video_res_x /= 2; + } switch (svga->gdcreg[5] & 0x60) { @@ -1359,20 +1379,17 @@ void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga) { xsize=wx; ysize=wy+1; - if (xsize<64) xsize=0; + if (xsize<128) xsize=0; if (ysize<32) ysize=0; - if (svga->vertical_linedbl) - updatewindowsize(xsize,ysize*2); - else - updatewindowsize(xsize,ysize); + updatewindowsize(xsize * (svga->horizontal_linedbl ? 2 : 1), ysize * (svga->vertical_linedbl ? 2 : 1)); } if (vid_resize) { xsize = wx; ysize = wy + 1; } - video_blit_memtoscreen(32, 0, y1, y2, xsize, ysize); + video_blit_memtoscreen(32, 0, y1, y2, xsize << svga->horizontal_linedbl, ysize); // pclog("svga_doblit end\n"); } diff --git a/pcem/vid_svga.h b/pcem/vid_svga.h index e67ab42d..a4bbd73c 100644 --- a/pcem/vid_svga.h +++ b/pcem/vid_svga.h @@ -140,6 +140,7 @@ typedef struct svga_t uint8_t ksc5601_sbyte_mask; int vertical_linedbl; + int horizontal_linedbl; /*Used to implement CRTC[0x17] bit 2 hsync divisor*/ int hsync_divisor; diff --git a/pcem/vid_svga_render.cpp b/pcem/vid_svga_render.cpp index 6320542e..a50abb9a 100644 --- a/pcem/vid_svga_render.cpp +++ b/pcem/vid_svga_render.cpp @@ -375,7 +375,7 @@ void svga_render_4bpp_lowres(svga_t *svga) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; - for (x = 0; x <= svga->hdisp; x += 16) + for (x = 0; x <= svga->hdisp << svga->horizontal_linedbl; x += 16) { uint8_t edat[4]; uint8_t dat; @@ -457,7 +457,7 @@ void svga_render_8bpp_lowres(svga_t *svga) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; - for (x = 0; x <= svga->hdisp; x += 8) + for (x = 0; x <= svga->hdisp << svga->horizontal_linedbl; x += 8) { uint32_t dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); @@ -519,17 +519,12 @@ void svga_render_15bpp_lowres(svga_t *svga) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; - for (x = 0; x <= svga->hdisp; x += 4) + for (x = 0; x <= svga->hdisp << svga->horizontal_linedbl; x += 4) { - uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + x) & svga->vram_display_mask]); - p[x] = video_15to32[dat & 0xffff]; - p[x + 1] = video_15to32[dat >> 16]; - - dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); - - p[x] = video_15to32[dat & 0xffff]; - p[x + 1] = video_15to32[dat >> 16]; + p[x] = p[x + 1] = video_15to32[dat & 0xffff]; + p[x + 2] = p[x + 3] = video_15to32[dat >> 16]; } svga->ma += x << 1; svga->ma &= svga->vram_display_mask; @@ -583,17 +578,12 @@ void svga_render_16bpp_lowres(svga_t *svga) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; - for (x = 0; x <= svga->hdisp; x += 4) + for (x = 0; x <= svga->hdisp << svga->horizontal_linedbl; x += 4) { - uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); - - p[x] = video_16to32[dat & 0xffff]; - p[x + 1] = video_16to32[dat >> 16]; - - dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + x) & svga->vram_display_mask]); - p[x] = video_16to32[dat & 0xffff]; - p[x + 1] = video_16to32[dat >> 16]; + p[x] = p[x + 1] = video_16to32[dat & 0xffff]; + p[x + 2] = p[x + 3] = video_16to32[dat >> 16]; } svga->ma += x << 1; svga->ma &= svga->vram_display_mask; @@ -649,16 +639,16 @@ void svga_render_24bpp_lowres(svga_t *svga) offset = (8 - (svga->scrollcache & 6)) + 24; if (svga->swaprb) { - for (x = 0; x <= svga->hdisp; x++) { + for (x = 0; x <= svga->hdisp << svga->horizontal_linedbl; x++) { fg = svga->vram[svga->ma + 2] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 0] << 16); svga->ma += 3; svga->ma &= svga->vram_display_mask; ((uint32_t *)buffer32->line[svga->displine])[(x << 1) + offset] = ((uint32_t *)buffer32->line[svga->displine])[(x << 1) + 1 + offset] = fg; } } else { - for (x = 0; x <= svga->hdisp; x++) + for (x = 0; x <= svga->hdisp << svga->horizontal_linedbl; x++) { - fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); + fg = svga->vram[svga->ma] | (svga->vram[(svga->ma + 1) & svga->vram_display_mask] << 8) | (svga->vram[(svga->ma + 2) & svga->vram_display_mask] << 16); svga->ma += 3; svga->ma &= svga->vram_display_mask; ((uint32_t *)buffer32->line[svga->displine])[(x << 1) + offset] = ((uint32_t *)buffer32->line[svga->displine])[(x << 1) + 1 + offset] = fg; @@ -683,27 +673,36 @@ void svga_render_24bpp_highres(svga_t *svga) uint32_t dat; for (x = 0; x <= svga->hdisp; x++) { - dat = svga->vram[svga->ma + 2] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 0] << 16); + dat = svga->vram[(svga->ma + 2) &svga->vram_display_mask] | (svga->vram[(svga->ma + 1) & svga->vram_display_mask] << 8) | (svga->vram[svga->ma + 0] << 16); p[x] = dat; svga->ma += 3; svga->ma &= svga->vram_display_mask; } } else { - for (x = 0; x <= svga->hdisp; x += 4) - { - uint32_t dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); - p[x] = dat & 0xffffff; + if ((svga->ma & svga->vram_display_mask) + svga->hdisp * 3 + 3 > svga->vram_display_mask) { + for (x = 0; x <= svga->hdisp; x++) { + uint32_t dat = (svga->vram[(svga->ma + 0) & svga->vram_display_mask] << 0) | + (svga->vram[(svga->ma + 1) & svga->vram_display_mask] << 8) | + (svga->vram[(svga->ma + 2) & svga->vram_display_mask] << 16); + p[x] = dat; + svga->ma += 3; + } + } else { + for (x = 0; x <= svga->hdisp; x += 4) { + uint32_t dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + p[x] = dat & 0xffffff; - dat = *(uint32_t *)(&svga->vram[(svga->ma + 3) & svga->vram_display_mask]); - p[x + 1] = dat & 0xffffff; + dat = *(uint32_t *)(&svga->vram[(svga->ma + 3) & svga->vram_display_mask]); + p[x + 1] = dat & 0xffffff; - dat = *(uint32_t *)(&svga->vram[(svga->ma + 6) & svga->vram_display_mask]); - p[x + 2] = dat & 0xffffff; + dat = *(uint32_t *)(&svga->vram[(svga->ma + 6) & svga->vram_display_mask]); + p[x + 2] = dat & 0xffffff; - dat = *(uint32_t *)(&svga->vram[(svga->ma + 9) & svga->vram_display_mask]); - p[x + 3] = dat & 0xffffff; + dat = *(uint32_t *)(&svga->vram[(svga->ma + 9) & svga->vram_display_mask]); + p[x + 3] = dat & 0xffffff; - svga->ma += 12; + svga->ma += 12; + } } } svga->ma &= svga->vram_display_mask; @@ -723,7 +722,7 @@ void svga_render_32bpp_lowres(svga_t *svga) offset = (8 - (svga->scrollcache & 6)) + 24; - for (x = 0; x <= svga->hdisp; x++) + for (x = 0; x <= svga->hdisp << svga->horizontal_linedbl; x++) { fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); svga->ma += 4; -- 2.47.3