From c1dbffe5fdebb37a479586f89ef53d5112a3e979 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sun, 12 Jul 2015 04:23:48 +0200 Subject: [PATCH 01/25] More texture modes --- hw/xbox/nv2a_psh.c | 52 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/hw/xbox/nv2a_psh.c b/hw/xbox/nv2a_psh.c index 87ed625fb3..09cb9cb7cb 100644 --- a/hw/xbox/nv2a_psh.c +++ b/hw/xbox/nv2a_psh.c @@ -562,11 +562,14 @@ static QString* psh_convert(struct PixelShader *ps) qstring_append(vars, "float fog = pFog.x;\n"); for (i = 0; i < 4; i++) { - if (ps->tex_modes[i] == PS_TEXTUREMODES_NONE) continue; const char *sampler_type = NULL; switch (ps->tex_modes[i]) { + case PS_TEXTUREMODES_NONE: + qstring_append_fmt(vars, "vec4 t%d = vec4(0.0); /* PS_TEXTUREMODES_NONE */\n", + i); + break; case PS_TEXTUREMODES_PROJECT2D: if (ps->rect_tex[i]) { sampler_type = "sampler2DRect"; @@ -578,24 +581,61 @@ static QString* psh_convert(struct PixelShader *ps) break; case PS_TEXTUREMODES_PROJECT3D: sampler_type = "sampler3D"; - qstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, pT%d.xyz);\n", + qstring_append_fmt(vars, "vec4 t%d = textureProj(texSamp%d, pT%d.xyzw);\n", i, i, i); break; case PS_TEXTUREMODES_CUBEMAP: sampler_type = "samplerCube"; - qstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, pT%d.xyz);\n", - i, i, i); + qstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, pT%d.xyz / pT%d.w);\n", + i, i, i, i); break; case PS_TEXTUREMODES_PASSTHRU: qstring_append_fmt(vars, "vec4 t%d = pT%d;\n", i, i); break; + case PS_TEXTUREMODES_DPNDNT_AR: + assert(!ps->rect_tex[i]); + sampler_type = "sampler2D"; + qstring_append_fmt(vars, " vec4 t%d = texture(texSamp%d, t%d.ar);\n", + i, i, ps->input_tex[i]); + break; + case PS_TEXTUREMODES_DPNDNT_GB: + assert(!ps->rect_tex[i]); + sampler_type = "sampler2D"; + qstring_append_fmt(vars, " vec4 t%d = texture(texSamp%d, t%d.gb);\n", + i, i, ps->input_tex[i]); + break; + case PS_TEXTUREMODES_BUMPENVMAP: + assert(!ps->rect_tex[i]); + sampler_type = "sampler2D"; + qstring_append_fmt(vars, " mat2 texBumpMat%d = mat2(1.0,0.0,0.0,1.0);\n", + i); /* FIXME: Uniform and fill */ + qstring_append_fmt(vars, " vec4 t%d = texture(texSamp%d, pT%d.xy + t%d.rg * texBumpMat%d);\n", + i, i, i, ps->input_tex[i], i); + break; + case PS_TEXTUREMODES_CLIPPLANE: { + int j; + qstring_append_fmt(vars, " vec4 t%d = vec4(0.0); /* PS_TEXTUREMODES_CLIPPLANE */\n", + i); +#if 0 /* FIXME: Compare mode missing! */ + for (j = 0; j < 4; j++) { + qstring_append_fmt(vars, " if(pT%d.%c %s 0.0) { discard; };\n", + i, "xyzw"[j], + ps->compare_mode[i][j] ? ">=" : "<"); + } +#endif + break; + } + case PS_TEXTUREMODES_DOTPRODUCT: + qstring_append_fmt(vars, " vec4 t%d = vec4(dot(pT%d.xyz, t%d.rgb));\n", + i, i, ps->input_tex[i]); + break; default: printf("%x\n", ps->tex_modes[i]); assert(false); break; } - if (ps->tex_modes[i] != PS_TEXTUREMODES_PASSTHRU) { + if (sampler_type != NULL) { qstring_append_fmt(preflight, "uniform %s texSamp%d;\n", sampler_type, i); } } @@ -762,4 +802,4 @@ QString *psh_translate(uint32_t combiner_control, uint32_t shader_stage_program, return psh_convert(&ps); -} \ No newline at end of file +} From 7f4d7e9cccb1627b98797d99dcd65ecca9d4df64 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Mon, 13 Jul 2015 19:42:10 +0200 Subject: [PATCH 02/25] Alphakill, Texkill and Bumpmapping --- hw/xbox/nv2a.c | 45 ++++++++++++++++++++++++++++++++++++++++----- hw/xbox/nv2a_psh.c | 26 +++++++++++++++++++++----- hw/xbox/nv2a_psh.h | 4 +++- 3 files changed, 64 insertions(+), 11 deletions(-) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index 6c76546ac5..aaaf6f16ef 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -448,6 +448,7 @@ static void gl_debug_label(GLenum target, GLuint name, const char *fmt, ...) # define NV_PGRAPH_CONTROL_2_STENCIL_OP_V_DECR 8 #define NV_PGRAPH_SETUPRASTER 0x00001990 # define NV_PGRAPH_SETUPRASTER_Z_FORMAT (1 << 29) +#define NV_PGRAPH_SHADERCLIPMODE 0x00001994 #define NV_PGRAPH_SHADERCTL 0x00001998 #define NV_PGRAPH_SHADERPROG 0x0000199C #define NV_PGRAPH_SPECFOGFACTOR0 0x000019AC @@ -457,9 +458,10 @@ static void gl_debug_label(GLenum target, GLuint name, const char *fmt, ...) #define NV_PGRAPH_TEXADDRESS2 0x000019C4 #define NV_PGRAPH_TEXADDRESS3 0x000019C8 #define NV_PGRAPH_TEXCTL0_0 0x000019CC -# define NV_PGRAPH_TEXCTL0_0_ENABLE (1 << 30) -# define NV_PGRAPH_TEXCTL0_0_MIN_LOD_CLAMP 0x3FFC0000 +# define NV_PGRAPH_TEXCTL0_0_ALPHAKILLEN (1 << 2) # define NV_PGRAPH_TEXCTL0_0_MAX_LOD_CLAMP 0x0003FFC0 +# define NV_PGRAPH_TEXCTL0_0_MIN_LOD_CLAMP 0x3FFC0000 +# define NV_PGRAPH_TEXCTL0_0_ENABLE (1 << 30) #define NV_PGRAPH_TEXCTL0_1 0x000019D0 #define NV_PGRAPH_TEXCTL0_2 0x000019D4 #define NV_PGRAPH_TEXCTL0_3 0x000019D8 @@ -816,6 +818,7 @@ static void gl_debug_label(GLenum target, GLuint name, const char *fmt, ...) # define NV097_SET_VERTEX_DATA_ARRAY_FORMAT_STRIDE 0xFFFFFF00 # define NV097_SET_LOGIC_OP_ENABLE 0x009717BC # define NV097_SET_LOGIC_OP 0x009717C0 +# define NV097_SET_SHADER_CLIP_PLANE_MODE 0x009717F8 # define NV097_SET_BEGIN_END 0x009717FC # define NV097_SET_BEGIN_END_OP_END 0x00 # define NV097_SET_BEGIN_END_OP_POINTS 0x01 @@ -889,6 +892,7 @@ static void gl_debug_label(GLenum target, GLuint name, const char *fmt, ...) # define NV097_SET_TEXTURE_PALETTE_LENGTH_64 2 # define NV097_SET_TEXTURE_PALETTE_LENGTH_32 3 # define NV097_SET_TEXTURE_PALETTE_OFFSET 0xFFFFFFC0 +# define NV097_SET_TEXTURE_SET_BUMP_ENV_MAT 0x00971B28 # define NV097_SET_SEMAPHORE_OFFSET 0x00971D6C # define NV097_BACK_END_WRITE_SEMAPHORE_RELEASE 0x00971D70 # define NV097_SET_ZSTENCIL_CLEAR_VALUE 0x00971D8C @@ -1232,6 +1236,8 @@ typedef struct ShaderState { uint32_t alpha_inputs[8], alpha_outputs[8]; bool rect_tex[4]; + bool compare_mode[4][4]; + bool alphakill[4]; bool alpha_test; enum AlphaFunc alpha_func; @@ -1389,7 +1395,7 @@ typedef struct PGRAPHState { ShaderBinding *shader_binding; float composite_matrix[16]; - GLint composite_matrix_location; + float texture_bump_matrix[4]; GloContext *gl_context; GLuint gl_framebuffer; @@ -2580,6 +2586,8 @@ static ShaderBinding* generate_shaders(const ShaderState state) state.final_inputs_0, state.final_inputs_1, /* final_constant_0, final_constant_1, */ state.rect_tex, + state.compare_mode, + state.alphakill, state.alpha_test, state.alpha_func); const char *fragment_shader_code_str = qstring_get_str(fragment_shader_code); @@ -2767,6 +2775,15 @@ static void pgraph_bind_shaders(PGRAPHState *pg) if (enabled && kelvin_color_format_map[color_format].linear) { state.rect_tex[i] = true; } + + int j; + for(j = 0; j < 4; j++) { + /* compare_mode[i][j] = stage i, component j { s,t,r,q } */ + state.compare_mode[i][j] = + (pg->regs[NV_PGRAPH_SHADERCLIPMODE] >> (4 * i + j)) & 1; + } + state.alphakill[i] = GET_MASK(pg->regs[NV_PGRAPH_TEXCTL0_0 + i*4], + NV_PGRAPH_TEXCTL0_0_ALPHAKILLEN); } ShaderBinding* cached_shader = g_hash_table_lookup(pg->shader_cache, &state); @@ -2821,7 +2838,13 @@ static void pgraph_bind_shaders(PGRAPHState *pg) glUniform1f(alpha_ref_loc, alpha_ref); } - + GLint tex_bump_mat_loc = glGetUniformLocation( + pg->shader_binding->gl_program, + "texBumpMat"); + if (tex_bump_mat_loc != -1) { + glUniformMatrix2fv(tex_bump_mat_loc, 1, GL_FALSE, + pg->texture_bump_matrix); + } float zclip_max = *(float*)&pg->regs[NV_PGRAPH_ZCLIPMAX]; float zclip_min = *(float*)&pg->regs[NV_PGRAPH_ZCLIPMIN]; @@ -2829,7 +2852,8 @@ static void pgraph_bind_shaders(PGRAPHState *pg) if (fixed_function) { /* update fixed function composite matrix */ - GLint comLoc = glGetUniformLocation(pg->shader_binding->gl_program, "composite"); + GLint comLoc = glGetUniformLocation(pg->shader_binding->gl_program, + "composite"); assert(comLoc != -1); glUniformMatrix4fv(comLoc, 1, GL_FALSE, pg->composite_matrix); @@ -4438,6 +4462,13 @@ static void pgraph_method(NV2AState *d, pg->texture_dirty[slot] = true; break; } + + case NV097_SET_TEXTURE_SET_BUMP_ENV_MAT ... + NV097_SET_TEXTURE_SET_BUMP_ENV_MAT + 0xc: + slot = (class_method - NV097_SET_TEXTURE_SET_BUMP_ENV_MAT) / 4; + pg->texture_bump_matrix[slot] = *(float*)¶meter; + break; + case NV097_ARRAY_ELEMENT16: assert(pg->inline_elements_length < NV2A_MAX_BATCH_LENGTH); pg->inline_elements[ @@ -4622,6 +4653,10 @@ static void pgraph_method(NV2AState *d, pg->regs[NV_PGRAPH_SPECFOGFACTOR0 + slot*4] = parameter; break; + case NV097_SET_SHADER_CLIP_PLANE_MODE: + pg->regs[NV_PGRAPH_SHADERCLIPMODE] = parameter; + break; + case NV097_SET_COMBINER_COLOR_OCW ... NV097_SET_COMBINER_COLOR_OCW + 28: slot = (class_method - NV097_SET_COMBINER_COLOR_OCW) / 4; diff --git a/hw/xbox/nv2a_psh.c b/hw/xbox/nv2a_psh.c index 09cb9cb7cb..6f83819344 100644 --- a/hw/xbox/nv2a_psh.c +++ b/hw/xbox/nv2a_psh.c @@ -197,9 +197,12 @@ struct PixelShader { struct FCInputInfo final_input; int tex_modes[4], input_tex[4]; - //uint32_t compare_mode, dot_mapping, input_texture; + //uint32_t dot_mapping, input_texture; bool rect_tex[4]; + bool compare_mode[4][4]; + bool alphakill[4]; + bool alpha_test; enum AlphaFunc alpha_func; @@ -561,6 +564,7 @@ static QString* psh_convert(struct PixelShader *ps) qstring_append(vars, "vec4 v1 = pD1;\n"); qstring_append(vars, "float fog = pFog.x;\n"); + bool bumpenvmap = false; for (i = 0; i < 4; i++) { const char *sampler_type = NULL; @@ -607,22 +611,21 @@ static QString* psh_convert(struct PixelShader *ps) case PS_TEXTUREMODES_BUMPENVMAP: assert(!ps->rect_tex[i]); sampler_type = "sampler2D"; - qstring_append_fmt(vars, " mat2 texBumpMat%d = mat2(1.0,0.0,0.0,1.0);\n", - i); /* FIXME: Uniform and fill */ + bumpenvmap = true; + assert(false); /* FIXME: Untested */ qstring_append_fmt(vars, " vec4 t%d = texture(texSamp%d, pT%d.xy + t%d.rg * texBumpMat%d);\n", i, i, i, ps->input_tex[i], i); break; case PS_TEXTUREMODES_CLIPPLANE: { int j; + assert(false); /* FIXME: Untested */ qstring_append_fmt(vars, " vec4 t%d = vec4(0.0); /* PS_TEXTUREMODES_CLIPPLANE */\n", i); -#if 0 /* FIXME: Compare mode missing! */ for (j = 0; j < 4; j++) { qstring_append_fmt(vars, " if(pT%d.%c %s 0.0) { discard; };\n", i, "xyzw"[j], ps->compare_mode[i][j] ? ">=" : "<"); } -#endif break; } case PS_TEXTUREMODES_DOTPRODUCT: @@ -637,9 +640,20 @@ static QString* psh_convert(struct PixelShader *ps) if (sampler_type != NULL) { qstring_append_fmt(preflight, "uniform %s texSamp%d;\n", sampler_type, i); + + /* As this means a texture fetch does happen, do alphakill */ + if (ps->alphakill[i]) { + assert(false); /* FIXME: Untested */ + qstring_append_fmt(vars, " if (t%d.a == 0.0) { discard; };\n", + i); + } } } + if (bumpenvmap) { + qstring_append(preflight, " uniform mat2 texBumpMat\n"); + } + ps->code = qstring_new(); for (i = 0; i < ps->num_stages; i++) { ps->cur_stage = i; @@ -748,6 +762,8 @@ QString *psh_translate(uint32_t combiner_control, uint32_t shader_stage_program, uint32_t final_inputs_0, uint32_t final_inputs_1, /*uint32_t final_constant_0, uint32_t final_constant_1,*/ const bool rect_tex[4], + const bool compare_mode[4][4], + const bool alphakill[4], bool alpha_test, enum AlphaFunc alpha_func) { int i; diff --git a/hw/xbox/nv2a_psh.h b/hw/xbox/nv2a_psh.h index 51d2623f82..d75043797d 100644 --- a/hw/xbox/nv2a_psh.h +++ b/hw/xbox/nv2a_psh.h @@ -45,6 +45,8 @@ QString *psh_translate(uint32_t combiner_control, uint32_t shader_stage_program, uint32_t final_inputs_0, uint32_t final_inputs_1, /*uint32_t final_constant_0, uint32_t final_constant_1,*/ const bool rect_tex[4], + const bool compare_mode[4][4], + const bool alphakill[4], bool alpha_test, enum AlphaFunc alpha_func); -#endif \ No newline at end of file +#endif From 114679b2a2a14726ffa25df78e30e9ece9fc297e Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 16 Jul 2015 02:44:25 +0200 Subject: [PATCH 03/25] Add texture addressing --- hw/xbox/nv2a.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index aaaf6f16ef..0b1533144d 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -454,6 +454,18 @@ static void gl_debug_label(GLenum target, GLuint name, const char *fmt, ...) #define NV_PGRAPH_SPECFOGFACTOR0 0x000019AC #define NV_PGRAPH_SPECFOGFACTOR1 0x000019B0 #define NV_PGRAPH_TEXADDRESS0 0x000019BC +# define NV_PGRAPH_TEXADDRESS0_ADDRU 0x00000007 +# define NV_PGRAPH_TEXADDRESS0_ADDRU_WRAP 1 +# define NV_PGRAPH_TEXADDRESS0_ADDRU_MIRROR 2 +# define NV_PGRAPH_TEXADDRESS0_ADDRU_CLAMP_TO_EDGE 3 +# define NV_PGRAPH_TEXADDRESS0_ADDRU_BORDER 4 +# define NV_PGRAPH_TEXADDRESS0_ADDRU_CLAMP_OGL 5 +# define NV_PGRAPH_TEXADDRESS0_WRAP_U (1 << 4) +# define NV_PGRAPH_TEXADDRESS0_ADDRV 0x00000700 +# define NV_PGRAPH_TEXADDRESS0_WRAP_V (1 << 12) +# define NV_PGRAPH_TEXADDRESS0_ADDRP 0x00070000 +# define NV_PGRAPH_TEXADDRESS0_WRAP_P (1 << 20) +# define NV_PGRAPH_TEXADDRESS0_WRAP_Q (1 << 24) #define NV_PGRAPH_TEXADDRESS1 0x000019C0 #define NV_PGRAPH_TEXADDRESS2 0x000019C4 #define NV_PGRAPH_TEXADDRESS3 0x000019C8 @@ -954,6 +966,15 @@ static const GLenum pgraph_texture_mag_filter_map[] = { GL_LINEAR /* TODO: Convolution filter... */ }; +static const GLenum pgraph_texture_addr_map[] = { + 0, + GL_REPEAT, + GL_MIRRORED_REPEAT, + GL_CLAMP_TO_EDGE, + GL_CLAMP_TO_BORDER, + GL_CLAMP +}; + static const GLenum pgraph_blend_factor_map[] = { GL_ZERO, GL_ONE, @@ -2153,6 +2174,7 @@ static void pgraph_bind_textures(NV2AState *d) uint32_t ctl_1 = pg->regs[NV_PGRAPH_TEXCTL1_0 + i*4]; uint32_t fmt = pg->regs[NV_PGRAPH_TEXFMT0 + i*4]; uint32_t filter = pg->regs[NV_PGRAPH_TEXFILTER0 + i*4]; + uint32_t address = pg->regs[NV_PGRAPH_TEXADDRESS0 + i*4]; uint32_t palette = pg->regs[NV_PGRAPH_TEXPALETTE0 + i*4]; bool enabled = GET_MASK(ctl_0, NV_PGRAPH_TEXCTL0_0_ENABLE); @@ -2185,6 +2207,10 @@ static void pgraph_bind_textures(NV2AState *d) unsigned int min_filter = GET_MASK(filter, NV_PGRAPH_TEXFILTER0_MIN); unsigned int mag_filter = GET_MASK(filter, NV_PGRAPH_TEXFILTER0_MAG); + unsigned int addru = GET_MASK(address, NV_PGRAPH_TEXADDRESS0_ADDRU); + unsigned int addrv = GET_MASK(address, NV_PGRAPH_TEXADDRESS0_ADDRV); + unsigned int addrp = GET_MASK(address, NV_PGRAPH_TEXADDRESS0_ADDRP); + unsigned int offset = pg->regs[NV_PGRAPH_TEXOFFSET0 + i*4]; bool palette_dma_select = @@ -2334,6 +2360,18 @@ static void pgraph_bind_textures(NV2AState *d) glTexParameteri(binding->gl_target, GL_TEXTURE_MAG_FILTER, pgraph_texture_mag_filter_map[mag_filter]); + /* Texture wrapping */ + glTexParameteri(binding->gl_target, GL_TEXTURE_WRAP_S, + pgraph_texture_addr_map[addru]); + if (dimensionality > 1) { + glTexParameteri(binding->gl_target, GL_TEXTURE_WRAP_T, + pgraph_texture_addr_map[addrv]); + } + if (dimensionality > 2) { + glTexParameteri(binding->gl_target, GL_TEXTURE_WRAP_R, + pgraph_texture_addr_map[addrp]); + } + if (pg->texture_binding[i]) { texture_binding_destroy(pg->texture_binding[i]); } @@ -3771,6 +3809,10 @@ static void pgraph_method(NV2AState *d, pg->regs[NV_PGRAPH_COMBINESPECFOG1] = parameter; break; + CASE_4(NV097_SET_TEXTURE_ADDRESS, 64): + slot = (class_method - NV097_SET_TEXTURE_ADDRESS) / 64; + pg->regs[NV_PGRAPH_TEXADDRESS0 + slot * 4] = parameter; + break; case NV097_SET_CONTROL0: { pgraph_update_surface(d, false, true, true); From dd935fffa67232d79e37a756cc8bc7b6038d1a94 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 16 Jul 2015 10:34:43 +0200 Subject: [PATCH 04/25] New delta texture modes (req. GL_EXT_texture_snorm) and RGB_565 internal format (req. GL_ARB_ES2_compatibility) --- hw/xbox/nv2a.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index 0b1533144d..7c579f96bf 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -873,6 +873,7 @@ static void gl_debug_label(GLenum target, GLuint name, const char *fmt, ...) # define NV097_SET_TEXTURE_FORMAT_COLOR_SZ_A8 0x19 # define NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_X8R8G8B8 0x1E # define NV097_SET_TEXTURE_FORMAT_COLOR_LC_IMAGE_CR8YB8CB8YA8 0x24 +# define NV097_SET_TEXTURE_FORMAT_COLOR_SZ_R6G5B5 0x27 # define NV097_SET_TEXTURE_FORMAT_COLOR_SZ_G8B8 0x28 # define NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_DEPTH_X8_Y24_FIXED 0x2E # define NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_DEPTH_Y16_FIXED 0x30 @@ -1077,7 +1078,7 @@ static const ColorFormatInfo kelvin_color_format_map[66] = { [NV097_SET_TEXTURE_FORMAT_COLOR_SZ_A4R4G4B4] = {2, false, GL_RGBA4, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV}, [NV097_SET_TEXTURE_FORMAT_COLOR_SZ_R5G6B5] = - {2, false, GL_RGB5, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, + {2, false, GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, [NV097_SET_TEXTURE_FORMAT_COLOR_SZ_A8R8G8B8] = {4, false, GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV}, [NV097_SET_TEXTURE_FORMAT_COLOR_SZ_X8R8G8B8] = @@ -1095,7 +1096,7 @@ static const ColorFormatInfo kelvin_color_format_map[66] = { {4, false, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0, GL_RGBA}, [NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_R5G6B5] = - {2, true, GL_RGB5, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, + {2, true, GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, [NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_A8R8G8B8] = {4, true, GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV}, [NV097_SET_TEXTURE_FORMAT_COLOR_SZ_A8] = @@ -1104,8 +1105,10 @@ static const ColorFormatInfo kelvin_color_format_map[66] = { [NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_X8R8G8B8] = {4, true, GL_RGB8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV}, + [NV097_SET_TEXTURE_FORMAT_COLOR_SZ_R6G5B5] = + {2, false, GL_RGB8_SNORM, GL_RGB, GL_BYTE}, /* FIXME: This might be signed */ [NV097_SET_TEXTURE_FORMAT_COLOR_SZ_G8B8] = - {2, false, GL_RG8, GL_RG, GL_UNSIGNED_BYTE}, + {2, false, GL_RG8_SNORM, GL_RG, GL_BYTE}, /* FIXME: This might be signed */ /* TODO: format conversion */ [NV097_SET_TEXTURE_FORMAT_COLOR_LC_IMAGE_CR8YB8CB8YA8] = @@ -1131,7 +1134,7 @@ static const SurfaceColorFormatInfo kelvin_surface_color_format_map[] = { [NV097_SET_SURFACE_FORMAT_COLOR_LE_X1R5G5B5_Z1R5G5B5] = {2, GL_RGB5_A1, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV}, [NV097_SET_SURFACE_FORMAT_COLOR_LE_R5G6B5] = - {2, GL_RGB5, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, + {2, GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, [NV097_SET_SURFACE_FORMAT_COLOR_LE_X8R8G8B8_Z8R8G8B8] = {4, GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV}, [NV097_SET_SURFACE_FORMAT_COLOR_LE_A8R8G8B8] = @@ -1999,6 +2002,30 @@ static uint8_t* convert_texture_data(const TextureShape s, } } return converted_data; + } else if (s.color_format + == NV097_SET_TEXTURE_FORMAT_COLOR_SZ_R6G5B5) { + uint8_t *converted_data = g_malloc(width * height * 3); + int x, y; + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + uint8_t v; + uint16_t rgb565 = *(uint16_t*)(data + y * pitch + x * 2); + int8_t *pixel = &converted_data[(y * width + x) * 3]; + /* FIXME: This is pretty ugly code to extend from + * signed 565 to signed 888 (hopefully) + */ + v = (rgb565 & 0xF800) >> 8; + pixel[0] = (v & 0x80) ? *(int8_t*)&v * 16 / 0x80 + : ((v & 0x78) * 15) / 0x78; + v = (rgb565 & 0x07E0) >> 3; + pixel[1] = (v & 0x80) ? *(int8_t*)&v * 32 / 0x80 + : ((v & 0x7C) * 31) / 0x7C; + v = (rgb565 & 0x001F) << 3; + pixel[2] = (v & 0x80) ? *(int8_t*)&v * 16 / 0x80 + : ((v & 0x78) * 15) / 0x78; + } + } + return converted_data; } else { return NULL; } @@ -3385,6 +3412,8 @@ static void pgraph_init(NV2AState *d) glextensions_init(); assert(glo_check_extension("GL_EXT_texture_compression_s3tc")); + assert(glo_check_extension("GL_EXT_texture_snorm")); + assert(glo_check_extension("GL_ARB_ES2_compatibility")); GLint max_vertex_attributes; glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &max_vertex_attributes); From f8ace726674dc6e60e85b9c69f01db886002d9d6 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 16 Jul 2015 10:37:57 +0200 Subject: [PATCH 05/25] Better style in nv2a --- hw/xbox/nv2a.c | 30 ++++++++++++++++-------------- hw/xbox/nv2a_vsh.h | 2 +- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index 7c579f96bf..d3edf4f4a0 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -926,8 +926,8 @@ static void gl_debug_label(GLenum target, GLuint name, const char *fmt, ...) # define NV097_SET_SHADER_STAGE_PROGRAM 0x00971E70 # define NV097_SET_SHADER_OTHER_STAGE_INPUT 0x00971E78 # define NV097_SET_TRANSFORM_EXECUTION_MODE 0x00971E94 -# define NV_097_SET_TRANSFORM_EXECUTION_MODE_MODE 0x00000003 -# define NV_097_SET_TRANSFORM_EXECUTION_MODE_RANGE_MODE 0xFFFFFFFC +# define NV097_SET_TRANSFORM_EXECUTION_MODE_MODE 0x00000003 +# define NV097_SET_TRANSFORM_EXECUTION_MODE_RANGE_MODE 0xFFFFFFFC # define NV097_SET_TRANSFORM_PROGRAM_CXT_WRITE_EN 0x00971E98 # define NV097_SET_TRANSFORM_PROGRAM_LOAD 0x00971E9C # define NV097_SET_TRANSFORM_PROGRAM_START 0x00971EA0 @@ -2057,7 +2057,7 @@ static TextureBinding* generate_texture(const TextureShape s, glBindTexture(gl_target, gl_texture); NV2A_GL_DLABEL(GL_TEXTURE, gl_texture, - "format: 0x%02X%s, width: %i", + "format: 0x%02X%s, width: %d", s.color_format, f.linear ? "" : " (SZ)", s.width); if (f.linear) { @@ -2761,7 +2761,7 @@ static ShaderBinding* generate_shaders(const ShaderState state) static void pgraph_bind_shaders(PGRAPHState *pg) { - int i; + int i, j; bool vertex_program = GET_MASK(pg->regs[NV_PGRAPH_CSV0_D], NV_PGRAPH_CSV0_D_MODE) == 2; @@ -2831,8 +2831,8 @@ static void pgraph_bind_shaders(PGRAPHState *pg) for (i = 0; i < 4; i++) { state.rect_tex[i] = false; - bool enabled = GET_MASK(pg->regs[NV_PGRAPH_TEXCTL0_0 + i*4], - NV_PGRAPH_TEXCTL0_0_ENABLE); + bool enabled = pg->regs[NV_PGRAPH_TEXCTL0_0 + i*4] + & NV_PGRAPH_TEXCTL0_0_ENABLE; unsigned int color_format = GET_MASK(pg->regs[NV_PGRAPH_TEXFMT0 + i*4], NV_PGRAPH_TEXFMT0_COLOR); @@ -2881,7 +2881,6 @@ static void pgraph_bind_shaders(PGRAPHState *pg) constant[1] = pg->regs[NV_PGRAPH_COMBINEFACTOR1 + i * 4]; } - int j; for (j = 0; j < 2; j++) { GLint loc = pg->shader_binding->psh_constant_loc[i][j]; if (loc != -1) { @@ -2919,8 +2918,9 @@ static void pgraph_bind_shaders(PGRAPHState *pg) GLint comLoc = glGetUniformLocation(pg->shader_binding->gl_program, "composite"); - assert(comLoc != -1); - glUniformMatrix4fv(comLoc, 1, GL_FALSE, pg->composite_matrix); + if (comLoc != -1) { + glUniformMatrix4fv(comLoc, 1, GL_FALSE, pg->composite_matrix); + } /* estimate the viewport by assuming it matches the surface ... */ float m11 = 0.5 * pg->surface_shape.clip_width; @@ -2931,7 +2931,6 @@ static void pgraph_bind_shaders(PGRAPHState *pg) float m43 = zclip_min; //float m44 = 1.0; - if (m33 == 0.0) { m33 = 1.0; } @@ -2944,8 +2943,9 @@ static void pgraph_bind_shaders(PGRAPHState *pg) GLint view_loc = glGetUniformLocation(pg->shader_binding->gl_program, "invViewport"); - assert(view_loc != -1); - glUniformMatrix4fv(view_loc, 1, GL_FALSE, &invViewport[0]); + if (view_loc != -1) { + glUniformMatrix4fv(view_loc, 1, GL_FALSE, &invViewport[0]); + } } else if (vertex_program) { /* update vertex program constants */ @@ -4748,9 +4748,11 @@ static void pgraph_method(NV2AState *d, case NV097_SET_TRANSFORM_EXECUTION_MODE: SET_MASK(pg->regs[NV_PGRAPH_CSV0_D], NV_PGRAPH_CSV0_D_MODE, - GET_MASK(parameter, NV_097_SET_TRANSFORM_EXECUTION_MODE_MODE)); + GET_MASK(parameter, + NV097_SET_TRANSFORM_EXECUTION_MODE_MODE)); SET_MASK(pg->regs[NV_PGRAPH_CSV0_D], NV_PGRAPH_CSV0_D_RANGE_MODE, - GET_MASK(parameter, NV_097_SET_TRANSFORM_EXECUTION_MODE_RANGE_MODE)); + GET_MASK(parameter, + NV097_SET_TRANSFORM_EXECUTION_MODE_RANGE_MODE)); break; case NV097_SET_TRANSFORM_PROGRAM_CXT_WRITE_EN: pg->enable_vertex_program_write = parameter; diff --git a/hw/xbox/nv2a_vsh.h b/hw/xbox/nv2a_vsh.h index 3e2aa9c87a..ff0849d514 100644 --- a/hw/xbox/nv2a_vsh.h +++ b/hw/xbox/nv2a_vsh.h @@ -90,4 +90,4 @@ QString* vsh_translate(uint16_t version, char output_prefix); -#endif \ No newline at end of file +#endif From f8933e372492f8211c911536e51b21900a6c9522 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 16 Jul 2015 10:53:16 +0200 Subject: [PATCH 06/25] Texgen registers --- hw/xbox/nv2a.c | 132 ++++++++++++++++++++++++++++++++++++++++++++- hw/xbox/nv2a_vsh.h | 9 ++++ 2 files changed, 140 insertions(+), 1 deletion(-) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index d3edf4f4a0..ae024aedf5 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -337,12 +337,45 @@ static void gl_debug_label(GLenum target, GLuint name, const char *fmt, ...) # define NV_PGRAPH_CHANNEL_CTX_TRIGGER_READ_IN (1 << 0) # define NV_PGRAPH_CHANNEL_CTX_TRIGGER_WRITE_OUT (1 << 1) #define NV_PGRAPH_CSV0_D 0x00000FB4 -# define NV_PGRAPH_CSV0_D_MODE 0xC0000000 # define NV_PGRAPH_CSV0_D_RANGE_MODE (1 << 18) +# define NV_PGRAPH_CSV0_D_TEXGEN_REF (1 << 20) +# define NV_PGRAPH_CSV0_D_TEXGEN_REF_LOCAL_VIEWER 0 +# define NV_PGRAPH_CSV0_D_TEXGEN_REF_INFINITE_VIEWER 1 +# define NV_PGRAPH_CSV0_D_MODE 0xC0000000 +# define NV_PGRAPH_CSV0_D_SKIN 0x1C000000 +# define NV_PGRAPH_CSV0_D_SKIN_OFF 0 +# define NV_PGRAPH_CSV0_D_SKIN_2G 1 +# define NV_PGRAPH_CSV0_D_SKIN_2 2 +# define NV_PGRAPH_CSV0_D_SKIN_3G 3 +# define NV_PGRAPH_CSV0_D_SKIN_3 4 +# define NV_PGRAPH_CSV0_D_SKIN_4G 5 +# define NV_PGRAPH_CSV0_D_SKIN_4 6 #define NV_PGRAPH_CSV0_C 0x00000FB8 # define NV_PGRAPH_CSV0_C_CHEOPS_PROGRAM_START 0x0000FF00 #define NV_PGRAPH_CSV1_B 0x00000FBC #define NV_PGRAPH_CSV1_A 0x00000FC0 +# define NV_PGRAPH_CSV1_A_T0_ENABLE (1 << 0) +# define NV_PGRAPH_CSV1_A_T0_MODE (1 << 1) +# define NV_PGRAPH_CSV1_A_T0_TEXTURE (1 << 2) +# define NV_PGRAPH_CSV1_A_T0_TEXTURE_2D 0 +# define NV_PGRAPH_CSV1_A_T0_TEXTURE_3D 1 +# define NV_PGRAPH_CSV1_A_T0_S 0x00000070 +# define NV_PGRAPH_CSV1_A_T0_S_DISABLE 0 +# define NV_PGRAPH_CSV1_A_T0_S_NORMAL_MAP 4 +# define NV_PGRAPH_CSV1_A_T0_S_REFLECTION_MAP 5 +# define NV_PGRAPH_CSV1_A_T0_S_EYE_LINEAR 1 +# define NV_PGRAPH_CSV1_A_T0_S_OBJECT_LINEAR 2 +# define NV_PGRAPH_CSV1_A_T0_S_SPHERE_MAP 3 +# define NV_PGRAPH_CSV1_A_T0_T 0x00000380 +# define NV_PGRAPH_CSV1_A_T0_R 0x00001C00 +# define NV_PGRAPH_CSV1_A_T0_Q 0x0000E000 +# define NV_PGRAPH_CSV1_A_T1_ENABLE (1 << 16) +# define NV_PGRAPH_CSV1_A_T1_MODE (1 << 17) +# define NV_PGRAPH_CSV1_A_T1_TEXTURE (1 << 18) +# define NV_PGRAPH_CSV1_A_T1_S 0x00700000 +# define NV_PGRAPH_CSV1_A_T1_T 0x03800000 +# define NV_PGRAPH_CSV1_A_T1_R 0x1C000000 +# define NV_PGRAPH_CSV1_A_T1_Q 0xE0000000 #define NV_PGRAPH_CHEOPS_OFFSET 0x00000FC4 # define NV_PGRAPH_CHEOPS_OFFSET_PROG_LD_PTR 0x000000FF # define NV_PGRAPH_CHEOPS_OFFSET_CONST_LD_PTR 0x0000FF00 @@ -807,7 +840,20 @@ static void gl_debug_label(GLenum target, GLuint name, const char *fmt, ...) # define NV097_SET_STENCIL_OP_V_DECR 0x8508 # define NV097_SET_CLIP_MIN 0x00970394 # define NV097_SET_CLIP_MAX 0x00970398 +# define NV097_SET_TEXGEN_S 0x009703C0 +# define NV097_SET_TEXGEN_S_DISABLE 0x0000 +# define NV097_SET_TEXGEN_S_EYE_LINEAR 0x2400 +# define NV097_SET_TEXGEN_S_OBJECT_LINEAR 0x2401 +# define NV097_SET_TEXGEN_S_SPHERE_MAP 0x2402 +# define NV097_SET_TEXGEN_S_REFLECTION_MAP 0x8512 +# define NV097_SET_TEXGEN_S_NORMAL_MAP 0x8511 +# define NV097_SET_TEXGEN_T 0x009703C4 +# define NV097_SET_TEXGEN_R 0x009703C8 +# define NV097_SET_TEXGEN_Q 0x009703CC # define NV097_SET_COMPOSITE_MATRIX 0x00970680 +# define NV097_SET_TEXGEN_VIEW_MODEL 0x009709CC +# define NV097_SET_TEXGEN_VIEW_MODEL_LOCAL_VIEWER 0 +# define NV097_SET_TEXGEN_VIEW_MODEL_INFINITE_VIEWER 1 # define NV097_SET_VIEWPORT_OFFSET 0x00970A20 # define NV097_SET_COMBINER_FACTOR0 0x00970A60 # define NV097_SET_COMBINER_FACTOR1 0x00970A80 @@ -1266,6 +1312,7 @@ typedef struct ShaderState { bool alpha_test; enum AlphaFunc alpha_func; + enum Texgen texgen[4][4]; bool fixed_function; @@ -2820,6 +2867,20 @@ static void pgraph_bind_shaders(PGRAPHState *pg) } } + /* Texgen */ + for (i = 0; i < 4; i++) { + unsigned int reg = (i < 2) ? NV_PGRAPH_CSV1_A : NV_PGRAPH_CSV1_B; + for (j = 0; j < 4; j++) { + unsigned int masks[] = { + (i % 2) ? NV_PGRAPH_CSV1_A_T1_S : NV_PGRAPH_CSV1_A_T0_S, + (i % 2) ? NV_PGRAPH_CSV1_A_T1_T : NV_PGRAPH_CSV1_A_T0_T, + (i % 2) ? NV_PGRAPH_CSV1_A_T1_R : NV_PGRAPH_CSV1_A_T0_R, + (i % 2) ? NV_PGRAPH_CSV1_A_T1_Q : NV_PGRAPH_CSV1_A_T0_Q + }; + state.texgen[i][j] = GET_MASK(pg->regs[reg], masks[j]); + } + } + for (i = 0; i < 8; i++) { state.rgb_inputs[i] = pg->regs[NV_PGRAPH_COMBINECOLORI0 + i * 4]; state.rgb_outputs[i] = pg->regs[NV_PGRAPH_COMBINECOLORO0 + i * 4]; @@ -3520,6 +3581,33 @@ static unsigned int kelvin_map_stencil_op(uint32_t parameter) return op; } +static unsigned int kelvin_map_texgen(uint32_t parameter, unsigned int channel) +{ + assert(channel < 4); + unsigned int texgen; + switch (parameter) { + case NV097_SET_TEXGEN_S_DISABLE: + texgen = NV_PGRAPH_CSV1_A_T0_S_DISABLE; break; + case NV097_SET_TEXGEN_S_EYE_LINEAR: + texgen = NV_PGRAPH_CSV1_A_T0_S_EYE_LINEAR; break; + case NV097_SET_TEXGEN_S_OBJECT_LINEAR: + texgen = NV_PGRAPH_CSV1_A_T0_S_OBJECT_LINEAR; break; + case NV097_SET_TEXGEN_S_SPHERE_MAP: + assert(channel < 2); + texgen = NV_PGRAPH_CSV1_A_T0_S_SPHERE_MAP; break; + case NV097_SET_TEXGEN_S_REFLECTION_MAP: + assert(channel < 3); + texgen = NV_PGRAPH_CSV1_A_T0_S_REFLECTION_MAP; break; + case NV097_SET_TEXGEN_S_NORMAL_MAP: + assert(channel < 3); + texgen = NV_PGRAPH_CSV1_A_T0_S_NORMAL_MAP; break; + default: + assert(false); + break; + } + return texgen; +} + static void pgraph_method(NV2AState *d, unsigned int subchannel, unsigned int method, @@ -4057,12 +4145,54 @@ static void pgraph_method(NV2AState *d, pg->regs[NV_PGRAPH_ZCLIPMAX] = parameter; break; + CASE_4(NV097_SET_TEXGEN_S, 16): { + slot = (class_method - NV097_SET_TEXGEN_S) / 16; + unsigned int reg = (slot < 2) ? NV_PGRAPH_CSV1_A + : NV_PGRAPH_CSV1_B; + unsigned int mask = (slot % 2) ? NV_PGRAPH_CSV1_A_T1_S + : NV_PGRAPH_CSV1_A_T0_S; + SET_MASK(pg->regs[reg], mask, kelvin_map_texgen(parameter, 0)); + break; + } + CASE_4(NV097_SET_TEXGEN_T, 16): { + slot = (class_method - NV097_SET_TEXGEN_T) / 16; + unsigned int reg = (slot < 2) ? NV_PGRAPH_CSV1_A + : NV_PGRAPH_CSV1_B; + unsigned int mask = (slot % 2) ? NV_PGRAPH_CSV1_A_T1_T + : NV_PGRAPH_CSV1_A_T0_T; + SET_MASK(pg->regs[reg], mask, kelvin_map_texgen(parameter, 1)); + break; + } + CASE_4(NV097_SET_TEXGEN_R, 16): { + slot = (class_method - NV097_SET_TEXGEN_R) / 16; + unsigned int reg = (slot < 2) ? NV_PGRAPH_CSV1_A + : NV_PGRAPH_CSV1_B; + unsigned int mask = (slot % 2) ? NV_PGRAPH_CSV1_A_T1_R + : NV_PGRAPH_CSV1_A_T0_R; + SET_MASK(pg->regs[reg], mask, kelvin_map_texgen(parameter, 2)); + break; + } + CASE_4(NV097_SET_TEXGEN_Q, 16): { + slot = (class_method - NV097_SET_TEXGEN_Q) / 16; + unsigned int reg = (slot < 2) ? NV_PGRAPH_CSV1_A + : NV_PGRAPH_CSV1_B; + unsigned int mask = (slot % 2) ? NV_PGRAPH_CSV1_A_T1_Q + : NV_PGRAPH_CSV1_A_T0_Q; + SET_MASK(pg->regs[reg], mask, kelvin_map_texgen(parameter, 3)); + break; + } + case NV097_SET_COMPOSITE_MATRIX ... NV097_SET_COMPOSITE_MATRIX + 0x3c: slot = (class_method - NV097_SET_COMPOSITE_MATRIX) / 4; pg->composite_matrix[slot] = *(float*)¶meter; break; + case NV097_SET_TEXGEN_VIEW_MODEL: + SET_MASK(pg->regs[NV_PGRAPH_CSV0_D], NV_PGRAPH_CSV0_D_TEXGEN_REF, + parameter); + break; + case NV097_SET_VIEWPORT_OFFSET ... NV097_SET_VIEWPORT_OFFSET + 12: diff --git a/hw/xbox/nv2a_vsh.h b/hw/xbox/nv2a_vsh.h index ff0849d514..b64ff11536 100644 --- a/hw/xbox/nv2a_vsh.h +++ b/hw/xbox/nv2a_vsh.h @@ -24,6 +24,15 @@ #include "qapi/qmp/qstring.h" +enum Texgen { + TEXGEN_DISABLE, + TEXGEN_EYE_LINEAR, + TEXGEN_OBJECT_LINEAR, + TEXGEN_SPHERE_MAP, + TEXGEN_NORMAL_MAP, + TEXGEN_REFLECTION_MAP, +}; + // vs.1.1, not an official value #define VSH_VERSION_VS 0xF078 From 53a6b628c9a9581796092d7c642c35d7993cb2e7 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 16 Jul 2015 10:56:38 +0200 Subject: [PATCH 07/25] Normalization registers --- hw/xbox/nv2a.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index ae024aedf5..d02eb61172 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -352,6 +352,7 @@ static void gl_debug_label(GLenum target, GLuint name, const char *fmt, ...) # define NV_PGRAPH_CSV0_D_SKIN_4 6 #define NV_PGRAPH_CSV0_C 0x00000FB8 # define NV_PGRAPH_CSV0_C_CHEOPS_PROGRAM_START 0x0000FF00 +# define NV_PGRAPH_CSV0_C_NORMALIZATION_ENABLE (1 << 27) #define NV_PGRAPH_CSV1_B 0x00000FBC #define NV_PGRAPH_CSV1_A 0x00000FC0 # define NV_PGRAPH_CSV1_A_T0_ENABLE (1 << 0) @@ -840,6 +841,7 @@ static void gl_debug_label(GLenum target, GLuint name, const char *fmt, ...) # define NV097_SET_STENCIL_OP_V_DECR 0x8508 # define NV097_SET_CLIP_MIN 0x00970394 # define NV097_SET_CLIP_MAX 0x00970398 +# define NV097_SET_NORMALIZATION_ENABLE 0x009703A4 # define NV097_SET_TEXGEN_S 0x009703C0 # define NV097_SET_TEXGEN_S_DISABLE 0x0000 # define NV097_SET_TEXGEN_S_EYE_LINEAR 0x2400 @@ -1314,6 +1316,8 @@ typedef struct ShaderState { enum Texgen texgen[4][4]; + bool normalization; + bool fixed_function; /* vertex program */ @@ -2839,6 +2843,9 @@ static void pgraph_bind_shaders(PGRAPHState *pg) .alpha_func = GET_MASK(pg->regs[NV_PGRAPH_CONTROL_0], NV_PGRAPH_CONTROL_0_ALPHAFUNC), + .normalization = pg->regs[NV_PGRAPH_CSV0_C] + & NV_PGRAPH_CSV0_C_NORMALIZATION_ENABLE, + /* fixed function stuff */ .fixed_function = fixed_function, @@ -4145,6 +4152,12 @@ static void pgraph_method(NV2AState *d, pg->regs[NV_PGRAPH_ZCLIPMAX] = parameter; break; + case NV097_SET_NORMALIZATION_ENABLE: + SET_MASK(pg->regs[NV_PGRAPH_CSV0_C], + NV_PGRAPH_CSV0_C_NORMALIZATION_ENABLE, + parameter); + break; + CASE_4(NV097_SET_TEXGEN_S, 16): { slot = (class_method - NV097_SET_TEXGEN_S) / 16; unsigned int reg = (slot < 2) ? NV_PGRAPH_CSV1_A From 20e0ac58a998921e35889298b400f5f2ef1b16a7 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 16 Jul 2015 11:03:39 +0200 Subject: [PATCH 08/25] Bumpmapping Lum registers, better var name and fix for Bumpmapping --- hw/xbox/nv2a.c | 67 +++++++++++++++++++++++++++++++++++++++------- hw/xbox/nv2a_psh.c | 25 +++++++++-------- 2 files changed, 71 insertions(+), 21 deletions(-) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index d02eb61172..6550185512 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -418,6 +418,8 @@ static void gl_debug_label(GLenum target, GLuint name, const char *fmt, ...) # define NV_PGRAPH_BLEND_LOGICOP_ENABLE (1 << 16) # define NV_PGRAPH_BLEND_LOGICOP 0x0000F000 #define NV_PGRAPH_BLENDCOLOR 0x00001808 +#define NV_PGRAPH_BUMPOFFSET1 0x0000184C +#define NV_PGRAPH_BUMPSCALE1 0x00001858 #define NV_PGRAPH_CLEARRECTX 0x00001864 # define NV_PGRAPH_CLEARRECTX_XMIN 0x00000FFF # define NV_PGRAPH_CLEARRECTX_XMAX 0x0FFF0000 @@ -954,6 +956,8 @@ static void gl_debug_label(GLenum target, GLuint name, const char *fmt, ...) # define NV097_SET_TEXTURE_PALETTE_LENGTH_32 3 # define NV097_SET_TEXTURE_PALETTE_OFFSET 0xFFFFFFC0 # define NV097_SET_TEXTURE_SET_BUMP_ENV_MAT 0x00971B28 +# define NV097_SET_TEXTURE_SET_BUMP_ENV_SCALE 0x00971B38 +# define NV097_SET_TEXTURE_SET_BUMP_ENV_OFFSET 0x00971B3C # define NV097_SET_SEMAPHORE_OFFSET 0x00971D6C # define NV097_BACK_END_WRITE_SEMAPHORE_RELEASE 0x00971D70 # define NV097_SET_ZSTENCIL_CLEAR_VALUE 0x00971D8C @@ -1470,7 +1474,9 @@ typedef struct PGRAPHState { ShaderBinding *shader_binding; float composite_matrix[16]; - float texture_bump_matrix[4]; + + /* FIXME: Move to NV_PGRAPH_BUMPMAT... */ + float bump_env_matrix[3][4]; /* 4 stages with 2x2 matrix each */ GloContext *gl_context; GLuint gl_framebuffer; @@ -2970,12 +2976,36 @@ static void pgraph_bind_shaders(PGRAPHState *pg) glUniform1f(alpha_ref_loc, alpha_ref); } - GLint tex_bump_mat_loc = glGetUniformLocation( - pg->shader_binding->gl_program, - "texBumpMat"); - if (tex_bump_mat_loc != -1) { - glUniformMatrix2fv(tex_bump_mat_loc, 1, GL_FALSE, - pg->texture_bump_matrix); + /* For each texture stage */ + for (i = 0; i < 4; i++) { + char name[16]; + GLint loc; + + /* Bump luminance only during stages 1 - 3 */ + if (i > 0) { + + sprintf(name, "bumpMat%d", i); + loc = glGetUniformLocation(pg->shader_binding->gl_program, name); + if (loc != -1) { + glUniformMatrix2fv(loc, 1, GL_FALSE, pg->bump_env_matrix[i - 1]); + } + + sprintf(name, "bumpScale%d", i); + loc = glGetUniformLocation(pg->shader_binding->gl_program, name); + if (loc != -1) { + glUniform1fv(loc, 1, + &pg->regs[NV_PGRAPH_BUMPSCALE1 + (i - 1) * 4]); + } + + sprintf(name, "bumpOffset%d", i); + loc = glGetUniformLocation(pg->shader_binding->gl_program, name); + if (loc != -1) { + glUniform1fv(loc, 1, + &pg->regs[NV_PGRAPH_BUMPOFFSET1 + (i - 1) * 4]); + } + + } + } float zclip_max = *(float*)&pg->regs[NV_PGRAPH_ZCLIPMAX]; @@ -4677,10 +4707,27 @@ static void pgraph_method(NV2AState *d, break; } - case NV097_SET_TEXTURE_SET_BUMP_ENV_MAT ... - NV097_SET_TEXTURE_SET_BUMP_ENV_MAT + 0xc: + CASE_4(NV097_SET_TEXTURE_SET_BUMP_ENV_MAT + 0x0, 64): + CASE_4(NV097_SET_TEXTURE_SET_BUMP_ENV_MAT + 0x4, 64): + CASE_4(NV097_SET_TEXTURE_SET_BUMP_ENV_MAT + 0x8, 64): + CASE_4(NV097_SET_TEXTURE_SET_BUMP_ENV_MAT + 0xc, 64): slot = (class_method - NV097_SET_TEXTURE_SET_BUMP_ENV_MAT) / 4; - pg->texture_bump_matrix[slot] = *(float*)¶meter; + assert((slot / 16) > 0); + slot -= 16; + pg->bump_env_matrix[slot / 16][slot % 4] = *(float*)¶meter; + break; + + CASE_4(NV097_SET_TEXTURE_SET_BUMP_ENV_SCALE, 64): + slot = (class_method - NV097_SET_TEXTURE_SET_BUMP_ENV_SCALE) / 64; + assert(slot > 0); + slot--; + pg->regs[NV_PGRAPH_BUMPSCALE1 + slot * 4] = parameter; + break; + CASE_4(NV097_SET_TEXTURE_SET_BUMP_ENV_OFFSET, 64): + slot = (class_method - NV097_SET_TEXTURE_SET_BUMP_ENV_OFFSET) / 64; + assert(slot > 0); + slot--; + pg->regs[NV_PGRAPH_BUMPOFFSET1 + slot * 4] = parameter; break; case NV097_ARRAY_ELEMENT16: diff --git a/hw/xbox/nv2a_psh.c b/hw/xbox/nv2a_psh.c index 6f83819344..c90a5a66af 100644 --- a/hw/xbox/nv2a_psh.c +++ b/hw/xbox/nv2a_psh.c @@ -564,7 +564,8 @@ static QString* psh_convert(struct PixelShader *ps) qstring_append(vars, "vec4 v1 = pD1;\n"); qstring_append(vars, "float fog = pFog.x;\n"); - bool bumpenvmap = false; + ps->code = qstring_new(); + for (i = 0; i < 4; i++) { const char *sampler_type = NULL; @@ -608,13 +609,20 @@ static QString* psh_convert(struct PixelShader *ps) qstring_append_fmt(vars, " vec4 t%d = texture(texSamp%d, t%d.gb);\n", i, i, ps->input_tex[i]); break; + case PS_TEXTUREMODES_BUMPENVMAP_LUM: + qstring_append_fmt(preflight, "uniform float bumpScale%d;\n", i); + qstring_append_fmt(preflight, "uniform float bumpOffset%d;\n", i); + qstring_append_fmt(ps->code, "/* BUMPENVMAP_LUM for stage %d */\n", i); + qstring_append_fmt(ps->code, "t%d = t%d * (bumpScale%d * t%d.b + bumpOffset%d);\n", + i, i, i, ps->input_tex[i], i); + /* No break here! Extension of BUMPENVMAP */ case PS_TEXTUREMODES_BUMPENVMAP: assert(!ps->rect_tex[i]); sampler_type = "sampler2D"; - bumpenvmap = true; - assert(false); /* FIXME: Untested */ - qstring_append_fmt(vars, " vec4 t%d = texture(texSamp%d, pT%d.xy + t%d.rg * texBumpMat%d);\n", - i, i, i, ps->input_tex[i], i); + qstring_append_fmt(preflight, "uniform mat2 bumpMat%d;\n", i); + /* FIXME: Do bumpMat swizzle on CPU before upload */ + qstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, pT%d.xy + t%d.rg * mat2(bumpMat%d[0].xy,bumpMat%d[1].yx));\n", + i, i, i, ps->input_tex[i], i, i); break; case PS_TEXTUREMODES_CLIPPLANE: { int j; @@ -644,17 +652,12 @@ static QString* psh_convert(struct PixelShader *ps) /* As this means a texture fetch does happen, do alphakill */ if (ps->alphakill[i]) { assert(false); /* FIXME: Untested */ - qstring_append_fmt(vars, " if (t%d.a == 0.0) { discard; };\n", + qstring_append_fmt(vars, "if (t%d.a == 0.0) { discard; };\n", i); } } } - if (bumpenvmap) { - qstring_append(preflight, " uniform mat2 texBumpMat\n"); - } - - ps->code = qstring_new(); for (i = 0; i < ps->num_stages; i++) { ps->cur_stage = i; qstring_append_fmt(ps->code, "// Stage %d\n", i); From add2a25a925e0a57bb7a0353f82834102ef74d2c Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 16 Jul 2015 11:07:49 +0200 Subject: [PATCH 09/25] Add TEXTURE_FILTER_?SIGNED assert, functionality not yet known (maybe delta tex?) --- hw/xbox/nv2a.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index 6550185512..fd773d87d5 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -531,6 +531,10 @@ static void gl_debug_label(GLenum target, GLuint name, const char *fmt, ...) # define NV_PGRAPH_TEXFILTER0_MIN_TENT_TENT_LOD 6 # define NV_PGRAPH_TEXFILTER0_MIN_CONVOLUTION_2D_LOD0 7 # define NV_PGRAPH_TEXFILTER0_MAG 0x0F000000 +# define NV_PGRAPH_TEXFILTER0_ASIGNED (1 << 28) +# define NV_PGRAPH_TEXFILTER0_RSIGNED (1 << 29) +# define NV_PGRAPH_TEXFILTER0_GSIGNED (1 << 30) +# define NV_PGRAPH_TEXFILTER0_BSIGNED (1 << 31) #define NV_PGRAPH_TEXFILTER1 0x000019F8 #define NV_PGRAPH_TEXFILTER2 0x000019FC #define NV_PGRAPH_TEXFILTER3 0x00001A00 @@ -944,6 +948,10 @@ static void gl_debug_label(GLenum target, GLuint name, const char *fmt, ...) # define NV097_SET_TEXTURE_FILTER_MIPMAP_LOD_BIAS 0x00001FFF # define NV097_SET_TEXTURE_FILTER_MIN 0x00FF0000 # define NV097_SET_TEXTURE_FILTER_MAG 0x0F000000 +# define NV097_SET_TEXTURE_FILTER_ASIGNED (1 << 28) +# define NV097_SET_TEXTURE_FILTER_RSIGNED (1 << 29) +# define NV097_SET_TEXTURE_FILTER_GSIGNED (1 << 30) +# define NV097_SET_TEXTURE_FILTER_BSIGNED (1 << 31) # define NV097_SET_TEXTURE_IMAGE_RECT 0x00971B1C # define NV097_SET_TEXTURE_IMAGE_RECT_WIDTH 0xFFFF0000 # define NV097_SET_TEXTURE_IMAGE_RECT_HEIGHT 0x0000FFFF @@ -2313,6 +2321,11 @@ static void pgraph_bind_textures(NV2AState *d) default: assert(false); break; } + /* Check for unsupported features */ + assert(!(filter & NV_PGRAPH_TEXFILTER0_ASIGNED)); + assert(!(filter & NV_PGRAPH_TEXFILTER0_RSIGNED)); + assert(!(filter & NV_PGRAPH_TEXFILTER0_GSIGNED)); + assert(!(filter & NV_PGRAPH_TEXFILTER0_BSIGNED)); if (dimensionality != 2) continue; glActiveTexture(GL_TEXTURE0 + i); From bb232fb08211a0a7ec62395192a6bc0a3d70c1fa Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 16 Jul 2015 11:09:38 +0200 Subject: [PATCH 10/25] Skinning registers --- hw/xbox/nv2a.c | 17 +++++++++++++++++ hw/xbox/nv2a_vsh.h | 10 ++++++++++ 2 files changed, 27 insertions(+) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index fd773d87d5..58f20aa3bc 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -779,6 +779,14 @@ static void gl_debug_label(GLenum target, GLuint name, const char *fmt, ...) # define NV097_SET_ALPHA_TEST_ENABLE 0x00970300 # define NV097_SET_BLEND_ENABLE 0x00970304 # define NV097_SET_DEPTH_TEST_ENABLE 0x0097030C +# define NV097_SET_SKIN_MODE 0x00970328 +# define NV097_SET_SKIN_MODE_OFF 0 +# define NV097_SET_SKIN_MODE_2G 1 +# define NV097_SET_SKIN_MODE_2 2 +# define NV097_SET_SKIN_MODE_3G 3 +# define NV097_SET_SKIN_MODE_3 4 +# define NV097_SET_SKIN_MODE_4G 5 +# define NV097_SET_SKIN_MODE_4 6 # define NV097_SET_STENCIL_TEST_ENABLE 0x0097032C # define NV097_SET_ALPHA_FUNC 0x0097033C # define NV097_SET_ALPHA_REF 0x00970340 @@ -1328,6 +1336,8 @@ typedef struct ShaderState { enum Texgen texgen[4][4]; + enum Skinning skinning; + bool normalization; bool fixed_function; @@ -2862,6 +2872,9 @@ static void pgraph_bind_shaders(PGRAPHState *pg) .alpha_func = GET_MASK(pg->regs[NV_PGRAPH_CONTROL_0], NV_PGRAPH_CONTROL_0_ALPHAFUNC), + .skinning = GET_MASK(pg->regs[NV_PGRAPH_CSV0_D], + NV_PGRAPH_CSV0_D_SKIN), + .normalization = pg->regs[NV_PGRAPH_CSV0_C] & NV_PGRAPH_CSV0_C_NORMALIZATION_ENABLE, @@ -4006,6 +4019,10 @@ static void pgraph_method(NV2AState *d, SET_MASK(pg->regs[NV_PGRAPH_CONTROL_0], NV_PGRAPH_CONTROL_0_ZENABLE, parameter); break; + case NV097_SET_SKIN_MODE: + SET_MASK(pg->regs[NV_PGRAPH_CSV0_D], NV_PGRAPH_CSV0_D_SKIN, + parameter); + break; case NV097_SET_STENCIL_TEST_ENABLE: SET_MASK(pg->regs[NV_PGRAPH_CONTROL_1], NV_PGRAPH_CONTROL_1_STENCIL_TEST_ENABLE, parameter); diff --git a/hw/xbox/nv2a_vsh.h b/hw/xbox/nv2a_vsh.h index b64ff11536..c41069ee30 100644 --- a/hw/xbox/nv2a_vsh.h +++ b/hw/xbox/nv2a_vsh.h @@ -33,6 +33,16 @@ enum Texgen { TEXGEN_REFLECTION_MAP, }; +enum Skinning { + SKINNING_OFF, + SKINNING_1WEIGHTS, + SKINNING_2WEIGHTS, + SKINNING_3WEIGHTS, + SKINNING_2WEIGHTS2MATRICES, + SKINNING_3WEIGHTS3MATRICES, + SKINNING_4WEIGHTS4MATRICES, +}; + // vs.1.1, not an official value #define VSH_VERSION_VS 0xF078 From cc89da0c20d4851c252bb88fcffcecca0decbbc5 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 16 Jul 2015 11:19:44 +0200 Subject: [PATCH 11/25] Store Matrices (4x MV, 4x iMV, Proj) --- hw/xbox/nv2a.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index 58f20aa3bc..40d5d44219 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -866,6 +866,9 @@ static void gl_debug_label(GLenum target, GLuint name, const char *fmt, ...) # define NV097_SET_TEXGEN_T 0x009703C4 # define NV097_SET_TEXGEN_R 0x009703C8 # define NV097_SET_TEXGEN_Q 0x009703CC +# define NV097_SET_PROJECTION_MATRIX 0x00970440 +# define NV097_SET_MODEL_VIEW_MATRIX 0x00970480 +# define NV097_SET_INVERSE_MODEL_VIEW_MATRIX 0x00970580 # define NV097_SET_COMPOSITE_MATRIX 0x00970680 # define NV097_SET_TEXGEN_VIEW_MODEL 0x009709CC # define NV097_SET_TEXGEN_VIEW_MODEL_LOCAL_VIEWER 0 @@ -1493,6 +1496,11 @@ typedef struct PGRAPHState { float composite_matrix[16]; + /* FIXME: These are probably stored in the vshader consts */ + float projection_matrix[16]; + float inverse_model_view_matrix[4][16]; /* 4 weights with 4x4 matrix each */ + float model_view_matrix[4][16]; /* 4 weights with 4x4 matrix each */ + /* FIXME: Move to NV_PGRAPH_BUMPMAT... */ float bump_env_matrix[3][4]; /* 4 stages with 2x2 matrix each */ @@ -2630,6 +2638,15 @@ static ShaderBinding* generate_shaders(const ShaderState state) qstring_append(vertex_shader_code, "\n" "uniform mat4 composite;\n" +"uniform mat4 modelViewMat0;\n" +"uniform mat4 modelViewMat1;\n" +"uniform mat4 modelViewMat2;\n" +"uniform mat4 modelViewMat3;\n" +"uniform mat4 invModelViewMat0;\n" +"uniform mat4 invModelViewMat1;\n" +"uniform mat4 invModelViewMat2;\n" +"uniform mat4 invModelViewMat3;\n" +"uniform mat4 projectionMat;\n" "uniform mat4 invViewport;\n" "void main() {\n" " gl_Position = invViewport * (position * composite);\n" @@ -3034,6 +3051,33 @@ static void pgraph_bind_shaders(PGRAPHState *pg) } + /* For each vertex weight */ + for (i = 0; i < 4; i++) { + char name[16]; + GLint loc; + + sprintf(name, "modelViewMat%d", i); + loc = glGetUniformLocation(pg->shader_binding->gl_program, name); + if (loc != -1) { + glUniformMatrix4fv(loc, 1, GL_FALSE, + pg->model_view_matrix[i]); + } + + sprintf(name, "invModelViewMat%d", i); + loc = glGetUniformLocation(pg->shader_binding->gl_program, name); + if (loc != -1) { + glUniformMatrix4fv(loc, 1, GL_FALSE, + pg->inverse_model_view_matrix[i]); + } + + } + + GLint projLoc = glGetUniformLocation(pg->shader_binding->gl_program, + "projectionMat"); + if (projLoc != -1) { + glUniformMatrix4fv(projLoc, 1, GL_FALSE, pg->projection_matrix); + } + float zclip_max = *(float*)&pg->regs[NV_PGRAPH_ZCLIPMAX]; float zclip_min = *(float*)&pg->regs[NV_PGRAPH_ZCLIPMIN]; @@ -4255,6 +4299,24 @@ static void pgraph_method(NV2AState *d, break; } + case NV097_SET_PROJECTION_MATRIX ... + NV097_SET_PROJECTION_MATRIX + 0x3c: + slot = (class_method - NV097_SET_PROJECTION_MATRIX) / 4; + pg->projection_matrix[slot] = *(float*)¶meter; + break; + + case NV097_SET_MODEL_VIEW_MATRIX ... + NV097_SET_MODEL_VIEW_MATRIX + 0xfc: + slot = (class_method - NV097_SET_MODEL_VIEW_MATRIX) / 4; + pg->model_view_matrix[slot / 16][slot % 16] = *(float*)¶meter; + break; + + case NV097_SET_INVERSE_MODEL_VIEW_MATRIX ... + NV097_SET_INVERSE_MODEL_VIEW_MATRIX + 0xfc: + slot = (class_method - NV097_SET_INVERSE_MODEL_VIEW_MATRIX) / 4; + pg->inverse_model_view_matrix[slot / 16][slot % 16] = *(float*)¶meter; + break; + case NV097_SET_COMPOSITE_MATRIX ... NV097_SET_COMPOSITE_MATRIX + 0x3c: slot = (class_method - NV097_SET_COMPOSITE_MATRIX) / 4; From 9ea1c53c8e7d8a00a576a770f6e2244c6763b1cf Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 16 Jul 2015 11:20:52 +0200 Subject: [PATCH 12/25] Texture matrix registers --- hw/xbox/nv2a.c | 31 +++++++++++++++++++++++++++++++ hw/xbox/nv2a_vsh.c | 5 +++++ 2 files changed, 36 insertions(+) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index 40d5d44219..ee8badba69 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -866,10 +866,12 @@ static void gl_debug_label(GLenum target, GLuint name, const char *fmt, ...) # define NV097_SET_TEXGEN_T 0x009703C4 # define NV097_SET_TEXGEN_R 0x009703C8 # define NV097_SET_TEXGEN_Q 0x009703CC +# define NV097_SET_TEXTURE_MATRIX_ENABLE 0x00970420 # define NV097_SET_PROJECTION_MATRIX 0x00970440 # define NV097_SET_MODEL_VIEW_MATRIX 0x00970480 # define NV097_SET_INVERSE_MODEL_VIEW_MATRIX 0x00970580 # define NV097_SET_COMPOSITE_MATRIX 0x00970680 +# define NV097_SET_TEXTURE_MATRIX 0x009706C0 # define NV097_SET_TEXGEN_VIEW_MODEL 0x009709CC # define NV097_SET_TEXGEN_VIEW_MODEL_LOCAL_VIEWER 0 # define NV097_SET_TEXGEN_VIEW_MODEL_INFINITE_VIEWER 1 @@ -1337,6 +1339,7 @@ typedef struct ShaderState { bool alpha_test; enum AlphaFunc alpha_func; + bool texture_matrix_enable[4]; enum Texgen texgen[4][4]; enum Skinning skinning; @@ -1497,6 +1500,8 @@ typedef struct PGRAPHState { float composite_matrix[16]; /* FIXME: These are probably stored in the vshader consts */ + bool texture_matrix_enable[4]; + float texture_matrix[4][16]; /* 4 stages with 4x4 matrix each */ float projection_matrix[16]; float inverse_model_view_matrix[4][16]; /* 4 weights with 4x4 matrix each */ float model_view_matrix[4][16]; /* 4 weights with 4x4 matrix each */ @@ -2638,6 +2643,10 @@ static ShaderBinding* generate_shaders(const ShaderState state) qstring_append(vertex_shader_code, "\n" "uniform mat4 composite;\n" +"uniform mat4 texMat0;\n" +"uniform mat4 texMat1;\n" +"uniform mat4 texMat2;\n" +"uniform mat4 texMat3;\n" "uniform mat4 modelViewMat0;\n" "uniform mat4 modelViewMat1;\n" "uniform mat4 modelViewMat2;\n" @@ -2937,6 +2946,11 @@ static void pgraph_bind_shaders(PGRAPHState *pg) } } + /* Texture matrices */ + for (i = 0; i < 4; i++) { + state.texture_matrix_enable[i] = pg->texture_matrix_enable[i]; + } + for (i = 0; i < 8; i++) { state.rgb_inputs[i] = pg->regs[NV_PGRAPH_COMBINECOLORI0 + i * 4]; state.rgb_outputs[i] = pg->regs[NV_PGRAPH_COMBINECOLORO0 + i * 4]; @@ -3049,6 +3063,13 @@ static void pgraph_bind_shaders(PGRAPHState *pg) } + /* Texture matrices */ + sprintf(name, "texMat%d", i); + loc = glGetUniformLocation(pg->shader_binding->gl_program, name); + if (loc != -1) { + glUniformMatrix4fv(loc, 1, GL_FALSE, pg->texture_matrix[i]); + } + } /* For each vertex weight */ @@ -4298,6 +4319,10 @@ static void pgraph_method(NV2AState *d, SET_MASK(pg->regs[reg], mask, kelvin_map_texgen(parameter, 3)); break; } + CASE_4(NV097_SET_TEXTURE_MATRIX_ENABLE,4): + slot = (class_method - NV097_SET_TEXTURE_MATRIX_ENABLE) / 4; + pg->texture_matrix_enable[slot] = parameter; + break; case NV097_SET_PROJECTION_MATRIX ... NV097_SET_PROJECTION_MATRIX + 0x3c: @@ -4323,6 +4348,12 @@ static void pgraph_method(NV2AState *d, pg->composite_matrix[slot] = *(float*)¶meter; break; + case NV097_SET_TEXTURE_MATRIX ... + NV097_SET_TEXTURE_MATRIX + 0xfc: + slot = (class_method - NV097_SET_TEXTURE_MATRIX) / 4; + pg->texture_matrix[slot / 16][slot % 16] = *(float*)¶meter; + break; + case NV097_SET_TEXGEN_VIEW_MODEL: SET_MASK(pg->regs[NV_PGRAPH_CSV0_D], NV_PGRAPH_CSV0_D_TEXGEN_REF, parameter); diff --git a/hw/xbox/nv2a_vsh.c b/hw/xbox/nv2a_vsh.c index 7da6f785c1..0fdd3e096c 100644 --- a/hw/xbox/nv2a_vsh.c +++ b/hw/xbox/nv2a_vsh.c @@ -748,6 +748,11 @@ QString* vsh_translate(uint16_t version, qstring_append_fmt(header, "noperspective out vec4 %cT1;\n", output_prefix); qstring_append_fmt(header, "noperspective out vec4 %cT2;\n", output_prefix); qstring_append_fmt(header, "noperspective out vec4 %cT3;\n", output_prefix); + qstring_append(header, "\n" + "uniform mat4 texMat0;\n" + "uniform mat4 texMat1;\n" + "uniform mat4 texMat2;\n" + "uniform mat4 texMat3;\n"); qstring_append(header, vsh_header); QString *body = qstring_from_str("\n"); From 939ad0121a443d8529220fad7d5f7f6a17ef5501 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 16 Jul 2015 11:22:04 +0200 Subject: [PATCH 13/25] Prepare for vertex weights --- hw/xbox/nv2a.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index ee8badba69..a1505c62b1 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -1405,6 +1405,7 @@ typedef struct TextureBinding { typedef struct InlineVertexBufferEntry { float position[4]; + float weight[4]; float diffuse[4]; float tex_coord[NV2A_MAX_TEXTURES][4]; } InlineVertexBufferEntry; @@ -2607,6 +2608,7 @@ static ShaderBinding* generate_shaders(const ShaderState state) "#version 330\n" "\n" "in vec4 position;\n" +"in vec4 weight;\n" "in vec3 normal;\n" "in vec4 diffuse;\n" "in vec4 specular;\n" @@ -2723,6 +2725,7 @@ static ShaderBinding* generate_shaders(const ShaderState state) if (state.fixed_function) { /* bind fixed function vertex attributes */ glBindAttribLocation(program, NV2A_VERTEX_ATTR_POSITION, "position"); + glBindAttribLocation(program, NV2A_VERTEX_ATTR_WEIGHT, "weight"); glBindAttribLocation(program, NV2A_VERTEX_ATTR_DIFFUSE, "diffuse"); glBindAttribLocation(program, NV2A_VERTEX_ATTR_SPECULAR, "specular"); glBindAttribLocation(program, NV2A_VERTEX_ATTR_FOG, "fog"); @@ -4600,6 +4603,14 @@ static void pgraph_method(NV2AState *d, (void*)offsetof(InlineVertexBufferEntry, position)); glEnableVertexAttribArray(NV2A_VERTEX_ATTR_POSITION); + glVertexAttribPointer(NV2A_VERTEX_ATTR_WEIGHT, + 4, + GL_FLOAT, + GL_FALSE, + sizeof(InlineVertexBufferEntry), + (void*)offsetof(InlineVertexBufferEntry, weight)); + glEnableVertexAttribArray(NV2A_VERTEX_ATTR_WEIGHT); + glVertexAttribPointer(NV2A_VERTEX_ATTR_DIFFUSE, 4, GL_FLOAT, From 71ad6234fad2d83f345f7341c7b8af1c790bee7a Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 16 Jul 2015 11:28:41 +0200 Subject: [PATCH 14/25] Cleanup PSH and alphakill --- hw/xbox/nv2a.c | 8 +++----- hw/xbox/nv2a_psh.c | 12 +++++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index a1505c62b1..0f466919f5 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -2975,14 +2975,12 @@ static void pgraph_bind_shaders(PGRAPHState *pg) state.rect_tex[i] = true; } - int j; - for(j = 0; j < 4; j++) { - /* compare_mode[i][j] = stage i, component j { s,t,r,q } */ + for (j = 0; j < 4; j++) { state.compare_mode[i][j] = (pg->regs[NV_PGRAPH_SHADERCLIPMODE] >> (4 * i + j)) & 1; } - state.alphakill[i] = GET_MASK(pg->regs[NV_PGRAPH_TEXCTL0_0 + i*4], - NV_PGRAPH_TEXCTL0_0_ALPHAKILLEN); + state.alphakill[i] = pg->regs[NV_PGRAPH_TEXCTL0_0 + i*4] + & NV_PGRAPH_TEXCTL0_0_ALPHAKILLEN; } ShaderBinding* cached_shader = g_hash_table_lookup(pg->shader_cache, &state); diff --git a/hw/xbox/nv2a_psh.c b/hw/xbox/nv2a_psh.c index c90a5a66af..780760f350 100644 --- a/hw/xbox/nv2a_psh.c +++ b/hw/xbox/nv2a_psh.c @@ -597,16 +597,19 @@ static QString* psh_convert(struct PixelShader *ps) case PS_TEXTUREMODES_PASSTHRU: qstring_append_fmt(vars, "vec4 t%d = pT%d;\n", i, i); break; + case PS_TEXTUREMODES_DOT_RFLCT_SPEC: + assert(false); + break; case PS_TEXTUREMODES_DPNDNT_AR: assert(!ps->rect_tex[i]); sampler_type = "sampler2D"; - qstring_append_fmt(vars, " vec4 t%d = texture(texSamp%d, t%d.ar);\n", + qstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, t%d.ar);\n", i, i, ps->input_tex[i]); break; case PS_TEXTUREMODES_DPNDNT_GB: assert(!ps->rect_tex[i]); sampler_type = "sampler2D"; - qstring_append_fmt(vars, " vec4 t%d = texture(texSamp%d, t%d.gb);\n", + qstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, t%d.gb);\n", i, i, ps->input_tex[i]); break; case PS_TEXTUREMODES_BUMPENVMAP_LUM: @@ -626,8 +629,7 @@ static QString* psh_convert(struct PixelShader *ps) break; case PS_TEXTUREMODES_CLIPPLANE: { int j; - assert(false); /* FIXME: Untested */ - qstring_append_fmt(vars, " vec4 t%d = vec4(0.0); /* PS_TEXTUREMODES_CLIPPLANE */\n", + qstring_append_fmt(vars, "vec4 t%d = vec4(0.0); /* PS_TEXTUREMODES_CLIPPLANE */\n", i); for (j = 0; j < 4; j++) { qstring_append_fmt(vars, " if(pT%d.%c %s 0.0) { discard; };\n", @@ -637,7 +639,7 @@ static QString* psh_convert(struct PixelShader *ps) break; } case PS_TEXTUREMODES_DOTPRODUCT: - qstring_append_fmt(vars, " vec4 t%d = vec4(dot(pT%d.xyz, t%d.rgb));\n", + qstring_append_fmt(vars, "vec4 t%d = vec4(dot(pT%d.xyz, t%d.rgb));\n", i, i, ps->input_tex[i]); break; default: From 2d46263821411794c8765dc1519a82a9476c695f Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 16 Jul 2015 11:34:10 +0200 Subject: [PATCH 15/25] Rename composite GLSL var to compositeMat --- hw/xbox/nv2a.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index 0f466919f5..7f140babf3 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -2644,7 +2644,6 @@ static ShaderBinding* generate_shaders(const ShaderState state) qstring_append(vertex_shader_code, "\n" -"uniform mat4 composite;\n" "uniform mat4 texMat0;\n" "uniform mat4 texMat1;\n" "uniform mat4 texMat2;\n" @@ -2658,11 +2657,12 @@ static ShaderBinding* generate_shaders(const ShaderState state) "uniform mat4 invModelViewMat2;\n" "uniform mat4 invModelViewMat3;\n" "uniform mat4 projectionMat;\n" +"uniform mat4 compositeMat;\n" "uniform mat4 invViewport;\n" "void main() {\n" -" gl_Position = invViewport * (position * composite);\n" +" gl_Position = invViewport * (position * compositeMat);\n" /* temp hack: the composite matrix includes the view transform... */ -//" gl_Position = position * composite;\n" +//" gl_Position = position * compositeMat;\n" //" gl_Position.x = (gl_Position.x - 320.0) / 320.0;\n" //" gl_Position.y = -(gl_Position.y - 240.0) / 240.0;\n" " gl_Position.z = gl_Position.z * 2.0 - gl_Position.w;\n"); @@ -3107,7 +3107,7 @@ static void pgraph_bind_shaders(PGRAPHState *pg) /* update fixed function composite matrix */ GLint comLoc = glGetUniformLocation(pg->shader_binding->gl_program, - "composite"); + "compositeMat"); if (comLoc != -1) { glUniformMatrix4fv(comLoc, 1, GL_FALSE, pg->composite_matrix); } From fc3b5d0c882acb71bbfd206a5eb37d406ed8c9ba Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 16 Jul 2015 11:43:19 +0200 Subject: [PATCH 16/25] Skinning, Texgen and Texture matrices WIP --- hw/xbox/nv2a.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 122 insertions(+), 5 deletions(-) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index 7f140babf3..6c8c6cc0c5 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -2659,8 +2659,125 @@ static ShaderBinding* generate_shaders(const ShaderState state) "uniform mat4 projectionMat;\n" "uniform mat4 compositeMat;\n" "uniform mat4 invViewport;\n" -"void main() {\n" +"\n" +"void main() {\n"); + + /* Skinning */ + unsigned int count; + bool mix; + switch (state.skinning) { + case SKINNING_OFF: + count = 0; break; + case SKINNING_1WEIGHTS: + mix = true; count = 2; break; + case SKINNING_2WEIGHTS: + mix = true; count = 3; break; + case SKINNING_3WEIGHTS: + mix = true; count = 4; break; + case SKINNING_2WEIGHTS2MATRICES: + mix = false; count = 2; break; + case SKINNING_3WEIGHTS3MATRICES: + mix = false; count = 3; break; + case SKINNING_4WEIGHTS4MATRICES: + mix = false; count = 4; break; + default: + assert(false); + break; + } + qstring_append_fmt(vertex_shader_code, "/* Skinning mode %d */\n", + state.skinning); + if (count == 0) { + qstring_append(vertex_shader_code, "vec4 tPosition = position * modelViewMat0;\n"); + qstring_append(vertex_shader_code, "vec3 tNormal = (invModelViewMat0 * vec4(normal, 0.0)).xyz;\n"); + } else { + qstring_append(vertex_shader_code, "vec4 tPosition = vec4(0.0);\n"); + qstring_append(vertex_shader_code, "vec3 tNormal = vec3(0.0);\n"); + if (mix) { + /* Tweening */ + /* + This should *probably* be something like: + if (count == 2) { + pos = mix(position*modelViewMat0,position*modelViewMat1,weight.x) + } + Not sure about higher amount of matrices. + /* + assert(false); + } else { + /* Individual matrices */ + for (i = 0; i < count; i++) { + char c = "xyzw"[i]; + qstring_append_fmt(vertex_shader_code, "tPosition += position * modelViewMat%d * weight.%c;\n", + i, c); + qstring_append_fmt(vertex_shader_code, "tNormal += (invModelViewMat%d * vec4(normal, 0.0) * weight.%c).xyz;\n", + i, c); + } + } + } + + /* Normalization */ + if (state.normalization) { + qstring_append(vertex_shader_code, "tNormal = normalize(tNormal);\n"); + } + + /* Texgen */ + for (i = 0; i < 4; i++) { + qstring_append_fmt(vertex_shader_code, "/* Texgen for stage %d */\n", + i); + qstring_append_fmt(vertex_shader_code, "vec4 tTexture%d;\n", + i); + /* Set each component individually */ + /* FIXME: could be nicer if some channels share the same texgen */ + for (j = 0; j < 4; j++) { + char c = "xyzw"[j]; + switch (state.texgen[i][j]) { + case TEXGEN_DISABLE: + qstring_append_fmt(vertex_shader_code, "tTexture%d.%c = texture%d.%c;\n", + i, c, i, c); + break; + case TEXGEN_EYE_LINEAR: + qstring_append_fmt(vertex_shader_code, "tTexture%d.%c = tPosition.%c;\n", + i, c, c); + break; + case TEXGEN_OBJECT_LINEAR: + qstring_append_fmt(vertex_shader_code, "tTexture%d.%c = position.%c;\n", + i, c, c); + break; + case TEXGEN_SPHERE_MAP: + assert(i < 2); /* Channels S,T only! */ + assert(false); + break; + case TEXGEN_REFLECTION_MAP: + assert(i < 3); /* Channels S,T,R only! */ + qstring_append_fmt(vertex_shader_code, "tTexture%d.%c = reflect(???, tNormal).%c;\n", + i, c, c); + assert(false); /* FIXME: Code not complete yet! */ + break; + case TEXGEN_NORMAL_MAP: + assert(i < 3); /* Channels S,T,R only! */ + qstring_append_fmt(vertex_shader_code, "tTexture%d.%c = tNormal.%c;\n", + i, c, c); + break; + default: + assert(false); + break; + } + } + } + + /* Apply texture matrices */ + for (i = 0; i < 4; i++) { + if (state.texture_matrix_enable[i]) { + qstring_append_fmt(vertex_shader_code, "tTexture%d = tTexture%d * texMat%d;\n", + i, i, i); + } + } + + qstring_append(vertex_shader_code, +#if 0 +" gl_Position = position * modelViewMat0 * projectionMat;\n" +#else " gl_Position = invViewport * (position * compositeMat);\n" +#endif /* temp hack: the composite matrix includes the view transform... */ //" gl_Position = position * compositeMat;\n" //" gl_Position.x = (gl_Position.x - 320.0) / 320.0;\n" @@ -2678,13 +2795,13 @@ static ShaderBinding* generate_shaders(const ShaderState state) qstring_append_fmt(vertex_shader_code, "%cB1 = backSpecular * %cPos_w;\n", v_prefix, v_prefix); qstring_append_fmt(vertex_shader_code, - "%cT0 = texture0 * %cPos_w;\n", v_prefix, v_prefix); + "%cT0 = tTexture0 * %cPos_w;\n", v_prefix, v_prefix); qstring_append_fmt(vertex_shader_code, - "%cT1 = texture1 * %cPos_w;\n", v_prefix, v_prefix); + "%cT1 = tTexture1 * %cPos_w;\n", v_prefix, v_prefix); qstring_append_fmt(vertex_shader_code, - "%cT2 = texture2 * %cPos_w;\n", v_prefix, v_prefix); + "%cT2 = tTexture2 * %cPos_w;\n", v_prefix, v_prefix); qstring_append_fmt(vertex_shader_code, - "%cT3 = texture3 * %cPos_w;\n", v_prefix, v_prefix); + "%cT3 = tTexture3 * %cPos_w;\n", v_prefix, v_prefix); qstring_append(vertex_shader_code, "}\n"); From ce6524089718564253dc1f886eaa2b2411c22a78 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 16 Jul 2015 14:10:33 +0200 Subject: [PATCH 17/25] Remove req. for GL_EXT_texture_snorm (Part of GL3.3) --- hw/xbox/nv2a.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index 6c8c6cc0c5..0a37d3a2d4 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -3719,7 +3719,6 @@ static void pgraph_init(NV2AState *d) glextensions_init(); assert(glo_check_extension("GL_EXT_texture_compression_s3tc")); - assert(glo_check_extension("GL_EXT_texture_snorm")); assert(glo_check_extension("GL_ARB_ES2_compatibility")); GLint max_vertex_attributes; From 5f0759c27efc232fa1ead6c5ef60c1a86ddbb7fc Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 16 Jul 2015 14:15:40 +0200 Subject: [PATCH 18/25] Explanation for GL extensions --- hw/xbox/nv2a.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index 0a37d3a2d4..faa4a9dea8 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -3718,7 +3718,9 @@ static void pgraph_init(NV2AState *d) glextensions_init(); + /* DXT textures */ assert(glo_check_extension("GL_EXT_texture_compression_s3tc")); + /* Internal RGB565 texture format */ assert(glo_check_extension("GL_ARB_ES2_compatibility")); GLint max_vertex_attributes; From 3ffbb446eb2fb01dd6807ddad943f22d629de115 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 16 Jul 2015 14:38:33 +0200 Subject: [PATCH 19/25] Add some FIXME --- hw/xbox/nv2a.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index faa4a9dea8..0b7954c5fa 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -2644,6 +2644,7 @@ static ShaderBinding* generate_shaders(const ShaderState state) qstring_append(vertex_shader_code, "\n" +/* FIXME: Add these uniforms using code when they are used */ "uniform mat4 texMat0;\n" "uniform mat4 texMat1;\n" "uniform mat4 texMat2;\n" @@ -2656,7 +2657,7 @@ static ShaderBinding* generate_shaders(const ShaderState state) "uniform mat4 invModelViewMat1;\n" "uniform mat4 invModelViewMat2;\n" "uniform mat4 invModelViewMat3;\n" -"uniform mat4 projectionMat;\n" +"uniform mat4 projectionMat; /* FIXME: when is this used? */\n" "uniform mat4 compositeMat;\n" "uniform mat4 invViewport;\n" "\n" From 8a43da637a3c0801da88266833f51fff8530ff0a Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 16 Jul 2015 14:41:30 +0200 Subject: [PATCH 20/25] Fix some parts of skinning --- hw/xbox/nv2a.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index 0b7954c5fa..44d7d71553 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -2688,21 +2688,22 @@ static ShaderBinding* generate_shaders(const ShaderState state) qstring_append_fmt(vertex_shader_code, "/* Skinning mode %d */\n", state.skinning); if (count == 0) { - qstring_append(vertex_shader_code, "vec4 tPosition = position * modelViewMat0;\n"); + qstring_append(vertex_shader_code, "vec4 tPosition = position;\n"); + /* FIXME: Is the normal still transformed? */ qstring_append(vertex_shader_code, "vec3 tNormal = (invModelViewMat0 * vec4(normal, 0.0)).xyz;\n"); } else { qstring_append(vertex_shader_code, "vec4 tPosition = vec4(0.0);\n"); qstring_append(vertex_shader_code, "vec3 tNormal = vec3(0.0);\n"); if (mix) { /* Tweening */ - /* - This should *probably* be something like: - if (count == 2) { - pos = mix(position*modelViewMat0,position*modelViewMat1,weight.x) - } - Not sure about higher amount of matrices. - /* - assert(false); + if (count == 2) { + qstring_append(vertex_shader_code, "tPosition += mix(position * modelViewMat1," + " position * modelViewMat0, weight.x);\n"); + + } else { + /* FIXME: Not sure how blend weights are calculated */ + assert(false); + } } else { /* Individual matrices */ for (i = 0; i < count; i++) { @@ -2774,11 +2775,7 @@ static ShaderBinding* generate_shaders(const ShaderState state) } qstring_append(vertex_shader_code, -#if 0 -" gl_Position = position * modelViewMat0 * projectionMat;\n" -#else -" gl_Position = invViewport * (position * compositeMat);\n" -#endif +" gl_Position = invViewport * (tPosition * compositeMat);\n" /* temp hack: the composite matrix includes the view transform... */ //" gl_Position = position * compositeMat;\n" //" gl_Position.x = (gl_Position.x - 320.0) / 320.0;\n" From 915a1ed410f6ac0dd24ad7079a8c1d6eb4d46594 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 16 Jul 2015 14:44:08 +0200 Subject: [PATCH 21/25] Style + FIXME for assert --- hw/xbox/nv2a.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index 44d7d71553..c84362b040 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -2697,8 +2697,9 @@ static ShaderBinding* generate_shaders(const ShaderState state) if (mix) { /* Tweening */ if (count == 2) { - qstring_append(vertex_shader_code, "tPosition += mix(position * modelViewMat1," - " position * modelViewMat0, weight.x);\n"); + qstring_append(vertex_shader_code, + "tPosition += mix(position * modelViewMat1," + " position * modelViewMat0, weight.x);\n"); } else { /* FIXME: Not sure how blend weights are calculated */ @@ -2713,6 +2714,7 @@ static ShaderBinding* generate_shaders(const ShaderState state) qstring_append_fmt(vertex_shader_code, "tNormal += (invModelViewMat%d * vec4(normal, 0.0) * weight.%c).xyz;\n", i, c); } + assert(false); /* FIXME: Untested */ } } From d99880dac6311fa44570bf4077e2498fe6f4e858 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 16 Jul 2015 15:03:17 +0200 Subject: [PATCH 22/25] Fix skinning normals and cleanup --- hw/xbox/nv2a.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index c84362b040..eb3ca5cc8d 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -2690,7 +2690,7 @@ static ShaderBinding* generate_shaders(const ShaderState state) if (count == 0) { qstring_append(vertex_shader_code, "vec4 tPosition = position;\n"); /* FIXME: Is the normal still transformed? */ - qstring_append(vertex_shader_code, "vec3 tNormal = (invModelViewMat0 * vec4(normal, 0.0)).xyz;\n"); + qstring_append(vertex_shader_code, "vec3 tNormal = (vec4(normal, 0.0) * invModelViewMat0).xyz;\n"); } else { qstring_append(vertex_shader_code, "vec4 tPosition = vec4(0.0);\n"); qstring_append(vertex_shader_code, "vec3 tNormal = vec3(0.0);\n"); @@ -2698,9 +2698,10 @@ static ShaderBinding* generate_shaders(const ShaderState state) /* Tweening */ if (count == 2) { qstring_append(vertex_shader_code, - "tPosition += mix(position * modelViewMat1," - " position * modelViewMat0, weight.x);\n"); - + "tPosition += mix(position * modelViewMat1,\n" + " position * modelViewMat0, weight.x);\n" + "tNormal += mix((vec4(normal, 0.0) * invModelViewMat1).xyz,\n" + " (vec4(normal, 0.0) * invModelViewMat0).xyz, weight.x);\n"); } else { /* FIXME: Not sure how blend weights are calculated */ assert(false); @@ -2711,7 +2712,7 @@ static ShaderBinding* generate_shaders(const ShaderState state) char c = "xyzw"[i]; qstring_append_fmt(vertex_shader_code, "tPosition += position * modelViewMat%d * weight.%c;\n", i, c); - qstring_append_fmt(vertex_shader_code, "tNormal += (invModelViewMat%d * vec4(normal, 0.0) * weight.%c).xyz;\n", + qstring_append_fmt(vertex_shader_code, "tNormal += (vec4(normal, 0.0) * invModelViewMat%d * weight.%c).xyz;\n", i, c); } assert(false); /* FIXME: Untested */ From 811673cfde4cf2e277e707449759c2484877517e Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 16 Jul 2015 22:59:32 +0200 Subject: [PATCH 23/25] Give VSH and PSH types a prefix --- hw/xbox/nv2a.c | 6 +++--- hw/xbox/nv2a_psh.c | 4 ++-- hw/xbox/nv2a_psh.h | 4 ++-- hw/xbox/nv2a_vsh.h | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index eb3ca5cc8d..407822508b 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -1337,12 +1337,12 @@ typedef struct ShaderState { bool alphakill[4]; bool alpha_test; - enum AlphaFunc alpha_func; + enum PshAlphaFunc alpha_func; bool texture_matrix_enable[4]; - enum Texgen texgen[4][4]; + enum VshTexgen texgen[4][4]; - enum Skinning skinning; + enum VshSkinning skinning; bool normalization; diff --git a/hw/xbox/nv2a_psh.c b/hw/xbox/nv2a_psh.c index 780760f350..fbd83f909b 100644 --- a/hw/xbox/nv2a_psh.c +++ b/hw/xbox/nv2a_psh.c @@ -204,7 +204,7 @@ struct PixelShader { bool alphakill[4]; bool alpha_test; - enum AlphaFunc alpha_func; + enum PshAlphaFunc alpha_func; QString *varE, *varF; QString *code; @@ -769,7 +769,7 @@ QString *psh_translate(uint32_t combiner_control, uint32_t shader_stage_program, const bool rect_tex[4], const bool compare_mode[4][4], const bool alphakill[4], - bool alpha_test, enum AlphaFunc alpha_func) + bool alpha_test, enum PshAlphaFunc alpha_func) { int i; struct PixelShader ps; diff --git a/hw/xbox/nv2a_psh.h b/hw/xbox/nv2a_psh.h index d75043797d..965b238612 100644 --- a/hw/xbox/nv2a_psh.h +++ b/hw/xbox/nv2a_psh.h @@ -24,7 +24,7 @@ #include "qapi/qmp/qstring.h" -enum AlphaFunc { +enum PshAlphaFunc { ALPHA_FUNC_NEVER, ALPHA_FUNC_LESS, ALPHA_FUNC_EQUAL, @@ -47,6 +47,6 @@ QString *psh_translate(uint32_t combiner_control, uint32_t shader_stage_program, const bool rect_tex[4], const bool compare_mode[4][4], const bool alphakill[4], - bool alpha_test, enum AlphaFunc alpha_func); + bool alpha_test, enum PshAlphaFunc alpha_func); #endif diff --git a/hw/xbox/nv2a_vsh.h b/hw/xbox/nv2a_vsh.h index c41069ee30..d541ec2dbc 100644 --- a/hw/xbox/nv2a_vsh.h +++ b/hw/xbox/nv2a_vsh.h @@ -24,7 +24,7 @@ #include "qapi/qmp/qstring.h" -enum Texgen { +enum VshTexgen { TEXGEN_DISABLE, TEXGEN_EYE_LINEAR, TEXGEN_OBJECT_LINEAR, @@ -33,7 +33,7 @@ enum Texgen { TEXGEN_REFLECTION_MAP, }; -enum Skinning { +enum VshSkinning { SKINNING_OFF, SKINNING_1WEIGHTS, SKINNING_2WEIGHTS, From 58411243d1417a82f45e4f9440d4bc4b8f8297f6 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Fri, 17 Jul 2015 00:16:52 +0200 Subject: [PATCH 24/25] Fix delta-R6G5B5 code (incl. new mapping algorithm) --- hw/xbox/nv2a.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index 407822508b..8c6d7df703 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -2097,21 +2097,15 @@ static uint8_t* convert_texture_data(const TextureShape s, int x, y; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { - uint8_t v; - uint16_t rgb565 = *(uint16_t*)(data + y * pitch + x * 2); + uint16_t rgb655 = *(uint16_t*)(data + y * pitch + x * 2); int8_t *pixel = &converted_data[(y * width + x) * 3]; - /* FIXME: This is pretty ugly code to extend from - * signed 565 to signed 888 (hopefully) + /* Maps 5 bit G and B signed value range to 8 bit + * signed values. R is probably unsigned. */ - v = (rgb565 & 0xF800) >> 8; - pixel[0] = (v & 0x80) ? *(int8_t*)&v * 16 / 0x80 - : ((v & 0x78) * 15) / 0x78; - v = (rgb565 & 0x07E0) >> 3; - pixel[1] = (v & 0x80) ? *(int8_t*)&v * 32 / 0x80 - : ((v & 0x7C) * 31) / 0x7C; - v = (rgb565 & 0x001F) << 3; - pixel[2] = (v & 0x80) ? *(int8_t*)&v * 16 / 0x80 - : ((v & 0x78) * 15) / 0x78; + rgb655 ^= (1 << 9) | (1 << 4); + pixel[0] = ((rgb655 & 0xFC00) >> 10) * 0x7F / 0x3F; + pixel[1] = ((rgb655 & 0x03E0) >> 5) * 0xFF / 0x1F - 0x80; + pixel[2] = (rgb655 & 0x001F) * 0xFF / 0x1F - 0x80; } } return converted_data; From 8c445b5c690095d4ce025dd26a90535613dc1064 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Fri, 17 Jul 2015 02:28:50 +0200 Subject: [PATCH 25/25] Fix Texgen by doing skinning fixup later --- hw/xbox/nv2a.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index 8c6d7df703..d0c0b6c352 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -2682,7 +2682,7 @@ static ShaderBinding* generate_shaders(const ShaderState state) qstring_append_fmt(vertex_shader_code, "/* Skinning mode %d */\n", state.skinning); if (count == 0) { - qstring_append(vertex_shader_code, "vec4 tPosition = position;\n"); + qstring_append(vertex_shader_code, "vec4 tPosition = position * modelViewMat0;\n"); /* FIXME: Is the normal still transformed? */ qstring_append(vertex_shader_code, "vec3 tNormal = (vec4(normal, 0.0) * invModelViewMat0).xyz;\n"); } else { @@ -2771,6 +2771,11 @@ static ShaderBinding* generate_shaders(const ShaderState state) } } + /* If skinning is off the composite matrix already includes the MV matrix */ + if (state.skinning == SKINNING_OFF) { + qstring_append(vertex_shader_code, "tPosition = position;\n"); + } + qstring_append(vertex_shader_code, " gl_Position = invViewport * (tPosition * compositeMat);\n" /* temp hack: the composite matrix includes the view transform... */