From 518208e8494bb0a6189b677fe8f3f693cab41826 Mon Sep 17 00:00:00 2001 From: Erik Abair Date: Thu, 25 Sep 2025 12:12:28 -0700 Subject: [PATCH] nv2a: Handle anisotropic filter setting --- hw/xbox/nv2a/nv2a_regs.h | 1 + hw/xbox/nv2a/pgraph/gl/renderer.c | 3 +++ hw/xbox/nv2a/pgraph/gl/renderer.h | 4 ++++ hw/xbox/nv2a/pgraph/gl/texture.c | 26 ++++++++++++++++++++------ hw/xbox/nv2a/pgraph/vk/instance.c | 9 +++++---- hw/xbox/nv2a/pgraph/vk/renderer.h | 1 + hw/xbox/nv2a/pgraph/vk/texture.c | 13 ++++++++++--- 7 files changed, 44 insertions(+), 13 deletions(-) diff --git a/hw/xbox/nv2a/nv2a_regs.h b/hw/xbox/nv2a/nv2a_regs.h index 39061c99a4..97fb4c4812 100644 --- a/hw/xbox/nv2a/nv2a_regs.h +++ b/hw/xbox/nv2a/nv2a_regs.h @@ -539,6 +539,7 @@ #define NV_PGRAPH_TEXCTL0_0 0x000019CC # define NV_PGRAPH_TEXCTL0_0_COLORKEYMODE 0x03 # define NV_PGRAPH_TEXCTL0_0_ALPHAKILLEN (1 << 2) +# define NV_PGRAPH_TEXCTL0_0_MAX_ANISOTROPY 0x30 # 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) diff --git a/hw/xbox/nv2a/pgraph/gl/renderer.c b/hw/xbox/nv2a/pgraph/gl/renderer.c index 36b8029439..f3764f397d 100644 --- a/hw/xbox/nv2a/pgraph/gl/renderer.c +++ b/hw/xbox/nv2a/pgraph/gl/renderer.c @@ -66,6 +66,9 @@ static void pgraph_gl_init(NV2AState *d, Error **errp) pg->uniform_attrs = 0; pg->swizzle_attrs = 0; + + r->supported_extensions.texture_filter_anisotropic = + glo_check_extension("GL_EXT_texture_filter_anisotropic"); } static void pgraph_gl_finalize(NV2AState *d) diff --git a/hw/xbox/nv2a/pgraph/gl/renderer.h b/hw/xbox/nv2a/pgraph/gl/renderer.h index 1e55ce80ca..d76e502c8c 100644 --- a/hw/xbox/nv2a/pgraph/gl/renderer.h +++ b/hw/xbox/nv2a/pgraph/gl/renderer.h @@ -234,6 +234,10 @@ typedef struct PGRAPHGLState { GLfloat supported_aliased_line_width_range[2]; GLfloat supported_smooth_line_width_range[2]; + + struct supported_extensions { + GLboolean texture_filter_anisotropic; + } supported_extensions; } PGRAPHGLState; extern GloContext *g_nv2a_context_render; diff --git a/hw/xbox/nv2a/pgraph/gl/texture.c b/hw/xbox/nv2a/pgraph/gl/texture.c index ead8af5134..eb0e4199fe 100644 --- a/hw/xbox/nv2a/pgraph/gl/texture.c +++ b/hw/xbox/nv2a/pgraph/gl/texture.c @@ -107,13 +107,15 @@ static bool check_texture_possibly_dirty(NV2AState *d, return possibly_dirty; } -static void apply_texture_parameters(TextureBinding *binding, +static void apply_texture_parameters(PGRAPHGLState *r, + TextureBinding *binding, const BasicColorFormatInfo *f, unsigned int dimensionality, unsigned int filter, unsigned int address, bool is_bordered, - uint32_t border_color) + uint32_t border_color, + uint32_t max_anisotropy) { unsigned int min_filter = GET_MASK(filter, NV_PGRAPH_TEXFILTER0_MIN); unsigned int mag_filter = GET_MASK(filter, NV_PGRAPH_TEXFILTER0_MAG); @@ -181,6 +183,11 @@ static void apply_texture_parameters(TextureBinding *binding, needs_border_color = needs_border_color || binding->addrp == NV_PGRAPH_TEXADDRESS0_ADDRU_BORDER; } + if (r->supported_extensions.texture_filter_anisotropic) { + glTexParameterf(binding->gl_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, + max_anisotropy); + } + if (!is_bordered && needs_border_color) { if (!binding->border_color_set || binding->border_color != border_color) { /* FIXME: Color channels might be wrong order */ @@ -219,6 +226,9 @@ void pgraph_gl_bind_textures(NV2AState *d) uint32_t filter = pgraph_reg_r(pg, NV_PGRAPH_TEXFILTER0 + i*4); uint32_t address = pgraph_reg_r(pg, NV_PGRAPH_TEXADDRESS0 + i*4); uint32_t border_color = pgraph_reg_r(pg, NV_PGRAPH_BORDERCOLOR0 + i*4); + uint32_t max_anisotropy = + 1 << (GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_TEXCTL0_0 + i*4), + NV_PGRAPH_TEXCTL0_0_MAX_ANISOTROPY)); /* Check for unsupported features */ if (filter & NV_PGRAPH_TEXFILTER0_ASIGNED) NV2A_UNIMPLEMENTED("NV_PGRAPH_TEXFILTER0_ASIGNED"); @@ -262,13 +272,15 @@ void pgraph_gl_bind_textures(NV2AState *d) if (reusable) { glBindTexture(r->texture_binding[i]->gl_target, r->texture_binding[i]->gl_texture); - apply_texture_parameters(r->texture_binding[i], + apply_texture_parameters(r, + r->texture_binding[i], &kelvin_color_format_info_map[state.color_format], state.dimensionality, filter, address, state.border, - border_color); + border_color, + max_anisotropy); continue; } } @@ -372,13 +384,15 @@ void pgraph_gl_bind_textures(NV2AState *d) binding->scale = pg->surface_scale_factor; } - apply_texture_parameters(binding, + apply_texture_parameters(r, + binding, &kelvin_color_format_info_map[state.color_format], state.dimensionality, filter, address, state.border, - border_color); + border_color, + max_anisotropy); if (r->texture_binding[i]) { if (r->texture_binding[i]->gl_target != binding->gl_target) { diff --git a/hw/xbox/nv2a/pgraph/vk/instance.c b/hw/xbox/nv2a/pgraph/vk/instance.c index 3d993cb735..088972cf26 100644 --- a/hw/xbox/nv2a/pgraph/vk/instance.c +++ b/hw/xbox/nv2a/pgraph/vk/instance.c @@ -540,12 +540,13 @@ static bool create_logical_device(PGRAPHState *pg, Error **errp) .enabled = &r->enabled_physical_device_features.n, \ .required = req, \ } - F(shaderClipDistance, true), - F(geometryShader, true), - F(shaderTessellationAndGeometryPointSize, true), F(depthClamp, true), - F(occlusionQueryPrecise, true), F(fillModeNonSolid, true), + F(geometryShader, true), + F(occlusionQueryPrecise, true), + F(samplerAnisotropy, false), + F(shaderClipDistance, true), + F(shaderTessellationAndGeometryPointSize, true), F(wideLines, false), #undef F // clang-format on diff --git a/hw/xbox/nv2a/pgraph/vk/renderer.h b/hw/xbox/nv2a/pgraph/vk/renderer.h index c2233a7b17..d68e2c4207 100644 --- a/hw/xbox/nv2a/pgraph/vk/renderer.h +++ b/hw/xbox/nv2a/pgraph/vk/renderer.h @@ -206,6 +206,7 @@ typedef struct TextureKey { uint32_t filter; uint32_t address; uint32_t border_color; + uint32_t max_anisotropy; } TextureKey; typedef struct TextureBinding { diff --git a/hw/xbox/nv2a/pgraph/vk/texture.c b/hw/xbox/nv2a/pgraph/vk/texture.c index 551ea7376c..b3686f87c0 100644 --- a/hw/xbox/nv2a/pgraph/vk/texture.c +++ b/hw/xbox/nv2a/pgraph/vk/texture.c @@ -1101,6 +1101,9 @@ static void create_texture(PGRAPHState *pg, int texture_idx) pgraph_reg_r(pg, NV_PGRAPH_BORDERCOLOR0 + texture_idx * 4); bool is_indexed = (state.color_format == NV097_SET_TEXTURE_FORMAT_COLOR_SZ_I8_A8R8G8B8); + uint32_t max_anisotropy = + 1 << (GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_TEXCTL0_0 + texture_idx*4), + NV_PGRAPH_TEXCTL0_0_MAX_ANISOTROPY)); TextureKey key; memset(&key, 0, sizeof(key)); @@ -1120,6 +1123,7 @@ static void create_texture(PGRAPHState *pg, int texture_idx) key.filter = filter; key.address = address; key.border_color = border_color_pack32; + key.max_anisotropy = max_anisotropy; bool possibly_dirty = false; bool possibly_dirty_checked = false; @@ -1343,6 +1347,8 @@ static void create_texture(PGRAPHState *pg, int texture_idx) } else if (lod_bias < -r->device_props.limits.maxSamplerLodBias) { lod_bias = -r->device_props.limits.maxSamplerLodBias; } + uint32_t sampler_max_anisotropy = + MIN(r->device_props.limits.maxSamplerAnisotropy, max_anisotropy); VkSamplerCreateInfo sampler_create_info = { .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, @@ -1354,9 +1360,10 @@ static void create_texture(PGRAPHState *pg, int texture_idx) GET_MASK(address, NV_PGRAPH_TEXADDRESS0_ADDRV)), .addressModeW = (state.dimensionality > 2) ? lookup_texture_address_mode( GET_MASK(address, NV_PGRAPH_TEXADDRESS0_ADDRP)) : 0, - .anisotropyEnable = VK_FALSE, - // .anisotropyEnable = VK_TRUE, - // .maxAnisotropy = properties.limits.maxSamplerAnisotropy, + .anisotropyEnable = + r->enabled_physical_device_features.samplerAnisotropy && + sampler_max_anisotropy > 1, + .maxAnisotropy = sampler_max_anisotropy, .borderColor = vk_border_color, .compareEnable = VK_FALSE, .compareOp = VK_COMPARE_OP_ALWAYS,