diff --git a/hw/xbox/nv2a/pgraph/gl/renderer.h b/hw/xbox/nv2a/pgraph/gl/renderer.h index 28277fcdf53..1e55ce80ca2 100644 --- a/hw/xbox/nv2a/pgraph/gl/renderer.h +++ b/hw/xbox/nv2a/pgraph/gl/renderer.h @@ -73,6 +73,7 @@ typedef struct TextureBinding { unsigned int scale; unsigned int min_filter; unsigned int mag_filter; + uint32_t lod_bias; unsigned int addru; unsigned int addrv; unsigned int addrp; diff --git a/hw/xbox/nv2a/pgraph/gl/texture.c b/hw/xbox/nv2a/pgraph/gl/texture.c index 7622bf43691..ead8af51345 100644 --- a/hw/xbox/nv2a/pgraph/gl/texture.c +++ b/hw/xbox/nv2a/pgraph/gl/texture.c @@ -117,6 +117,8 @@ static void apply_texture_parameters(TextureBinding *binding, { unsigned int min_filter = GET_MASK(filter, NV_PGRAPH_TEXFILTER0_MIN); unsigned int mag_filter = GET_MASK(filter, NV_PGRAPH_TEXFILTER0_MAG); + unsigned int lod_bias = + GET_MASK(filter, NV_PGRAPH_TEXFILTER0_MIPMAP_LOD_BIAS); 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); @@ -146,6 +148,11 @@ static void apply_texture_parameters(TextureBinding *binding, pgraph_texture_mag_filter_gl_map[mag_filter]); binding->mag_filter = mag_filter; } + if (lod_bias != binding->lod_bias) { + binding->lod_bias = lod_bias; + glTexParameterf(binding->gl_target, GL_TEXTURE_LOD_BIAS, + pgraph_convert_lod_bias_to_float(lod_bias)); + } /* Texture wrapping */ assert(addru < ARRAY_SIZE(pgraph_texture_addr_gl_map)); @@ -727,6 +734,7 @@ static TextureBinding* generate_texture(const TextureShape s, ret->data_hash = 0; ret->min_filter = 0xFFFFFFFF; ret->mag_filter = 0xFFFFFFFF; + ret->lod_bias = 0xFFFFFFFF; ret->addru = 0xFFFFFFFF; ret->addrv = 0xFFFFFFFF; ret->addrp = 0xFFFFFFFF; diff --git a/hw/xbox/nv2a/pgraph/texture.h b/hw/xbox/nv2a/pgraph/texture.h index 4c9818ca3cc..343bcf0e3b2 100644 --- a/hw/xbox/nv2a/pgraph/texture.h +++ b/hw/xbox/nv2a/pgraph/texture.h @@ -64,4 +64,13 @@ hwaddr pgraph_get_texture_palette_phys_addr_length(PGRAPHState *pg, int texture_ TextureShape pgraph_get_texture_shape(PGRAPHState *pg, int texture_idx); size_t pgraph_get_texture_length(PGRAPHState *pg, TextureShape *shape); +static inline float pgraph_convert_lod_bias_to_float(uint32_t lod_bias) +{ + int sign_extended_bias = lod_bias; + if (lod_bias & (1 << 12)) { + sign_extended_bias |= ~NV_PGRAPH_TEXFILTER0_MIPMAP_LOD_BIAS; + } + return (float)sign_extended_bias / 256.f; +} + #endif diff --git a/hw/xbox/nv2a/pgraph/vk/texture.c b/hw/xbox/nv2a/pgraph/vk/texture.c index efaefaafab3..551ea7376c6 100644 --- a/hw/xbox/nv2a/pgraph/vk/texture.c +++ b/hw/xbox/nv2a/pgraph/vk/texture.c @@ -1336,6 +1336,14 @@ static void create_texture(PGRAPHState *pg, int texture_idx) min_filter == NV_PGRAPH_TEXFILTER0_MIN_BOX_NEARESTLOD || min_filter == NV_PGRAPH_TEXFILTER0_MIN_TENT_NEARESTLOD; + float lod_bias = pgraph_convert_lod_bias_to_float( + GET_MASK(filter, NV_PGRAPH_TEXFILTER0_MIPMAP_LOD_BIAS)); + if (lod_bias > r->device_props.limits.maxSamplerLodBias) { + lod_bias = r->device_props.limits.maxSamplerLodBias; + } else if (lod_bias < -r->device_props.limits.maxSamplerLodBias) { + lod_bias = -r->device_props.limits.maxSamplerLodBias; + } + VkSamplerCreateInfo sampler_create_info = { .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, .magFilter = vk_mag_filter, @@ -1356,7 +1364,7 @@ static void create_texture(PGRAPHState *pg, int texture_idx) VK_SAMPLER_MIPMAP_MODE_LINEAR, .minLod = mipmap_en ? MIN(state.min_mipmap_level, state.levels - 1) : 0.0, .maxLod = mipmap_en ? MIN(state.max_mipmap_level, state.levels - 1) : 0.0, - .mipLodBias = 0.0, + .mipLodBias = lod_bias, .pNext = sampler_next_struct, };