diff --git a/src/include/86box/vid_voodoo_codegen_x86-64.h b/src/include/86box/vid_voodoo_codegen_x86-64.h index e8b7299f2..8aba3e5b5 100644 --- a/src/include/86box/vid_voodoo_codegen_x86-64.h +++ b/src/include/86box/vid_voodoo_codegen_x86-64.h @@ -656,6 +656,7 @@ voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, 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; @@ -1732,6 +1733,15 @@ voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, addbyte(0xdb); break; } + if (params->fbzMode & FBZ_ALPHA_MASK) { + addbyte(0xf7); /*TEST EBX, 1*/ + addbyte(0xc3); + addlong(1); + addbyte(0x0f); /* JZ amask_skip_pos */ + addbyte(0x84); + amask_skip_pos = block_pos; + addlong(0); + } /*ECX = a_local*/ switch (cca_localselect) { case CCA_LOCALSELECT_ITER_A: @@ -2986,6 +2996,8 @@ voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, *(uint32_t *) &code_block[a_skip_pos] = (block_pos - a_skip_pos) - 4; if (chroma_skip_pos) *(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; addbyte(0x4c); /*MOV RSI, R15*/ addbyte(0x89); @@ -3225,6 +3237,12 @@ voodoo_get_block(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *stat voodoo_x86_data_t *voodoo_x86_data = voodoo->codegen_data; voodoo_x86_data_t *data; + if (params->fbzMode & FBZ_ALPHA_ENABLE) { + // Lands of Lore III relies on the alpha buffer functionality to create its transparent textures. + // Fallback to interpreter. + return NULL; + } + for (uint8_t c = 0; c < 8; c++) { data = &voodoo_x86_data[odd_even + c * 4]; //&voodoo_x86_data[odd_even][b]; diff --git a/src/include/86box/vid_voodoo_regs.h b/src/include/86box/vid_voodoo_regs.h index 6aeb98bcc..3340720a7 100644 --- a/src/include/86box/vid_voodoo_regs.h +++ b/src/include/86box/vid_voodoo_regs.h @@ -366,11 +366,14 @@ enum { FBZ_DEPTH_WMASK = (1 << 10), FBZ_DITHER_2x2 = (1 << 11), + FBZ_ALPHA_MASK = (1 << 13), + FBZ_DRAW_FRONT = 0x0000, FBZ_DRAW_BACK = 0x4000, FBZ_DRAW_MASK = 0xc000, FBZ_DEPTH_BIAS = (1 << 16), + FBZ_ALPHA_ENABLE = (1 << 18), FBZ_DITHER_SUB = (1 << 19), FBZ_DEPTH_SOURCE = (1 << 20), @@ -655,6 +658,8 @@ enum { #define src_afunc ((params->alphaMode >> 8) & 0xf) #define dest_afunc ((params->alphaMode >> 12) & 0xf) +#define src_aafunc ((params->alphaMode >> 16) & 0xf) +#define dest_aafunc ((params->alphaMode >> 20) & 0xf) #define alpha_func ((params->alphaMode >> 1) & 7) #define a_ref (params->alphaMode >> 24) #define depth_op ((params->fbzMode >> 5) & 7) diff --git a/src/video/vid_voodoo_render.c b/src/video/vid_voodoo_render.c index 9c1204bd3..97186634d 100644 --- a/src/video/vid_voodoo_render.c +++ b/src/video/vid_voodoo_render.c @@ -932,7 +932,7 @@ voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t * state->x = x; state->x2 = x2; #ifndef NO_CODEGEN - if (voodoo->use_recompiler) { + if (voodoo->use_recompiler && voodoo_draw) { voodoo_draw(state, params, x, real_y); } else #endif @@ -1017,6 +1017,13 @@ voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t * dest_b |= (dest_b >> 5); dest_a = 0xff; + if (params->fbzMode & FBZ_ALPHA_ENABLE) { + if (voodoo->params.aux_tiled) + dest_a = aux_mem[x_tiled]; + else + dest_a = aux_mem[x]; + } + if (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) { if ((params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL || !voodoo->dual_tmus) { /*TMU0 only sampling local colour or only one TMU, only sample TMU0*/ @@ -1032,11 +1039,6 @@ voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t * } else { voodoo_tmu_fetch_and_blend(voodoo, params, state, x); } - - if ((params->fbzMode & FBZ_CHROMAKEY) && state->tex_r[0] == params->chromaKey_r && state->tex_g[0] == params->chromaKey_g && state->tex_b[0] == params->chromaKey_b) { - voodoo->fbiChromaFail++; - goto skip_pixel; - } } if (voodoo->trexInit1[0] & (1 << 18)) { @@ -1088,6 +1090,11 @@ voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t * break; } + if ((params->fbzMode & FBZ_CHROMAKEY) && cother_r == params->chromaKey_r && cother_g == params->chromaKey_g && cother_b == params->chromaKey_b) { + voodoo->fbiChromaFail++; + goto skip_pixel; + } + switch (cca_localselect) { case CCA_LOCALSELECT_ITER_A: alocal = CLAMP(state->ia >> 12); @@ -1123,6 +1130,10 @@ voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t * break; } + if ((params->fbzMode & FBZ_ALPHA_MASK) && !(aother & 1)) { + goto skip_pixel; + } + if (cc_zero_other) { src_r = 0; src_g = 0; @@ -1283,6 +1294,9 @@ voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t * dest_b = dithersub_rb2x2[dest_b][real_y & 1][x & 1]; } ALPHA_BLEND(src_r, src_g, src_b, src_a); + + // TODO: Implement proper alpha blending support here for alpha values. + src_a = (((dest_aafunc == 4) ? dest_a * 256 : 0) + ((src_aafunc == 4) ? src_a * 256 : 0)) >> 8; } if (update) { @@ -1308,7 +1322,13 @@ voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t * else fb_mem[x] = src_b | (src_g << 5) | (src_r << 11); } - if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) { + if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_ALPHA_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_ALPHA_ENABLE)) { + if (voodoo->params.aux_tiled) + aux_mem[x_tiled] = src_a; + else + aux_mem[x] = src_a; + } + else if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) { if (voodoo->params.aux_tiled) aux_mem[x_tiled] = new_depth; else