From 6b821d2062f28d8b04c7e02447ed066b50936eea Mon Sep 17 00:00:00 2001 From: Erik Abair Date: Sat, 22 Jan 2022 12:11:54 -0800 Subject: [PATCH] nv2a: Implement pvideo color keying --- hw/xbox/nv2a/nv2a_int.h | 2 ++ hw/xbox/nv2a/nv2a_regs.h | 6 ++++++ hw/xbox/nv2a/pgraph.c | 24 ++++++++++++++++++++++-- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/hw/xbox/nv2a/nv2a_int.h b/hw/xbox/nv2a/nv2a_int.h index 4500b9119d..935011ea30 100644 --- a/hw/xbox/nv2a/nv2a_int.h +++ b/hw/xbox/nv2a/nv2a_int.h @@ -265,6 +265,8 @@ typedef struct PGRAPHState { GLint pvideo_enable_loc; GLint pvideo_tex_loc; GLint pvideo_pos_loc; + GLint pvideo_color_key_enable_loc; + GLint pvideo_color_key_loc; GLint palette_loc[256]; } disp_rndr; diff --git a/hw/xbox/nv2a/nv2a_regs.h b/hw/xbox/nv2a/nv2a_regs.h index 364ab4cd16..e512287761 100644 --- a/hw/xbox/nv2a/nv2a_regs.h +++ b/hw/xbox/nv2a/nv2a_regs.h @@ -653,6 +653,12 @@ # define NV_PVIDEO_FORMAT_COLOR 0x00030000 # define NV_PVIDEO_FORMAT_COLOR_LE_CR8YB8CB8YA8 1 # define NV_PVIDEO_FORMAT_DISPLAY (1 << 20) +# define NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY 1 +#define NV_PVIDEO_COLOR_KEY 0x00000B00 +# define NV_PVIDEO_COLOR_KEY_RED 0x00FF0000 +# define NV_PVIDEO_COLOR_KEY_GREEN 0x0000FF00 +# define NV_PVIDEO_COLOR_KEY_BLUE 0x000000FF +# define NV_PVIDEO_COLOR_KEY_ALPHA 0xFF000000 #define NV_PTIMER_INTR_0 0x00000100 diff --git a/hw/xbox/nv2a/pgraph.c b/hw/xbox/nv2a/pgraph.c index d058646e14..3c693a8532 100644 --- a/hw/xbox/nv2a/pgraph.c +++ b/hw/xbox/nv2a/pgraph.c @@ -4530,6 +4530,8 @@ static void pgraph_init_display_renderer(NV2AState *d) "uniform bool pvideo_enable;\n" "uniform sampler2D pvideo_tex;\n" "uniform vec4 pvideo_pos;\n" + "uniform bool pvideo_color_key_enable;\n" + "uniform vec4 pvideo_color_key;\n" "uniform vec2 display_size;\n" "uniform float line_offset;\n" "layout(location = 0) out vec4 out_Color;\n" @@ -4546,7 +4548,9 @@ static void pgraph_init_display_renderer(NV2AState *d) " if (!any(clip)) {\n" " vec2 spos = vec2(gl_FragCoord.x, textureSize(tex,0).y-gl_FragCoord.y);\n" " vec2 coord = (spos-pvideo_pos.xy)/pvideo_pos.zw;\n" - " out_Color.rgba = texture(pvideo_tex, coord);\n" + " if (!pvideo_color_key_enable || out_Color.rgba == pvideo_color_key) {\n" + " out_Color.rgba = texture(pvideo_tex, coord);\n" + " }\n" " }\n" " }\n" "}\n"; @@ -4556,6 +4560,8 @@ static void pgraph_init_display_renderer(NV2AState *d) pg->disp_rndr.pvideo_enable_loc = glGetUniformLocation(pg->disp_rndr.prog, "pvideo_enable"); pg->disp_rndr.pvideo_tex_loc = glGetUniformLocation(pg->disp_rndr.prog, "pvideo_tex"); pg->disp_rndr.pvideo_pos_loc = glGetUniformLocation(pg->disp_rndr.prog, "pvideo_pos"); + pg->disp_rndr.pvideo_color_key_enable_loc = glGetUniformLocation(pg->disp_rndr.prog, "pvideo_color_key_enable"); + pg->disp_rndr.pvideo_color_key_loc = glGetUniformLocation(pg->disp_rndr.prog, "pvideo_color_key"); pg->disp_rndr.display_size_loc = glGetUniformLocation(pg->disp_rndr.prog, "display_size"); pg->disp_rndr.line_offset_loc = glGetUniformLocation(pg->disp_rndr.prog, "line_offset"); @@ -4630,7 +4636,21 @@ static void pgraph_render_display_pvideo_overlay(NV2AState *d) unsigned int out_y = GET_MASK(d->pvideo.regs[NV_PVIDEO_POINT_OUT], NV_PVIDEO_POINT_OUT_Y); - /* TODO: color keys */ + unsigned int color_key_enabled = + GET_MASK(d->pvideo.regs[NV_PVIDEO_FORMAT], NV_PVIDEO_FORMAT_DISPLAY); + glUniform1ui(d->pgraph.disp_rndr.pvideo_color_key_enable_loc, + color_key_enabled); + + // TODO: Verify that masking off the top byte is correct. + // SeaBlade sets a color key of 0x80000000 but the texture passed into the + // shader is cleared to 0 alpha. + unsigned int color_key = d->pvideo.regs[NV_PVIDEO_COLOR_KEY] & 0xFFFFFF; + glUniform4f(d->pgraph.disp_rndr.pvideo_color_key_loc, + GET_MASK(color_key, NV_PVIDEO_COLOR_KEY_RED) / 255.0, + GET_MASK(color_key, NV_PVIDEO_COLOR_KEY_GREEN) / 255.0, + GET_MASK(color_key, NV_PVIDEO_COLOR_KEY_BLUE) / 255.0, + GET_MASK(color_key, NV_PVIDEO_COLOR_KEY_ALPHA) / 255.0); + assert(offset + in_pitch * in_height <= limit); hwaddr end = base + offset + in_pitch * in_height; assert(end <= memory_region_size(d->vram));