From e59bb4dc2ec24688d57b3658eda1c19c0f1514ea Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 21 Dec 2025 22:00:24 +0600 Subject: [PATCH] Voodoo stippling support for 3D --- src/include/86box/vid_voodoo_codegen_x86-64.h | 82 +++++++++++++++++-- src/include/86box/vid_voodoo_regs.h | 3 + src/video/vid_voodoo_fb.c | 26 ++++++ src/video/vid_voodoo_render.c | 17 ++++ 4 files changed, 120 insertions(+), 8 deletions(-) diff --git a/src/include/86box/vid_voodoo_codegen_x86-64.h b/src/include/86box/vid_voodoo_codegen_x86-64.h index 67a5cae2c..8b1413ad4 100644 --- a/src/include/86box/vid_voodoo_codegen_x86-64.h +++ b/src/include/86box/vid_voodoo_codegen_x86-64.h @@ -653,14 +653,15 @@ codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *pa static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int depthop) { - int block_pos = 0; - int z_skip_pos = 0; - int a_skip_pos = 0; - int amask_skip_pos = 0; - int chroma_skip_pos = 0; - int depth_jump_pos = 0; - int depth_jump_pos2 = 0; - int loop_jump_pos = 0; + int block_pos = 0; + int z_skip_pos = 0; + int a_skip_pos = 0; + int amask_skip_pos = 0; + int stipple_skip_pos = 0; + int chroma_skip_pos = 0; + int depth_jump_pos = 0; + int depth_jump_pos2 = 0; + int loop_jump_pos = 0; #if 0 xmm_01_w = (__m128i)0x0001000100010001ull; xmm_ff_w = (__m128i)0x00ff00ff00ff00ffull; @@ -766,6 +767,69 @@ voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, addquad((uint64_t) (uintptr_t) &i_00_ff_w); loop_jump_pos = block_pos; + if (params->fbzMode & FBZ_STIPPLE) { + /* Stipple enabled. */ + if (params->fbzMode & FBZ_STIPPLE_PATT) { + /* x64's BT instruction is too slow. So use TEST instead. */ + addbyte(0x4c); /* MOV RBX, R14(real_y)*/ + addbyte(0x89); + addbyte(0xf3); + + addbyte(0x83); /* AND EBX, 3 */ + addbyte(0xe3); + addbyte(0x03); + + addbyte(0xc1); /* SHL EBX, 3 */ + addbyte(0xe3); + addbyte(0x03); + + addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + + addbyte(0xf7); /* NOT EAX */ + addbyte(0xd0); + + addbyte(0x83); /* AND EAX, 7 */ + addbyte(0xe0); + addbyte(0x07); + + addbyte(0x09); /* OR EAX, EBX */ + addbyte(0xc3); + + addbyte(0x88); /* MOV CL, AL */ + addbyte(0xc1); + + addbyte(0xb8); /* MOV EAX, 1*/ + addlong(1); + + addbyte(0xd3); /* SHL EAX, CL */ + addbyte(0xe0); + + addbyte(0x85); /* TEST state->stipple[EDI], EAX */ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, stipple)); + + addbyte(0x0f); /* JZ stipple_skip_pos */ + addbyte(0x84); + stipple_skip_pos = block_pos; + addlong(0); + } else { + addbyte(0xd1); /* ROR state->stipple[EDI], 1*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, stipple)); + + addbyte(0xf7); /* TEST state->stipple[EDI], 0x80000000 */ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, stipple)); + addlong(0x80000000); + + addbyte(0x0f); /* JZ stipple_skip_pos */ + addbyte(0x84); + stipple_skip_pos = block_pos; + addlong(0); + } + } addbyte(0x4c); /*MOV RSI, R15*/ addbyte(0x89); addbyte(0xfe); @@ -3190,6 +3254,8 @@ voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, *(uint32_t *) &code_block[chroma_skip_pos] = (block_pos - chroma_skip_pos) - 4; if (amask_skip_pos) *(uint32_t *) &code_block[amask_skip_pos] = (block_pos - amask_skip_pos) - 4; + if (stipple_skip_pos) + *(uint32_t *) &code_block[stipple_skip_pos] = (block_pos - stipple_skip_pos) - 4; addbyte(0x4c); /*MOV RSI, R15*/ addbyte(0x89); diff --git a/src/include/86box/vid_voodoo_regs.h b/src/include/86box/vid_voodoo_regs.h index 3340720a7..9f3260c9f 100644 --- a/src/include/86box/vid_voodoo_regs.h +++ b/src/include/86box/vid_voodoo_regs.h @@ -358,6 +358,7 @@ enum { enum { FBZ_CHROMAKEY = (1 << 1), + FBZ_STIPPLE = (1 << 2), FBZ_W_BUFFER = (1 << 3), FBZ_DEPTH_ENABLE = (1 << 4), @@ -366,6 +367,8 @@ enum { FBZ_DEPTH_WMASK = (1 << 10), FBZ_DITHER_2x2 = (1 << 11), + FBZ_STIPPLE_PATT = (1 << 12), + FBZ_ALPHA_MASK = (1 << 13), FBZ_DRAW_FRONT = 0x0000, diff --git a/src/video/vid_voodoo_fb.c b/src/video/vid_voodoo_fb.c index 1c140873f..a97ca62a7 100644 --- a/src/video/vid_voodoo_fb.c +++ b/src/video/vid_voodoo_fb.c @@ -254,6 +254,19 @@ voodoo_fb_writew(uint32_t addr, uint16_t val, void *priv) int colbfog_g = 0; int colbfog_b = 0; + if (params->fbzMode & FBZ_STIPPLE) { + if (params->fbzMode & FBZ_STIPPLE_PATT) { + int index = ((y & 3) << 3) | (~x & 7); + if (!(params->stipple & (1 << index))) + goto skip_pixel; + } else { + voodoo->params.stipple = (voodoo->params.stipple << 1) | (voodoo->params.stipple >> 31); + if (!(voodoo->params.stipple & 0x80000000)) { + goto skip_pixel; + } + } + } + if (params->fbzMode & FBZ_DEPTH_ENABLE) { uint16_t old_depth = *(uint16_t *) (&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]); @@ -449,6 +462,19 @@ voodoo_fb_writel(uint32_t addr, uint32_t val, void *priv) int colbfog_g = 0; int colbfog_b = 0; + if (params->fbzMode & FBZ_STIPPLE) { + if (params->fbzMode & FBZ_STIPPLE_PATT) { + int index = ((y & 3) << 3) | (~(x + c) & 7); + if (!(params->stipple & (1 << index))) + goto skip_pixel; + } else { + voodoo->params.stipple = (voodoo->params.stipple << 1) | (voodoo->params.stipple >> 31); + if (!(voodoo->params.stipple & 0x80000000)) { + goto skip_pixel; + } + } + } + if (params->fbzMode & FBZ_DEPTH_ENABLE) { uint16_t old_depth = *(uint16_t *) (&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]); diff --git a/src/video/vid_voodoo_render.c b/src/video/vid_voodoo_render.c index 97186634d..b25f42507 100644 --- a/src/video/vid_voodoo_render.c +++ b/src/video/vid_voodoo_render.c @@ -88,6 +88,8 @@ typedef struct voodoo_state_t { uint32_t texBaseAddr; int lod_frac[2]; + + int stipple; } voodoo_state_t; #ifdef ENABLE_VOODOO_RENDER_LOG @@ -990,6 +992,20 @@ voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t * w_depth = 0xffff; } + if (params->fbzMode & FBZ_STIPPLE) { + if (params->fbzMode & FBZ_STIPPLE_PATT) { + int index = ((real_y & 3) << 3) | (~x & 7); + + if (!(state->stipple & (1 << index))) + goto skip_pixel; + } else { + state->stipple = (state->stipple << 1) | (state->stipple >> 31); + if (!(state->stipple & 0x80000000)) { + goto skip_pixel; + } + } + } + #if 0 w_depth = CLAMP16(w_depth); #endif @@ -1560,6 +1576,7 @@ voodoo_render_log("voodoo_triangle %i %i %i : vA %f, %f vB %f, %f vC %f, %f f if (lodbias & 0x20) lodbias |= ~0x3f; state.tmu[1].lod = LOD + (lodbias << 6); + state.stipple = params->stipple; voodoo_half_triangle(voodoo, params, &state, vertexAy_adjusted, vertexCy_adjusted, odd_even); }