From 8c18331afeca37271616a31b94359c6e3e8f907e Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Fri, 20 Dec 2019 15:56:08 +0100 Subject: [PATCH] zink: implement txf texelFetch is a requirement for OpenGL 3.0, so this gets us a step closer to GL 3.0 support. Reviewed-by: Alyssa Rosenzweig --- .../drivers/zink/nir_to_spirv/nir_to_spirv.c | 40 ++++++++++++++++----- .../drivers/zink/nir_to_spirv/spirv_builder.c | 42 ++++++++++++++++++++++ .../drivers/zink/nir_to_spirv/spirv_builder.h | 11 ++++++ 3 files changed, 85 insertions(+), 8 deletions(-) diff --git a/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c b/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c index e118823..e027058 100644 --- a/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c +++ b/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c @@ -1319,13 +1319,23 @@ get_src_float(struct ntv_context *ctx, nir_src *src) return bitcast_to_fvec(ctx, def, bit_size, num_components); } +static SpvId +get_src_int(struct ntv_context *ctx, nir_src *src) +{ + SpvId def = get_src_uint(ctx, src); + unsigned num_components = nir_src_num_components(*src); + unsigned bit_size = nir_src_bit_size(*src); + return bitcast_to_ivec(ctx, def, bit_size, num_components); +} + static void emit_tex(struct ntv_context *ctx, nir_tex_instr *tex) { assert(tex->op == nir_texop_tex || tex->op == nir_texop_txb || tex->op == nir_texop_txl || - tex->op == nir_texop_txd); + tex->op == nir_texop_txd || + tex->op == nir_texop_txf); assert(nir_alu_type_get_base_type(tex->dest_type) == nir_type_float); assert(tex->texture_index == tex->sampler_index); @@ -1334,7 +1344,10 @@ emit_tex(struct ntv_context *ctx, nir_tex_instr *tex) for (unsigned i = 0; i < tex->num_srcs; i++) { switch (tex->src[i].src_type) { case nir_tex_src_coord: - coord = get_src_float(ctx, &tex->src[i].src); + if (tex->op == nir_texop_txf) + coord = get_src_int(ctx, &tex->src[i].src); + else + coord = get_src_float(ctx, &tex->src[i].src); coord_components = nir_src_num_components(tex->src[i].src); break; @@ -1352,7 +1365,10 @@ emit_tex(struct ntv_context *ctx, nir_tex_instr *tex) case nir_tex_src_lod: assert(nir_src_num_components(tex->src[i].src) == 1); - lod = get_src_float(ctx, &tex->src[i].src); + if (tex->op == nir_texop_txf) + lod = get_src_int(ctx, &tex->src[i].src); + else + lod = get_src_float(ctx, &tex->src[i].src); assert(lod != 0); break; @@ -1425,11 +1441,19 @@ emit_tex(struct ntv_context *ctx, nir_tex_instr *tex) if (dref) actual_dest_type = float_type; - SpvId result = spirv_builder_emit_image_sample(&ctx->builder, - actual_dest_type, load, - coord, - proj != 0, - lod, bias, dref, dx, dy); + SpvId result; + if (tex->op == nir_texop_txf) { + SpvId image = spirv_builder_emit_image(&ctx->builder, image_type, load); + result = spirv_builder_emit_image_fetch(&ctx->builder, dest_type, + image, coord, lod); + } else { + result = spirv_builder_emit_image_sample(&ctx->builder, + actual_dest_type, load, + coord, + proj != 0, + lod, bias, dref, dx, dy); + } + spirv_builder_emit_decoration(&ctx->builder, result, SpvDecorationRelaxedPrecision); diff --git a/src/gallium/drivers/zink/nir_to_spirv/spirv_builder.c b/src/gallium/drivers/zink/nir_to_spirv/spirv_builder.c index 275f81e..43a4a55 100644 --- a/src/gallium/drivers/zink/nir_to_spirv/spirv_builder.c +++ b/src/gallium/drivers/zink/nir_to_spirv/spirv_builder.c @@ -566,6 +566,48 @@ spirv_builder_emit_image_sample(struct spirv_builder *b, } SpvId +spirv_builder_emit_image(struct spirv_builder *b, SpvId result_type, + SpvId sampled_image) +{ + SpvId result = spirv_builder_new_id(b); + spirv_buffer_prepare(&b->instructions, 4); + spirv_buffer_emit_word(&b->instructions, SpvOpImage | (4 << 16)); + spirv_buffer_emit_word(&b->instructions, result_type); + spirv_buffer_emit_word(&b->instructions, result); + spirv_buffer_emit_word(&b->instructions, sampled_image); + return result; +} + +SpvId +spirv_builder_emit_image_fetch(struct spirv_builder *b, + SpvId result_type, + SpvId image, + SpvId coordinate, + SpvId lod) +{ + SpvId result = spirv_builder_new_id(b); + + SpvId extra_operands[2]; + int num_extra_operands = 0; + if (lod) { + extra_operands[0] = SpvImageOperandsLodMask; + extra_operands[1] = lod; + num_extra_operands = 2; + } + + spirv_buffer_prepare(&b->instructions, 5 + num_extra_operands); + spirv_buffer_emit_word(&b->instructions, SpvOpImageFetch | + ((5 + num_extra_operands) << 16)); + spirv_buffer_emit_word(&b->instructions, result_type); + spirv_buffer_emit_word(&b->instructions, result); + spirv_buffer_emit_word(&b->instructions, image); + spirv_buffer_emit_word(&b->instructions, coordinate); + for (int i = 0; i < num_extra_operands; ++i) + spirv_buffer_emit_word(&b->instructions, extra_operands[i]); + return result; +} + +SpvId spirv_builder_emit_ext_inst(struct spirv_builder *b, SpvId result_type, SpvId set, uint32_t instruction, const SpvId *args, size_t num_args) diff --git a/src/gallium/drivers/zink/nir_to_spirv/spirv_builder.h b/src/gallium/drivers/zink/nir_to_spirv/spirv_builder.h index 736eb21..d7213d8 100644 --- a/src/gallium/drivers/zink/nir_to_spirv/spirv_builder.h +++ b/src/gallium/drivers/zink/nir_to_spirv/spirv_builder.h @@ -218,6 +218,17 @@ spirv_builder_emit_image_sample(struct spirv_builder *b, SpvId dy); SpvId +spirv_builder_emit_image(struct spirv_builder *b, SpvId result_type, + SpvId sampled_image); + +SpvId +spirv_builder_emit_image_fetch(struct spirv_builder *b, + SpvId result_type, + SpvId image, + SpvId coordinate, + SpvId lod); + +SpvId spirv_builder_emit_ext_inst(struct spirv_builder *b, SpvId result_type, SpvId set, uint32_t instruction, const SpvId args[], size_t num_args); -- 2.7.4