diff --git a/src/asahi/vulkan/hk_descriptor_set.c b/src/asahi/vulkan/hk_descriptor_set.c index b74ccd79b23..3781c06e7a7 100644 --- a/src/asahi/vulkan/hk_descriptor_set.c +++ b/src/asahi/vulkan/hk_descriptor_set.c @@ -6,6 +6,7 @@ */ #include "hk_descriptor_set.h" #include "asahi/lib/agx_bo.h" +#include "util/half_float.h" #include "vulkan/vulkan_core.h" #include "hk_buffer.h" @@ -73,6 +74,11 @@ write_sampled_image_view_desc(struct hk_descriptor_set *set, assert(index < (1 << 20)); desc[plane].image_offset = index * HK_IMAGE_STRIDE; + + float min_lod = MAX2(view->vk.min_lod - view->vk.base_mip_level, 0.0); + + desc[plane].min_lod_fp16 = _mesa_float_to_half(min_lod); + desc[plane].min_lod_uint16 = min_lod; } } diff --git a/src/asahi/vulkan/hk_descriptor_set.h b/src/asahi/vulkan/hk_descriptor_set.h index 9063ac7494a..5360d6ebd30 100644 --- a/src/asahi/vulkan/hk_descriptor_set.h +++ b/src/asahi/vulkan/hk_descriptor_set.h @@ -29,9 +29,17 @@ struct hk_sampled_image_descriptor { * for custom border colour emulation. */ int16_t clamp_0_sampler_index_or_negative; + + /* We want LOD bias and min LOD together as fp16 in this order and 32-bit + * aligned. This lets us keep everything vectorized on the shader side, since + * this matches the AGX2 lod_bias + min_lod descriptor. + */ uint16_t lod_bias_fp16; - uint16_t pad_; - uint32_t pad; + uint16_t min_lod_fp16; + + /* This is only used for txf, it can be separate from the other stuff */ + uint16_t min_lod_uint16; + uint16_t pad; /* TODO: This should probably be a heap! */ uint32_t border[4]; }; diff --git a/src/asahi/vulkan/hk_nir_lower_descriptors.c b/src/asahi/vulkan/hk_nir_lower_descriptors.c index 6cadb9c82cb..dd11b01ed4c 100644 --- a/src/asahi/vulkan/hk_nir_lower_descriptors.c +++ b/src/asahi/vulkan/hk_nir_lower_descriptors.c @@ -609,6 +609,23 @@ lower_tex(nir_builder *b, nir_tex_instr *tex, return true; } + if (tex->op == nir_texop_image_min_lod_agx) { + assert(tex->dest_type == nir_type_float16 || + tex->dest_type == nir_type_uint16); + + unsigned offs = + tex->dest_type == nir_type_float16 + ? offsetof(struct hk_sampled_image_descriptor, min_lod_fp16) + : offsetof(struct hk_sampled_image_descriptor, min_lod_uint16); + + nir_def *min = load_resource_deref_desc( + b, 1, 16, nir_src_as_deref(nir_src_for_ssa(texture)), + plane_offset_B + offs, ctx); + + nir_def_replace(&tex->def, min); + return true; + } + if (tex->op == nir_texop_has_custom_border_color_agx) { unsigned offs = offsetof(struct hk_sampled_image_descriptor, clamp_0_sampler_index_or_negative); diff --git a/src/asahi/vulkan/hk_shader.c b/src/asahi/vulkan/hk_shader.c index 5571cfcd0f1..48eaafcdfb5 100644 --- a/src/asahi/vulkan/hk_shader.c +++ b/src/asahi/vulkan/hk_shader.c @@ -11,6 +11,7 @@ #include "agx_helpers.h" #include "agx_nir_lower_gs.h" #include "glsl_types.h" +#include "libagx.h" #include "nir.h" #include "nir_builder.h" @@ -535,6 +536,82 @@ agx_nir_lower_custom_border(nir_shader *nir) return nir_shader_instructions_pass(nir, lower, nir_metadata_none, NULL); } +static nir_def * +query_min_lod(nir_builder *b, nir_tex_instr *tex, bool int_coords) +{ + nir_alu_type T = int_coords ? nir_type_uint16 : nir_type_float16; + return nir_build_texture_query(b, tex, nir_texop_image_min_lod_agx, 1, T, + false, false); +} + +static bool +lower_min_lod(nir_builder *b, nir_instr *instr, UNUSED void *_data) +{ + if (instr->type != nir_instr_type_tex) + return false; + + nir_tex_instr *tex = nir_instr_as_tex(instr); + if (nir_tex_instr_is_query(tex)) + return false; + + /* Buffer textures don't have levels-of-detail */ + if (tex->sampler_dim == GLSL_SAMPLER_DIM_BUF) + return false; + + if (tex->backend_flags & AGX_TEXTURE_FLAG_NO_CLAMP) + return false; + + bool int_coords = tex->op == nir_texop_txf || tex->op == nir_texop_txf_ms || + tex->op == nir_texop_tg4; + + b->cursor = nir_before_instr(&tex->instr); + nir_def *min_lod = query_min_lod(b, tex, int_coords); + nir_def *other_min_lod = nir_steal_tex_src(tex, nir_tex_src_min_lod); + + if (tex->op == nir_texop_tg4) { + b->cursor = nir_after_instr(&tex->instr); + + /* The Vulkan spec section "Texel Gathering" says: + * + * If levelbase < minLodIntegerimageView, then any values fetched are + * zero if the robustImageAccess2 feature is enabled. + * + * We currently always enable robustImageAccess2, so implement that + * semantic here. + * + * We could probably optimize this with a special descriptor for this case + * but tg4 is rare enough I'm not bothered. + */ + nir_def *old = &tex->def; + nir_def *oob = nir_ine_imm(b, min_lod, 0); + nir_def *zero = nir_imm_zero(b, old->num_components, old->bit_size); + nir_def *new_ = nir_bcsel(b, oob, zero, old); + nir_def_rewrite_uses_after(old, new_, new_->parent_instr); + } else if (tex->op == nir_texop_txl) { + assert(other_min_lod == NULL && "txl doesn't have an API min lod"); + + nir_def *lod = nir_steal_tex_src(tex, nir_tex_src_lod); + lod = lod ? nir_fmax(b, lod, min_lod) : min_lod; + nir_tex_instr_add_src(tex, nir_tex_src_lod, lod); + } else { + if (other_min_lod) { + assert(!int_coords && "no API min lod"); + min_lod = nir_fmax(b, min_lod, nir_f2f16(b, other_min_lod)); + } + + nir_tex_instr_add_src(tex, nir_tex_src_min_lod, min_lod); + } + + return true; +} + +static bool +agx_nir_lower_image_view_min_lod(nir_shader *nir) +{ + return nir_shader_instructions_pass(nir, lower_min_lod, nir_metadata_none, + NULL); +} + /* * In Vulkan, the VIEWPORT should read 0 in the fragment shader if it is not * written by the vertex shader, but in our implementation, the varying would @@ -651,6 +728,8 @@ hk_lower_nir(struct hk_device *dev, nir_shader *nir, */ NIR_PASS(_, nir, agx_nir_lower_texture_early, true /* support_lod_bias */); + NIR_PASS(_, nir, agx_nir_lower_image_view_min_lod); + if (!HK_PERF(dev, NOBORDER)) { NIR_PASS(_, nir, agx_nir_lower_custom_border); }