From 08f3f9832270a97d54e53ebd202bd1408b8fc1e5 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Tue, 30 Jul 2024 00:00:33 -0700 Subject: [PATCH] nv2a: Normalize unnormalized texture coordinates in shader --- hw/xbox/nv2a/pgraph/gl/texture.c | 60 ++++++-------- hw/xbox/nv2a/pgraph/glsl/psh.c | 130 ++++++++++--------------------- hw/xbox/nv2a/pgraph/vk/texture.c | 7 -- 3 files changed, 65 insertions(+), 132 deletions(-) diff --git a/hw/xbox/nv2a/pgraph/gl/texture.c b/hw/xbox/nv2a/pgraph/gl/texture.c index 4011e979fec..b951b7e1e0c 100644 --- a/hw/xbox/nv2a/pgraph/gl/texture.c +++ b/hw/xbox/nv2a/pgraph/gl/texture.c @@ -203,7 +203,6 @@ void pgraph_gl_bind_textures(NV2AState *d) glActiveTexture(GL_TEXTURE0 + i); if (!enabled) { glBindTexture(GL_TEXTURE_CUBE_MAP, 0); - glBindTexture(GL_TEXTURE_RECTANGLE, 0); glBindTexture(GL_TEXTURE_1D, 0); glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_3D, 0); @@ -363,11 +362,7 @@ void pgraph_gl_bind_textures(NV2AState *d) surface->vram_addr, surface->width, surface->height); pgraph_gl_render_surface_to_texture(d, surface, binding, &state, i); binding->draw_time = surface->draw_time; - if (binding->gl_target == GL_TEXTURE_RECTANGLE) { - binding->scale = pg->surface_scale_factor; - } else { - binding->scale = 1; - } + binding->scale = pg->surface_scale_factor; } apply_texture_parameters(binding, @@ -428,28 +423,29 @@ static void upload_gl_texture(GLenum gl_target, case GL_TEXTURE_1D: assert(false); break; - case GL_TEXTURE_RECTANGLE: { - /* Can't handle strides unaligned to pixels */ - assert(s.pitch % f.bytes_per_pixel == 0); - - uint8_t *converted = pgraph_convert_texture_data( - s, texture_data, palette_data, adjusted_width, adjusted_height, 1, - adjusted_pitch, 0, NULL); - glPixelStorei(GL_UNPACK_ROW_LENGTH, - converted ? 0 : adjusted_pitch / f.bytes_per_pixel); - glTexImage2D(gl_target, 0, f.gl_internal_format, - adjusted_width, adjusted_height, 0, - f.gl_format, f.gl_type, - converted ? converted : texture_data); - - if (converted) { - g_free(converted); - } - - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - break; - } case GL_TEXTURE_2D: + if (f.linear) { + /* Can't handle strides unaligned to pixels */ + assert(s.pitch % f.bytes_per_pixel == 0); + + uint8_t *converted = pgraph_convert_texture_data( + s, texture_data, palette_data, adjusted_width, adjusted_height, 1, + adjusted_pitch, 0, NULL); + glPixelStorei(GL_UNPACK_ROW_LENGTH, + converted ? 0 : adjusted_pitch / f.bytes_per_pixel); + glTexImage2D(GL_TEXTURE_2D, 0, f.gl_internal_format, + adjusted_width, adjusted_height, 0, + f.gl_format, f.gl_type, + converted ? converted : texture_data); + + if (converted) { + g_free(converted); + } + + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + break; + } + /* fallthru */ case GL_TEXTURE_CUBE_MAP_POSITIVE_X: case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: @@ -645,15 +641,7 @@ static TextureBinding* generate_texture(const TextureShape s, gl_target = GL_TEXTURE_CUBE_MAP; } else { if (f.linear) { - /* linear textures use unnormalised texcoords. - * GL_TEXTURE_RECTANGLE_ARB conveniently also does, but - * does not allow repeat and mirror wrap modes. - * (or mipmapping, but xbox d3d says 'Non swizzled and non - * compressed textures cannot be mip mapped.') - * Not sure if that'll be an issue. */ - - /* FIXME: GLSL 330 provides us with textureSize()! Use that? */ - gl_target = GL_TEXTURE_RECTANGLE; + gl_target = GL_TEXTURE_2D; assert(s.dimensionality == 2); } else { switch(s.dimensionality) { diff --git a/hw/xbox/nv2a/pgraph/glsl/psh.c b/hw/xbox/nv2a/pgraph/glsl/psh.c index f93fbd82edd..ff38a51106b 100644 --- a/hw/xbox/nv2a/pgraph/glsl/psh.c +++ b/hw/xbox/nv2a/pgraph/glsl/psh.c @@ -562,31 +562,13 @@ static void add_final_stage_code(struct PixelShader *ps, struct FCInputInfo fina ps->varE = ps->varF = NULL; } -static enum PS_TEXTUREMODES correct_texture_mode_for_dimensionality(enum PS_TEXTUREMODES mode, const PshState *state, int i) +static const char *get_sampler_type(enum PS_TEXTUREMODES mode, const PshState *state, int i) { + const char *sampler2D = "sampler2D"; + const char *sampler3D = "sampler3D"; + const char *samplerCube = "samplerCube"; int dim = state->dim_tex[i]; - switch (mode) { - case PS_TEXTUREMODES_PROJECT2D: - return dim == 2 ? PS_TEXTUREMODES_PROJECT2D : - dim == 3 ? PS_TEXTUREMODES_PROJECT3D : - mode; - case PS_TEXTUREMODES_PROJECT3D: - return dim == 2 ? PS_TEXTUREMODES_PROJECT2D : mode; - case PS_TEXTUREMODES_DOT_STR_3D: - return dim == 2 ? PS_TEXTUREMODES_DOT_ST : mode; - default: - return mode; - } -} - -static const char sampler2D[] = "sampler2D"; -static const char sampler3D[] = "sampler3D"; -static const char samplerCube[] = "samplerCube"; -static const char sampler2DRect[] = "sampler2DRect"; - -static const char* get_sampler_type(enum PS_TEXTUREMODES mode, const PshState *state, int i) -{ // FIXME: Cleanup switch (mode) { default: @@ -598,7 +580,7 @@ static const char* get_sampler_type(enum PS_TEXTUREMODES mode, const PshState *s if (state->tex_x8y24[i] && state->vulkan) { return "usampler2D"; } - return (state->rect_tex[i] && !state->vulkan) ? sampler2DRect : sampler2D; + return sampler2D; case PS_TEXTUREMODES_BUMPENVMAP: case PS_TEXTUREMODES_BUMPENVMAP_LUM: @@ -608,7 +590,7 @@ static const char* get_sampler_type(enum PS_TEXTUREMODES mode, const PshState *s assert(!"Shadow map support not implemented for this mode"); } assert(state->dim_tex[i] == 2); - return (state->rect_tex[i] && !state->vulkan) ? sampler2DRect : sampler2D; + return sampler2D; case PS_TEXTUREMODES_PROJECT3D: case PS_TEXTUREMODES_DOT_STR_3D: @@ -616,10 +598,9 @@ static const char* get_sampler_type(enum PS_TEXTUREMODES mode, const PshState *s return "usampler2D"; } if (state->shadow_map[i]) { - return (state->rect_tex[i] && !state->vulkan) ? sampler2DRect : sampler2D; + return sampler2D; } - assert(state->dim_tex[i] == 3); - return sampler3D; + return dim == 2 ? sampler2D : sampler3D; case PS_TEXTUREMODES_CUBEMAP: case PS_TEXTUREMODES_DOT_RFLCT_DIFF: @@ -664,27 +645,19 @@ static void psh_append_shadowmap(const struct PixelShader *ps, int i, bool compa return; } - mstring_append_fmt(vars, "pT%d.xy *= texScale%d;\n", i, i); const char *comparison = shadow_comparison_map[ps->state.shadow_depth_func]; - if (ps->state.rect_tex[i] && ps->state.vulkan) { - if (ps->state.tex_x8y24[i]) { - mstring_append_fmt( - vars, - "uvec4 t%d_depth_raw = textureLod(texSamp%d, pT%d.xy/pT%d.w, 0);\n", i, i, i, i); - mstring_append_fmt( - vars, - "vec4 t%d_depth = vec4(float(t%d_depth_raw.x >> 8) / 0xFFFFFF, 1.0, 0.0, 0.0);\n", - i, i); - } else { - mstring_append_fmt( - vars, - "vec4 t%d_depth = textureLod(texSamp%d, pT%d.xy/pT%d.w, 0);\n", i, - i, i, i); - } - } else { - mstring_append_fmt( - vars, "vec4 t%d_depth = textureProj(texSamp%d, pT%d.xyw);\n", i, i, - i); + + bool extract_msb_24b = ps->state.tex_x8y24[i] && ps->state.vulkan; + + mstring_append_fmt(vars, + "%svec4 t%d_depth%s = textureProj(texSamp%d, pT%d.xyw);\n", + extract_msb_24b ? "u" : "", i, extract_msb_24b ? "_raw" : "", i, i); + + if (extract_msb_24b) { + mstring_append_fmt(vars, + "vec4 t%d_depth = vec4(float(t%d_depth_raw.x >> 8) " + "/ 0xFFFFFF, 1.0, 0.0, 0.0);\n", + i, i); } // Depth.y != 0 indicates 24 bit; depth.z != 0 indicates float. @@ -733,26 +706,13 @@ static void apply_border_adjustment(const struct PixelShader *ps, MString *vars, static void apply_convolution_filter(const struct PixelShader *ps, MString *vars, int tex) { - // FIXME: Convolution for 2D textures // FIXME: Quincunx - assert(ps->state.rect_tex[tex]); - - if (ps->state.vulkan) { - mstring_append_fmt(vars, - "vec4 t%d = vec4(0.0);\n" - "for (int i = 0; i < 9; i++) {\n" - " vec2 texCoord = pT%d.xy/pT%d.w + convolution3x3[i];\n" - " t%d += textureLod(texSamp%d, texCoord, 0) * gaussian3x3[i];\n" - "}\n", tex, tex, tex, tex, tex); - } else { - mstring_append_fmt(vars, - "vec4 t%d = vec4(0.0);\n" - "for (int i = 0; i < 9; i++) {\n" - " vec3 texCoord = pT%d.xyw + vec3(convolution3x3[i], 0);\n" - " t%d += textureProj(texSamp%d, texCoord) * gaussian3x3[i];\n" - "}\n", tex, tex, tex, tex, tex); - - } + mstring_append_fmt(vars, + "vec4 t%d = vec4(0.0);\n" + "for (int i = 0; i < 9; i++) {\n" + " vec3 texCoord = pT%d.xyw + vec3(convolution3x3[i] / (textureSize(texSamp%d, 0) * texScale%d), 0);\n" + " t%d += textureProj(texSamp%d, texCoord) * gaussian3x3[i];\n" + "}\n", tex, tex, tex, tex, tex, tex, tex); } static MString* psh_convert(struct PixelShader *ps) @@ -924,6 +884,12 @@ static MString* psh_convert(struct PixelShader *ps) ps->code = mstring_new(); + for (i = 0; i < 4; i++) { + if (ps->state.rect_tex[i]) { + mstring_append_fmt(vars, "pT%d.xy /= textureSize(texSamp%d, 0) / texScale%d;\n", i, i, i); + } + } + for (i = 0; i < 4; i++) { const char *sampler_type = get_sampler_type(ps->tex_modes[i], &ps->state, i); @@ -944,22 +910,9 @@ static MString* psh_convert(struct PixelShader *ps) psh_append_shadowmap(ps, i, false, vars); } else { apply_border_adjustment(ps, vars, i, "pT%d"); - mstring_append_fmt(vars, "pT%d.xy = texScale%d * pT%d.xy;\n", i, i, i); - if (ps->state.rect_tex[i]) { - if ((ps->state.conv_tex[i] == - CONVOLUTION_FILTER_GAUSSIAN) || - (ps->state.conv_tex[i] == - CONVOLUTION_FILTER_QUINCUNX)) { - apply_convolution_filter(ps, vars, i); - } else { - if (ps->state.vulkan) { - mstring_append_fmt(vars, "vec4 t%d = textureLod(texSamp%d, pT%d.xy/pT%d.w, 0);\n", - i, i, i, i); - } else { - mstring_append_fmt(vars, "vec4 t%d = textureProj(texSamp%d, pT%d.xyw);\n", - i, i, i); - } - } + if (((ps->state.conv_tex[i] == CONVOLUTION_FILTER_GAUSSIAN) || + (ps->state.conv_tex[i] == CONVOLUTION_FILTER_QUINCUNX))) { + apply_convolution_filter(ps, vars, i); } else { mstring_append_fmt(vars, "vec4 t%d = textureProj(texSamp%d, pT%d.xyw);\n", i, i, i); @@ -1011,8 +964,8 @@ static MString* psh_convert(struct PixelShader *ps) mstring_append_fmt(vars, "dsdt%d = bumpMat%d * dsdt%d;\n", i, i, i, i); - mstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, texScale%d * (pT%d.xy + dsdt%d));\n", - i, i, i, i, i); + mstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, (pT%d.xy + dsdt%d));\n", + i, i, i, i); break; case PS_TEXTUREMODES_BUMPENVMAP_LUM: assert(i >= 1); @@ -1029,8 +982,8 @@ static MString* psh_convert(struct PixelShader *ps) mstring_append_fmt(vars, "dsdtl%d.st = bumpMat%d * dsdtl%d.st;\n", i, i, i, i); - mstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, texScale%d * (pT%d.xy + dsdtl%d.st));\n", - i, i, i, i, i); + mstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, (pT%d.xy + dsdtl%d.st));\n", + i, i, i, i); mstring_append_fmt(vars, "t%d = t%d * (bumpScale%d * dsdtl%d.p + bumpOffset%d);\n", i, i, i, i, i); break; @@ -1049,8 +1002,8 @@ static MString* psh_convert(struct PixelShader *ps) i, i, dotmap_func, ps->input_tex[i], i, i-1, i); apply_border_adjustment(ps, vars, i, "dotST%d"); - mstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, texScale%d * dotST%d);\n", - i, i, i, i); + mstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, dotST%d);\n", + i, i, i); break; case PS_TEXTUREMODES_DOT_ZW: assert(i >= 2); @@ -1272,7 +1225,6 @@ MString *pgraph_gen_psh_glsl(const PshState state) ps.flags = state.combiner_control >> 8; for (i = 0; i < 4; i++) { ps.tex_modes[i] = (state.shader_stage_program >> (i * 5)) & 0x1F; - ps.tex_modes[i] = correct_texture_mode_for_dimensionality(ps.tex_modes[i], &state, i); } ps.dot_map[0] = 0; diff --git a/hw/xbox/nv2a/pgraph/vk/texture.c b/hw/xbox/nv2a/pgraph/vk/texture.c index 726350213ee..f74f5c0c4f4 100644 --- a/hw/xbox/nv2a/pgraph/vk/texture.c +++ b/hw/xbox/nv2a/pgraph/vk/texture.c @@ -1305,12 +1305,6 @@ static void create_texture(PGRAPHState *pg, int texture_idx) if (is_linear_filter_supported_for_format(r, state.color_format)) { vk_mag_filter = pgraph_texture_min_filter_vk_map[mag_filter]; vk_min_filter = pgraph_texture_min_filter_vk_map[min_filter]; - - if (f_basic.linear && vk_mag_filter != vk_min_filter) { - // FIXME: Per spec, if coordinates unnormalized, filters must be - // same. - vk_mag_filter = vk_min_filter = VK_FILTER_LINEAR; - } } else { vk_mag_filter = vk_min_filter = VK_FILTER_NEAREST; } @@ -1343,7 +1337,6 @@ static void create_texture(PGRAPHState *pg, int texture_idx) // .anisotropyEnable = VK_TRUE, // .maxAnisotropy = properties.limits.maxSamplerAnisotropy, .borderColor = vk_border_color, - .unnormalizedCoordinates = f_basic.linear ? VK_TRUE : VK_FALSE, .compareEnable = VK_FALSE, .compareOp = VK_COMPARE_OP_ALWAYS, .mipmapMode = mipmap_nearest ? VK_SAMPLER_MIPMAP_MODE_NEAREST :