From 7b6e5e5ad93e21e1c803eb537704f89105884b4c Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 4 Sep 2024 15:22:24 +0200 Subject: [PATCH] Implements the second CMDFIFO2 queue for Voodoo 3, fixing BeOS's Voodoo 3/Banshee drivers, fixes #4794. --- src/include/86box/vid_voodoo_common.h | 16 +- src/video/vid_voodoo.c | 4 +- src/video/vid_voodoo_banshee.c | 128 +++++++++++ src/video/vid_voodoo_fifo.c | 298 ++++++++++++++++++++++++++ 4 files changed, 443 insertions(+), 3 deletions(-) diff --git a/src/include/86box/vid_voodoo_common.h b/src/include/86box/vid_voodoo_common.h index 96865ac6d..5ab63ec3a 100644 --- a/src/include/86box/vid_voodoo_common.h +++ b/src/include/86box/vid_voodoo_common.h @@ -408,6 +408,7 @@ typedef struct voodoo_t { atomic_int cmd_read; atomic_int cmd_written; atomic_int cmd_written_fifo; + atomic_int cmd_written_fifo_2; voodoo_params_t params_buffer[PARAM_SIZE]; atomic_int params_read_idx[4]; @@ -426,7 +427,20 @@ typedef struct voodoo_t { uint32_t cmdfifo_amax; int cmdfifo_holecount; - atomic_uint cmd_status; + uint32_t cmdfifo_base_2; + uint32_t cmdfifo_end_2; + uint32_t cmdfifo_size_2; + int cmdfifo_rp_2; + int cmdfifo_ret_addr_2; + int cmdfifo_in_sub_2; + atomic_int cmdfifo_depth_rd_2; + atomic_int cmdfifo_depth_wr_2; + atomic_int cmdfifo_enabled_2; + uint32_t cmdfifo_amin_2; + uint32_t cmdfifo_amax_2; + int cmdfifo_holecount_2; + + atomic_uint cmd_status, cmd_status_2; uint32_t sSetupMode; vert_t verts[4]; diff --git a/src/video/vid_voodoo.c b/src/video/vid_voodoo.c index 93bdd1a4c..efa2d20c8 100644 --- a/src/video/vid_voodoo.c +++ b/src/video/vid_voodoo.c @@ -222,12 +222,12 @@ voodoo_readl(uint32_t addr, void *priv) { int fifo_entries = FIFO_ENTRIES; int swap_count = voodoo->swap_count; - int written = voodoo->cmd_written + voodoo->cmd_written_fifo; + int written = voodoo->cmd_written + voodoo->cmd_written_fifo + voodoo->cmd_written_fifo_2; int busy = (written - voodoo->cmd_read) || (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr); if (SLI_ENABLED && voodoo->type != VOODOO_2) { voodoo_t *voodoo_other = (voodoo == voodoo->set->voodoos[0]) ? voodoo->set->voodoos[1] : voodoo->set->voodoos[0]; - int other_written = voodoo_other->cmd_written + voodoo_other->cmd_written_fifo; + int other_written = voodoo_other->cmd_written + voodoo_other->cmd_written_fifo + voodoo->cmd_written_fifo_2; if (voodoo_other->swap_count > swap_count) swap_count = voodoo_other->swap_count; diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index 8e2b98980..c1fb65b00 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -204,6 +204,17 @@ enum { cmdFifoDepth0 = 0x44, cmdHoleCnt0 = 0x48, + cmdBaseAddr1 = 0x50, + cmdBaseSize1 = 0x50 + 0x4, + cmdBump1 = 0x50 + 0x8, + cmdRdPtrL1 = 0x50 + 0xc, + cmdRdPtrH1 = 0x50 + 0x10, + cmdAMin1 = 0x50 + 0x14, + cmdAMax1 = 0x50 + 0x1c, + cmdStatus1 = 0x50 + 0x20, + cmdFifoDepth1 = 0x50 + 0x24, + cmdHoleCnt1 = 0x50 + 0x28, + Agp_agpReqSize = 0x00, Agp_agpHostAddressLow = 0x04, Agp_agpHostAddressHigh = 0x08, @@ -1341,6 +1352,29 @@ banshee_cmd_read(banshee_t *banshee, uint32_t addr) ret = voodoo->cmdfifo_size; break; + case cmdBaseAddr1: + ret = voodoo->cmdfifo_base_2 >> 12; + // banshee_log("Read cmdfifo_base %08x\n", ret); + break; + + case cmdRdPtrL1: + ret = voodoo->cmdfifo_rp_2; + // banshee_log("Read cmdfifo_rp %08x\n", ret); + break; + + case cmdFifoDepth1: + ret = voodoo->cmdfifo_depth_wr_2 - voodoo->cmdfifo_depth_rd_2; + // banshee_log("Read cmdfifo_depth %08x\n", ret); + break; + + case cmdStatus1: + ret = voodoo->cmd_status_2; + break; + + case cmdBaseSize1: + ret = voodoo->cmdfifo_size_2; + break; + case 0x108: break; @@ -1625,6 +1659,45 @@ banshee_cmd_write(banshee_t *banshee, uint32_t addr, uint32_t val) voodoo->cmdfifo_depth_wr = val & 0xffff; break; + case cmdBaseAddr1: + voodoo->cmdfifo_base_2 = (val & 0xfff) << 12; + voodoo->cmdfifo_end_2 = voodoo->cmdfifo_base_2 + (((voodoo->cmdfifo_size_2 & 0xff) + 1) << 12); +#if 0 + banshee_log("cmdfifo_base=%08x cmdfifo_end=%08x %08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end, val); +#endif + break; + + case cmdBaseSize1: + voodoo->cmdfifo_size_2 = val; + voodoo->cmdfifo_end_2 = voodoo->cmdfifo_base_2 + (((voodoo->cmdfifo_size_2 & 0xff) + 1) << 12); + voodoo->cmdfifo_enabled_2 = val & 0x100; + if (!voodoo->cmdfifo_enabled_2) + voodoo->cmdfifo_in_sub_2 = 0; /*Not sure exactly when this should be reset*/ +#if 0 + banshee_log("cmdfifo_base=%08x cmdfifo_end=%08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end); +#endif + break; + +#if 0 + voodoo->cmdfifo_end = ((val >> 16) & 0x3ff) << 12; + banshee_log("CMDFIFO base=%08x end=%08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end); + break; +#endif + + case cmdRdPtrL1: + voodoo->cmdfifo_rp_2 = val; + break; + case cmdAMin1: + voodoo->cmdfifo_amin_2 = val; + break; + case cmdAMax1: + voodoo->cmdfifo_amax_2 = val; + break; + case cmdFifoDepth1: + voodoo->cmdfifo_depth_rd_2 = 0; + voodoo->cmdfifo_depth_wr_2 = val & 0xffff; + break; + default: banshee_log("Unknown banshee_cmd_write: addr=%08x val=%08x reg=0x%03x\n", addr, val, addr & 0x1fc); break; @@ -2064,6 +2137,60 @@ banshee_write_linear_l(uint32_t addr, uint32_t val, void *priv) voodoo->cmdfifo_holecount = ((voodoo->cmdfifo_amax - voodoo->cmdfifo_amin) >> 2) - 1; #if 0 banshee_log("CMDFIFO out of order: amin=%08x amax=%08x holecount=%i\n", voodoo->cmdfifo_amin, voodoo->cmdfifo_amax, voodoo->cmdfifo_holecount); +#endif + } + } + + if (voodoo->cmdfifo_enabled_2 && addr >= voodoo->cmdfifo_base_2 && addr < voodoo->cmdfifo_end_2) { +#if 0 + banshee_log("CMDFIFO write %08x %08x old amin=%08x amax=%08x hlcnt=%i depth_wr=%i rp=%08x\n", addr, val, voodoo->cmdfifo_amin, voodoo->cmdfifo_amax, voodoo->cmdfifo_holecount, voodoo->cmdfifo_depth_wr, voodoo->cmdfifo_rp); +#endif + if (addr == voodoo->cmdfifo_base_2 && !voodoo->cmdfifo_holecount_2) { +#if 0 + if (voodoo->cmdfifo_holecount) + fatal("CMDFIFO reset pointers while outstanding holes\n"); +#endif + /*Reset pointers*/ + voodoo->cmdfifo_amin_2 = voodoo->cmdfifo_base_2; + voodoo->cmdfifo_amax_2 = voodoo->cmdfifo_base_2; + voodoo->cmdfifo_depth_wr_2++; + voodoo_wake_fifo_thread(voodoo); + } else if (voodoo->cmdfifo_holecount_2) { +#if 0 + if ((addr <= voodoo->cmdfifo_amin && voodoo->cmdfifo_amin != -4) || addr >= voodoo->cmdfifo_amax) + fatal("CMDFIFO holecount write outside of amin/amax - amin=%08x amax=%08x holecount=%i\n", voodoo->cmdfifo_amin, voodoo->cmdfifo_amax, voodoo->cmdfifo_holecount); + banshee_log("holecount %i\n", voodoo->cmdfifo_holecount); +#endif + voodoo->cmdfifo_holecount_2--; + if (!voodoo->cmdfifo_holecount_2) { + /*Filled in holes, resume normal operation*/ + voodoo->cmdfifo_depth_wr_2 += ((voodoo->cmdfifo_amax_2 - voodoo->cmdfifo_amin_2) >> 2); + voodoo->cmdfifo_amin_2 = voodoo->cmdfifo_amax_2; + voodoo_wake_fifo_thread(voodoo); +#if 0 + banshee_log("hole filled! amin=%08x amax=%08x added %i words\n", voodoo->cmdfifo_amin, voodoo->cmdfifo_amax, words_to_add); +#endif + } + } else if (addr == voodoo->cmdfifo_amax_2 + 4) { + /*In-order write*/ + voodoo->cmdfifo_amin_2 = addr; + voodoo->cmdfifo_amax_2 = addr; + voodoo->cmdfifo_depth_wr_2++; + voodoo_wake_fifo_thread(voodoo); + } else { + /*Out-of-order write*/ + if (addr < voodoo->cmdfifo_amin_2) { + /*Reset back to start. Note that write is still out of order!*/ + voodoo->cmdfifo_amin_2 = voodoo->cmdfifo_base_2 - 4; + } +#if 0 + else if (addr < voodoo->cmdfifo_amax) + fatal("Out-of-order write really out of order\n"); +#endif + voodoo->cmdfifo_amax_2 = addr; + voodoo->cmdfifo_holecount_2 = ((voodoo->cmdfifo_amax_2 - voodoo->cmdfifo_amin_2) >> 2) - 1; +#if 0 + banshee_log("CMDFIFO out of order: amin=%08x amax=%08x holecount=%i\n", voodoo->cmdfifo_amin, voodoo->cmdfifo_amax, voodoo->cmdfifo_holecount); #endif } } @@ -3313,6 +3440,7 @@ banshee_init_common(const device_t *info, char *fn, int has_sgram, int type, int banshee->voodoo->tex_mem_w[1] = (uint16_t *) banshee->svga.vram; banshee->voodoo->texture_mask = banshee->svga.vram_mask; banshee->voodoo->cmd_status = (1 << 28); + banshee->voodoo->cmd_status_2 = (1 << 28); voodoo_generate_filter_v1(banshee->voodoo); banshee->vidSerialParallelPort = VIDSERIAL_DDC_DCK_W | VIDSERIAL_DDC_DDA_W; diff --git a/src/video/vid_voodoo_fifo.c b/src/video/vid_voodoo_fifo.c index f8495edec..88a6905c2 100644 --- a/src/video/vid_voodoo_fifo.c +++ b/src/video/vid_voodoo_fifo.c @@ -188,6 +188,40 @@ cmdfifo_get_f(voodoo_t *voodoo) return tempif.f; } +static uint32_t +cmdfifo_get_2(voodoo_t *voodoo) +{ + uint32_t val; + + if (!voodoo->cmdfifo_in_sub_2) { + while (voodoo->fifo_thread_run && (voodoo->cmdfifo_depth_rd_2 == voodoo->cmdfifo_depth_wr_2)) { + thread_wait_event(voodoo->wake_fifo_thread, -1); + thread_reset_event(voodoo->wake_fifo_thread); + } + } + + val = *(uint32_t *) &voodoo->fb_mem[voodoo->cmdfifo_rp_2 & voodoo->fb_mask]; + + if (!voodoo->cmdfifo_in_sub_2) + voodoo->cmdfifo_depth_rd_2++; + voodoo->cmdfifo_rp_2 += 4; + + // voodoo_fifo_log(" CMDFIFO get %08x\n", val); + return val; +} + +static inline float +cmdfifo_get_f_2(voodoo_t *voodoo) +{ + union { + uint32_t i; + float f; + } tempif; + + tempif.i = cmdfifo_get(voodoo); + return tempif.f; +} + enum { CMDFIFO3_PC_MASK_RGB = (1 << 10), CMDFIFO3_PC_MASK_ALPHA = (1 << 11), @@ -283,6 +317,7 @@ voodoo_fifo_thread(void *param) } voodoo->cmd_status |= (1 << 24); + voodoo->cmd_status_2 |= (1 << 24); while (voodoo->cmdfifo_enabled && (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr || voodoo->cmdfifo_in_sub)) { uint64_t start_time = plat_timer_read(); @@ -545,6 +580,269 @@ voodoo_fifo_thread(void *param) end_time = plat_timer_read(); voodoo->time += end_time - start_time; } + + while (voodoo->cmdfifo_enabled_2 && (voodoo->cmdfifo_depth_rd_2 != voodoo->cmdfifo_depth_wr_2 || voodoo->cmdfifo_in_sub_2)) { + uint64_t start_time = plat_timer_read(); + uint64_t end_time; + uint32_t header = cmdfifo_get_2(voodoo); + uint32_t addr; + uint32_t mask; + int smode; + int num; + int num_verticies; + int v_num; + +#if 0 + voodoo_fifo_log(" CMDFIFO header %08x at %08x\n", header, voodoo->cmdfifo_rp); +#endif + + voodoo->cmd_status_2 &= ~7; + voodoo->cmd_status_2 |= (header & 7); + voodoo->cmd_status_2 |= (1 << 11); + switch (header & 7) { + case 0: +#if 0 + voodoo_fifo_log("CMDFIFO0\n"); +#endif + voodoo->cmd_status_2 = (voodoo->cmd_status_2 & 0xffff8fff) | (((header >> 3) & 7) << 12); + switch ((header >> 3) & 7) { + case 0: /*NOP*/ + break; + + case 1: /*JSR*/ +#if 0 + voodoo_fifo_log("JSR %08x\n", (header >> 4) & 0xfffffc); +#endif + voodoo->cmdfifo_ret_addr_2 = voodoo->cmdfifo_rp_2; + voodoo->cmdfifo_rp_2 = (header >> 4) & 0xfffffc; + voodoo->cmdfifo_in_sub_2 = 1; + break; + + case 2: /*RET*/ + voodoo->cmdfifo_rp_2 = voodoo->cmdfifo_ret_addr_2; + voodoo->cmdfifo_in_sub_2 = 0; + break; + + case 3: /*JMP local frame buffer*/ + voodoo->cmdfifo_rp_2 = (header >> 4) & 0xfffffc; +#if 0 + voodoo_fifo_log("JMP to %08x %04x\n", voodoo->cmdfifo_rp, header); +#endif + break; + + default: + fatal("Bad CMDFIFO0 %08x\n", header); + } + voodoo->cmd_status_2 = (voodoo->cmd_status_2 & ~(1 << 27)) | (voodoo->cmdfifo_in_sub_2 << 27); + break; + + case 1: + num = header >> 16; + addr = (header & 0x7ff8) >> 1; +#if 0 + voodoo_fifo_log("CMDFIFO1 addr=%08x\n",addr); +#endif + while (num--) { + uint32_t val = cmdfifo_get_2(voodoo); + if ((addr & (1 << 13)) && voodoo->type >= VOODOO_BANSHEE) { +#if 0 + if (voodoo->type != VOODOO_BANSHEE) + fatal("CMDFIFO1: Not Banshee\n"); +#endif + +#if 0 + voodoo_fifo_log("CMDFIFO1: write %08x %08x\n", addr, val); +#endif + voodoo_2d_reg_writel(voodoo, addr, val); + } else { + if ((addr & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD || (addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD) + voodoo->cmd_written_fifo_2++; + + if (voodoo->type >= VOODOO_BANSHEE && (addr & 0x3ff) == SST_swapbufferCMD) + voodoo->cmd_written_fifo_2++; + voodoo_reg_writel(addr, val, voodoo); + } + + if (header & (1 << 15)) + addr += 4; + } + break; + + case 2: + if (voodoo->type < VOODOO_2) + fatal("CMDFIFO2: Not Voodoo 2\n"); + mask = (header >> 3); + addr = 8; + while (mask) { + if (mask & 1) { + uint32_t val = cmdfifo_get_2(voodoo); + + voodoo_2d_reg_writel(voodoo, addr, val); + } + + addr += 4; + mask >>= 1; + } + break; + + case 3: + num = (header >> 29) & 7; + mask = header; //(header >> 10) & 0xff; + smode = (header >> 22) & 0xf; + voodoo_reg_writel(SST_sSetupMode, ((header >> 10) & 0xff) | (smode << 16), voodoo); + num_verticies = (header >> 6) & 0xf; + v_num = 0; + if (((header >> 3) & 7) == 2) + v_num = 1; +#if 0 + voodoo_fifo_log("CMDFIFO3: num=%i verts=%i mask=%02x\n", num, num_verticies, (header >> 10) & 0xff); + voodoo_fifo_log("CMDFIFO3 %02x %i\n", (header >> 10), (header >> 3) & 7); +#endif + + while (num_verticies--) { + voodoo->verts[3].sVx = cmdfifo_get_f_2(voodoo); + voodoo->verts[3].sVy = cmdfifo_get_f_2(voodoo); + if (mask & CMDFIFO3_PC_MASK_RGB) { + if (header & CMDFIFO3_PC) { + uint32_t val = cmdfifo_get_2(voodoo); + voodoo->verts[3].sBlue = (float) (val & 0xff); + voodoo->verts[3].sGreen = (float) ((val >> 8) & 0xff); + voodoo->verts[3].sRed = (float) ((val >> 16) & 0xff); + voodoo->verts[3].sAlpha = (float) ((val >> 24) & 0xff); + } else { + voodoo->verts[3].sRed = cmdfifo_get_f_2(voodoo); + voodoo->verts[3].sGreen = cmdfifo_get_f_2(voodoo); + voodoo->verts[3].sBlue = cmdfifo_get_f_2(voodoo); + } + } + if ((mask & CMDFIFO3_PC_MASK_ALPHA) && !(header & CMDFIFO3_PC)) + voodoo->verts[3].sAlpha = cmdfifo_get_f_2(voodoo); + if (mask & CMDFIFO3_PC_MASK_Z) + voodoo->verts[3].sVz = cmdfifo_get_f_2(voodoo); + if (mask & CMDFIFO3_PC_MASK_Wb) + voodoo->verts[3].sWb = cmdfifo_get_f_2(voodoo); + if (mask & CMDFIFO3_PC_MASK_W0) + voodoo->verts[3].sW0 = cmdfifo_get_f_2(voodoo); + if (mask & CMDFIFO3_PC_MASK_S0_T0) { + voodoo->verts[3].sS0 = cmdfifo_get_f_2(voodoo); + voodoo->verts[3].sT0 = cmdfifo_get_f_2(voodoo); + } + if (mask & CMDFIFO3_PC_MASK_W1) + voodoo->verts[3].sW1 = cmdfifo_get_f_2(voodoo); + if (mask & CMDFIFO3_PC_MASK_S1_T1) { + voodoo->verts[3].sS1 = cmdfifo_get_f_2(voodoo); + voodoo->verts[3].sT1 = cmdfifo_get_f_2(voodoo); + } + if (v_num) + voodoo_reg_writel(SST_sDrawTriCMD, 0, voodoo); + else + voodoo_reg_writel(SST_sBeginTriCMD, 0, voodoo); + v_num++; + if (v_num == 3 && ((header >> 3) & 7) == 0) + v_num = 0; + } + while (num--) + cmdfifo_get_2(voodoo); + break; + + case 4: + num = (header >> 29) & 7; + mask = (header >> 15) & 0x3fff; + addr = (header & 0x7ff8) >> 1; +#if 0 + voodoo_fifo_log("CMDFIFO4 addr=%08x\n",addr); +#endif + while (mask) { + if (mask & 1) { + uint32_t val = cmdfifo_get_2(voodoo); + + if ((addr & (1 << 13)) && voodoo->type >= VOODOO_BANSHEE) { + if (voodoo->type < VOODOO_BANSHEE) + fatal("CMDFIFO1: Not Banshee\n"); +#if 0 + voodoo_fifo_log("CMDFIFO1: write %08x %08x\n", addr, val); +#endif + + voodoo_2d_reg_writel(voodoo, addr, val); + } else { + if ((addr & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD || (addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD) + voodoo->cmd_written_fifo_2++; + + if (voodoo->type >= VOODOO_BANSHEE && (addr & 0x3ff) == SST_swapbufferCMD) + voodoo->cmd_written_fifo_2++; + voodoo_reg_writel(addr, val, voodoo); + } + } + + addr += 4; + mask >>= 1; + } + while (num--) + cmdfifo_get_2(voodoo); + break; + + case 5: +#if 0 + if (header & 0x3fc00000) + fatal("CMDFIFO packet 5 has byte disables set %08x\n", header); +#endif + num = (header >> 3) & 0x7ffff; + addr = cmdfifo_get_2(voodoo) & 0xffffff; + if (!num) + num = 1; +#if 0 + voodoo_fifo_log("CMDFIFO5 addr=%08x num=%i\n", addr, num); +#endif + switch (header >> 30) { + case 0: /*Linear framebuffer (Banshee)*/ + case 1: /*Planar YUV*/ + if (voodoo->texture_present[0][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) { +#if 0 + voodoo_fifo_log("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT); +#endif + flush_texture_cache(voodoo, addr & voodoo->texture_mask, 0); + } + if (voodoo->texture_present[1][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) { +#if 0 + voodoo_fifo_log("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT); +#endif + flush_texture_cache(voodoo, addr & voodoo->texture_mask, 1); + } + while (num--) { + uint32_t val = cmdfifo_get_2(voodoo); + if (addr <= voodoo->fb_mask) + *(uint32_t *) &voodoo->fb_mem[addr] = val; + addr += 4; + } + break; + case 2: /*Framebuffer*/ + while (num--) { + uint32_t val = cmdfifo_get_2(voodoo); + voodoo_fb_writel(addr, val, voodoo); + addr += 4; + } + break; + case 3: /*Texture*/ + while (num--) { + uint32_t val = cmdfifo_get_2(voodoo); + voodoo_tex_writel(addr, val, voodoo); + addr += 4; + } + break; + + default: + fatal("CMDFIFO packet 5 bad space %08x %08x\n", header, voodoo->cmdfifo_rp); + } + break; + + default: + fatal("Bad CMDFIFO packet %08x %08x\n", header, voodoo->cmdfifo_rp); + } + + end_time = plat_timer_read(); + voodoo->time += end_time - start_time; + } + voodoo->voodoo_busy = 0; } }