diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index 6c76546ac5..d0c0b6c352 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -337,12 +337,46 @@ 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_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) +# 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 @@ -384,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 @@ -448,18 +484,32 @@ 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 #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 #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 @@ -481,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 @@ -725,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 @@ -793,7 +855,26 @@ 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 +# 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_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 # define NV097_SET_VIEWPORT_OFFSET 0x00970A20 # define NV097_SET_COMBINER_FACTOR0 0x00970A60 # define NV097_SET_COMBINER_FACTOR1 0x00970A80 @@ -816,6 +897,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 @@ -858,6 +940,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 @@ -878,6 +961,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 @@ -889,6 +976,9 @@ 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_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 @@ -909,8 +999,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 @@ -950,6 +1040,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, @@ -1052,7 +1151,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] = @@ -1070,7 +1169,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] = @@ -1079,8 +1178,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] = @@ -1106,7 +1207,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] = @@ -1232,10 +1333,18 @@ 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; + enum PshAlphaFunc alpha_func; + bool texture_matrix_enable[4]; + enum VshTexgen texgen[4][4]; + + enum VshSkinning skinning; + + bool normalization; bool fixed_function; @@ -1296,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; @@ -1389,7 +1499,16 @@ typedef struct PGRAPHState { ShaderBinding *shader_binding; float composite_matrix[16]; - GLint composite_matrix_location; + + /* 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 */ + + /* FIXME: Move to NV_PGRAPH_BUMPMAT... */ + float bump_env_matrix[3][4]; /* 4 stages with 2x2 matrix each */ GloContext *gl_context; GLuint gl_framebuffer; @@ -1972,6 +2091,24 @@ 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++) { + uint16_t rgb655 = *(uint16_t*)(data + y * pitch + x * 2); + int8_t *pixel = &converted_data[(y * width + x) * 3]; + /* Maps 5 bit G and B signed value range to 8 bit + * signed values. R is probably unsigned. + */ + 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; } else { return NULL; } @@ -2003,7 +2140,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) { @@ -2147,6 +2284,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); @@ -2179,6 +2317,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 = @@ -2197,6 +2339,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); @@ -2328,6 +2475,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]); } @@ -2443,6 +2602,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" @@ -2478,12 +2638,148 @@ static ShaderBinding* generate_shaders(const ShaderState state) qstring_append(vertex_shader_code, "\n" -"uniform mat4 composite;\n" +/* FIXME: Add these uniforms using code when they are used */ +"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" +"uniform mat4 modelViewMat3;\n" +"uniform mat4 invModelViewMat0;\n" +"uniform mat4 invModelViewMat1;\n" +"uniform mat4 invModelViewMat2;\n" +"uniform mat4 invModelViewMat3;\n" +"uniform mat4 projectionMat; /* FIXME: when is this used? */\n" +"uniform mat4 compositeMat;\n" "uniform mat4 invViewport;\n" -"void main() {\n" -" gl_Position = invViewport * (position * composite);\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"); + /* FIXME: Is the normal still transformed? */ + 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"); + if (mix) { + /* Tweening */ + if (count == 2) { + qstring_append(vertex_shader_code, + "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); + } + } 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 += (vec4(normal, 0.0) * invModelViewMat%d * weight.%c).xyz;\n", + i, c); + } + assert(false); /* FIXME: Untested */ + } + } + + /* 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); + } + } + + /* 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... */ -//" 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"); @@ -2499,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"); @@ -2546,6 +2842,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"); @@ -2580,6 +2877,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); @@ -2688,7 +2987,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; @@ -2719,6 +3018,12 @@ 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, + /* fixed function stuff */ .fixed_function = fixed_function, @@ -2747,6 +3052,25 @@ 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]); + } + } + + /* 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]; @@ -2758,8 +3082,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); @@ -2767,6 +3091,13 @@ static void pgraph_bind_shaders(PGRAPHState *pg) if (enabled && kelvin_color_format_map[color_format].linear) { state.rect_tex[i] = true; } + + for (j = 0; j < 4; j++) { + state.compare_mode[i][j] = + (pg->regs[NV_PGRAPH_SHADERCLIPMODE] >> (4 * i + j)) & 1; + } + 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); @@ -2799,7 +3130,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) { @@ -2821,7 +3151,71 @@ static void pgraph_bind_shaders(PGRAPHState *pg) glUniform1f(alpha_ref_loc, alpha_ref); } + /* 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]); + } + + } + + /* 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 */ + 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]; @@ -2829,9 +3223,11 @@ static void pgraph_bind_shaders(PGRAPHState *pg) if (fixed_function) { /* update fixed function composite matrix */ - GLint comLoc = glGetUniformLocation(pg->shader_binding->gl_program, "composite"); - assert(comLoc != -1); - glUniformMatrix4fv(comLoc, 1, GL_FALSE, pg->composite_matrix); + GLint comLoc = glGetUniformLocation(pg->shader_binding->gl_program, + "compositeMat"); + 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; @@ -2842,7 +3238,6 @@ static void pgraph_bind_shaders(PGRAPHState *pg) float m43 = zclip_min; //float m44 = 1.0; - if (m33 == 0.0) { m33 = 1.0; } @@ -2855,8 +3250,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 */ @@ -3322,7 +3718,10 @@ 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; glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &max_vertex_attributes); @@ -3429,6 +3828,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, @@ -3747,6 +4173,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); @@ -3773,6 +4203,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); @@ -3962,12 +4396,88 @@ 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 + : 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_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: + 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; 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); + break; + case NV097_SET_VIEWPORT_OFFSET ... NV097_SET_VIEWPORT_OFFSET + 12: @@ -4209,6 +4719,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, @@ -4438,6 +4956,30 @@ static void pgraph_method(NV2AState *d, pg->texture_dirty[slot] = true; break; } + + 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; + 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: assert(pg->inline_elements_length < NV2A_MAX_BATCH_LENGTH); pg->inline_elements[ @@ -4622,6 +5164,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; @@ -4642,9 +5188,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_psh.c b/hw/xbox/nv2a_psh.c index 87ed625fb3..fbd83f909b 100644 --- a/hw/xbox/nv2a_psh.c +++ b/hw/xbox/nv2a_psh.c @@ -197,11 +197,14 @@ 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; + enum PshAlphaFunc alpha_func; QString *varE, *varF; QString *code; @@ -561,12 +564,17 @@ static QString* psh_convert(struct PixelShader *ps) qstring_append(vars, "vec4 v1 = pD1;\n"); qstring_append(vars, "float fog = pFog.x;\n"); + ps->code = qstring_new(); + 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,29 +586,80 @@ 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_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", + 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_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"; + 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; + 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", + i, "xyzw"[j], + ps->compare_mode[i][j] ? ">=" : "<"); + } + 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); + + /* 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); + } } } - 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); @@ -708,7 +767,9 @@ 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], - bool alpha_test, enum AlphaFunc alpha_func) + const bool compare_mode[4][4], + const bool alphakill[4], + bool alpha_test, enum PshAlphaFunc alpha_func) { int i; struct PixelShader ps; @@ -762,4 +823,4 @@ QString *psh_translate(uint32_t combiner_control, uint32_t shader_stage_program, return psh_convert(&ps); -} \ No newline at end of file +} diff --git a/hw/xbox/nv2a_psh.h b/hw/xbox/nv2a_psh.h index 51d2623f82..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, @@ -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], - bool alpha_test, enum AlphaFunc alpha_func); + const bool compare_mode[4][4], + const bool alphakill[4], + bool alpha_test, enum PshAlphaFunc alpha_func); -#endif \ No newline at end of file +#endif 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"); diff --git a/hw/xbox/nv2a_vsh.h b/hw/xbox/nv2a_vsh.h index 3e2aa9c87a..d541ec2dbc 100644 --- a/hw/xbox/nv2a_vsh.h +++ b/hw/xbox/nv2a_vsh.h @@ -24,6 +24,25 @@ #include "qapi/qmp/qstring.h" +enum VshTexgen { + TEXGEN_DISABLE, + TEXGEN_EYE_LINEAR, + TEXGEN_OBJECT_LINEAR, + TEXGEN_SPHERE_MAP, + TEXGEN_NORMAL_MAP, + TEXGEN_REFLECTION_MAP, +}; + +enum VshSkinning { + 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 @@ -90,4 +109,4 @@ QString* vsh_translate(uint16_t version, char output_prefix); -#endif \ No newline at end of file +#endif