llvmpipe: Implement 64-bit image operations

LLVM has support and everything should be in place to support them.
There are just a few 32-bit assumptions that have to be removed.

Reviewed-by: Mike Blumenkrantz <michael.blumenkrantz@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33628>
This commit is contained in:
Konstantin Seurer 2025-01-30 17:34:34 +01:00 committed by Marge Bot
parent d49de8f10a
commit c05e42eaea
11 changed files with 176 additions and 70 deletions

View file

@ -314,8 +314,7 @@ lp_build_unpack_rgba_soa(struct gallivm_state *gallivm,
assert(format_desc->block.width == 1);
assert(format_desc->block.height == 1);
assert(format_desc->block.bits <= type.width);
/* FIXME: Support more output types */
assert(type.width == 32);
assert(type.width >= 32);
lp_build_context_init(&bld, gallivm, type);
@ -427,6 +426,24 @@ lp_build_fetch_rgba_soa(struct gallivm_state *gallivm,
enum pipe_format format = format_desc->format;
struct lp_type fetch_type;
if (util_format_is_int64(format_desc)) {
uint32_t c = 0;
for (; c < format_desc->nr_channels; c++) {
LLVMValueRef channel_offset =
LLVMBuildAdd(builder, offset, lp_build_const_int_vec(gallivm, lp_type_uint_vec(32, 32 * type.length), c * 8), "");
rgba_out[c] =
lp_build_gather(gallivm, type.length, format_desc->channel[c].size, lp_type_uint(type.width),
aligned, base_ptr, channel_offset, false);
}
for (; c < 4; c++) {
if (c == 3)
rgba_out[c] = lp_build_one(gallivm, type);
else
rgba_out[c] = lp_build_zero(gallivm, type);
}
return;
}
if (format_desc->layout == UTIL_FORMAT_LAYOUT_PLAIN &&
(format_desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
format_desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB ||
@ -992,7 +1009,6 @@ lp_build_pack_rgba_soa(struct gallivm_state *gallivm,
assert(format_desc->block.width == 1);
assert(format_desc->block.height == 1);
assert(format_desc->block.bits <= type.width);
/* FIXME: Support more output types */
assert(type.width == 32);
lp_build_context_init(&bld, gallivm, type);
@ -1024,7 +1040,11 @@ lp_build_store_rgba_soa(struct gallivm_state *gallivm,
unsigned num_stores = 0;
memset(packed, 0, sizeof(LLVMValueRef) * 4);
if (format_desc->layout == UTIL_FORMAT_LAYOUT_PLAIN &&
if (util_format_is_int64(format_desc)) {
memcpy(packed, rgba_in, sizeof(packed));
num_stores = format_desc->nr_channels;
} else if (format_desc->layout == UTIL_FORMAT_LAYOUT_PLAIN &&
format_desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB &&
!util_format_is_alpha(format) &&
format_desc->block.width == 1 &&
@ -1096,6 +1116,7 @@ lp_build_store_rgba_soa(struct gallivm_state *gallivm,
assert(exec_mask);
LLVMTypeRef int64_ptr_type = LLVMPointerType(LLVMInt64TypeInContext(gallivm->context), 0);
LLVMTypeRef int32_ptr_type = LLVMPointerType(LLVMInt32TypeInContext(gallivm->context), 0);
LLVMTypeRef int16_ptr_type = LLVMPointerType(LLVMInt16TypeInContext(gallivm->context), 0);
LLVMTypeRef int8_ptr_type = LLVMPointerType(LLVMInt8TypeInContext(gallivm->context), 0);
@ -1123,8 +1144,11 @@ lp_build_store_rgba_soa(struct gallivm_state *gallivm,
} else if (format_desc->block.bits == 16) {
this_offset = LLVMBuildBitCast(gallivm->builder, this_offset, int16_ptr_type, "");
data = LLVMBuildTrunc(gallivm->builder, data, LLVMInt16TypeInContext(gallivm->context), "");
} else
} else if (format_desc->block.bits == 32) {
this_offset = LLVMBuildBitCast(gallivm->builder, this_offset, int32_ptr_type, "");
} else {
this_offset = LLVMBuildBitCast(gallivm->builder, this_offset, int64_ptr_type, "");
}
LLVMBuildStore(gallivm->builder, data, this_offset);
lp_build_endif(&ifthen);
lp_build_loop_end_cond(&loop_state, lp_build_const_int32(gallivm, type.length),

View file

@ -472,7 +472,11 @@ lp_bld_llvm_image_soa_emit_op(const struct lp_build_image_soa *base,
gallivm, params->resource, offsetof(struct lp_descriptor, functions),
offsetof(struct lp_texture_functions, image_functions));
LLVMTypeRef image_function_type = lp_build_image_function_type(gallivm, params, params->ms_index);
uint32_t flags = params->packed_op / LP_IMAGE_OP_COUNT;
bool ms = flags & LP_IMAGE_OP_MS;
bool is64 = flags & LP_IMAGE_OP_64;
LLVMTypeRef image_function_type = lp_build_image_function_type(gallivm, params, ms, is64);
LLVMTypeRef image_function_ptr_type = LLVMPointerType(image_function_type, 0);
LLVMTypeRef image_functions_type = LLVMPointerType(image_function_ptr_type, 0);
LLVMTypeRef image_base_type = LLVMPointerType(image_functions_type, 0);
@ -480,16 +484,7 @@ lp_bld_llvm_image_soa_emit_op(const struct lp_build_image_soa *base,
image_base_ptr = LLVMBuildIntToPtr(builder, image_base_ptr, image_base_type, "");
LLVMValueRef image_functions = LLVMBuildLoad2(builder, image_functions_type, image_base_ptr, "");
uint32_t op = params->img_op;
if (op == LP_IMG_ATOMIC_CAS)
op--;
else if (op == LP_IMG_ATOMIC)
op = params->op + (LP_IMG_OP_COUNT - 1);
if (params->ms_index)
op += LP_TOTAL_IMAGE_OP_COUNT / 2;
LLVMValueRef function_index = lp_build_const_int32(gallivm, op);
LLVMValueRef function_index = lp_build_const_int32(gallivm, params->packed_op);
LLVMValueRef image_function_ptr = LLVMBuildGEP2(builder, image_function_ptr_type, image_functions, &function_index, 1, "");
LLVMValueRef image_function = LLVMBuildLoad2(builder, image_function_ptr_type, image_function_ptr, "");

View file

@ -65,10 +65,4 @@ lp_bld_llvm_image_soa_destroy(struct lp_build_image_soa *image)
FREE(image);
}
#if LLVM_VERSION_MAJOR >= 15
#define LP_TOTAL_IMAGE_OP_COUNT ((LP_IMG_OP_COUNT + LLVMAtomicRMWBinOpFMin) * 2)
#else
#define LP_TOTAL_IMAGE_OP_COUNT ((LP_IMG_OP_COUNT + 14) * 2)
#endif
#endif

View file

@ -842,7 +842,7 @@ lp_build_size_function_type(struct gallivm_state *gallivm,
LLVMTypeRef
lp_build_image_function_type(struct gallivm_state *gallivm,
const struct lp_img_params *params, bool ms)
const struct lp_img_params *params, bool ms, bool is64)
{
struct lp_type type;
memset(&type, 0, sizeof type);
@ -871,7 +871,11 @@ lp_build_image_function_type(struct gallivm_state *gallivm,
if (params->img_op == LP_IMG_ATOMIC_CAS)
num_inputs = 8;
const struct util_format_description *desc = util_format_description(params->format);
enum pipe_format format = params->format;
if (is64 && format == PIPE_FORMAT_NONE)
format = PIPE_FORMAT_R64G64B64A64_UINT;
const struct util_format_description *desc = util_format_description(format);
LLVMTypeRef component_type = lp_build_vec_type(gallivm, lp_build_texel_type(type, desc));
for (uint32_t i = 0; i < num_inputs; i++)

View file

@ -203,7 +203,8 @@ LLVMTypeRef lp_build_size_function_type(struct gallivm_state *gallivm,
const struct lp_sampler_size_query_params *params);
LLVMTypeRef lp_build_image_function_type(struct gallivm_state *gallivm,
const struct lp_img_params *params, bool ms);
const struct lp_img_params *params, bool ms,
bool is64);
struct lp_texture_functions {
void ***sample_functions;

View file

@ -97,6 +97,8 @@ lp_build_nir_sample_key(gl_shader_stage stage, nir_tex_instr *instr);
void lp_img_op_from_intrinsic(struct lp_img_params *params, nir_intrinsic_instr *instr);
uint32_t lp_packed_img_op_from_intrinsic(nir_intrinsic_instr *instr);
enum lp_nir_call_context_args {
LP_NIR_CALL_CONTEXT_CONTEXT,
LP_NIR_CALL_CONTEXT_RESOURCES,

View file

@ -4234,13 +4234,17 @@ visit_load_image(struct lp_build_nir_soa_context *bld,
params.coords = coords;
params.outdata = result;
lp_img_op_from_intrinsic(&params, instr);
params.packed_op = lp_packed_img_op_from_intrinsic(instr);
if (nir_intrinsic_image_dim(instr) == GLSL_SAMPLER_DIM_MS ||
nir_intrinsic_image_dim(instr) == GLSL_SAMPLER_DIM_SUBPASS_MS)
params.ms_index = cast_type(bld, get_src(bld, &instr->src[2], 0),
nir_type_uint, 32);
img_params_init_resource(bld, &params, &instr->src[0]);
params.format = nir_intrinsic_format(instr);
if (instr->def.bit_size == 64)
params.format = PIPE_FORMAT_R64G64B64A64_UINT;
emit_image_op(bld, &params);
}
@ -4265,6 +4269,8 @@ visit_store_image(struct lp_build_nir_soa_context *bld,
params.coords = coords;
params.format = nir_intrinsic_format(instr);
if (nir_src_bit_size(instr->src[3]) == 64)
params.format = PIPE_FORMAT_R64G64B64A64_UINT;
const struct util_format_description *desc = util_format_description(params.format);
bool integer = desc->channel[util_format_get_first_non_void_channel(params.format)].pure_integer;
@ -4272,14 +4278,20 @@ visit_store_image(struct lp_build_nir_soa_context *bld,
for (unsigned i = 0; i < 4; i++) {
params.indata[i] = in_val[i];
if (integer)
params.indata[i] = LLVMBuildBitCast(builder, params.indata[i], bld->int_bld.vec_type, "");
else
params.indata[i] = LLVMBuildBitCast(builder, params.indata[i], bld->base.vec_type, "");
if (nir_src_bit_size(instr->src[3]) == 64) {
assert(integer);
params.indata[i] = LLVMBuildBitCast(builder, params.indata[i], bld->int64_bld.vec_type, "");
} else {
if (integer)
params.indata[i] = LLVMBuildBitCast(builder, params.indata[i], bld->int_bld.vec_type, "");
else
params.indata[i] = LLVMBuildBitCast(builder, params.indata[i], bld->base.vec_type, "");
}
}
if (nir_intrinsic_image_dim(instr) == GLSL_SAMPLER_DIM_MS)
params.ms_index = get_src(bld, &instr->src[2], 0);
params.img_op = LP_IMG_STORE;
params.packed_op = lp_packed_img_op_from_intrinsic(instr);
img_params_init_resource(bld, &params, &instr->src[0]);
@ -4345,6 +4357,37 @@ lp_img_op_from_intrinsic(struct lp_img_params *params, nir_intrinsic_instr *inst
}
}
uint32_t
lp_packed_img_op_from_intrinsic(nir_intrinsic_instr *instr)
{
struct lp_img_params params;
lp_img_op_from_intrinsic(&params, instr);
if (params.img_op == -1)
return -1;
uint32_t op = params.img_op;
if (op == LP_IMG_ATOMIC_CAS)
op--;
else if (op == LP_IMG_ATOMIC)
op = params.op + (LP_IMG_OP_COUNT - 1);
uint32_t flags = 0;
if (nir_intrinsic_image_dim(instr) == GLSL_SAMPLER_DIM_MS ||
nir_intrinsic_image_dim(instr) == GLSL_SAMPLER_DIM_SUBPASS_MS)
flags |= LP_IMAGE_OP_MS;
if (params.img_op == LP_IMG_LOAD || params.img_op == LP_IMG_LOAD_SPARSE) {
if (instr->def.bit_size == 64)
flags |= LP_IMAGE_OP_64;
} else {
if (nir_src_bit_size(instr->src[3]) == 64)
flags |= LP_IMAGE_OP_64;
}
return op + flags * LP_IMAGE_OP_COUNT;
}
static void
visit_atomic_image(struct lp_build_nir_soa_context *bld,
nir_intrinsic_instr *instr,
@ -4369,6 +4412,8 @@ visit_atomic_image(struct lp_build_nir_soa_context *bld,
params.coords = coords;
params.format = nir_intrinsic_format(instr);
if (nir_src_bit_size(instr->src[3]) == 64)
params.format = PIPE_FORMAT_R64G64B64A64_UINT;
const struct util_format_description *desc = util_format_description(params.format);
bool integer = desc->channel[util_format_get_first_non_void_channel(params.format)].pure_integer;
@ -4376,28 +4421,33 @@ visit_atomic_image(struct lp_build_nir_soa_context *bld,
if (nir_intrinsic_image_dim(instr) == GLSL_SAMPLER_DIM_MS)
params.ms_index = get_src(bld, &instr->src[2], 0);
LLVMTypeRef indata_type = NULL;
if (nir_src_bit_size(instr->src[3]) == 64) {
assert(integer);
indata_type = bld->int64_bld.vec_type;
} else {
if (integer)
indata_type = bld->int_bld.vec_type;
else
indata_type = bld->base.vec_type;
}
if (instr->intrinsic == nir_intrinsic_image_atomic_swap ||
instr->intrinsic == nir_intrinsic_bindless_image_atomic_swap) {
LLVMValueRef cas_val = get_src(bld, &instr->src[4], 0);
params.indata[0] = in_val;
params.indata2[0] = cas_val;
if (integer)
params.indata2[0] = LLVMBuildBitCast(builder, params.indata2[0], bld->int_bld.vec_type, "");
else
params.indata2[0] = LLVMBuildBitCast(builder, params.indata2[0], bld->base.vec_type, "");
params.indata2[0] = LLVMBuildBitCast(builder, params.indata2[0], indata_type, "");
} else {
params.indata[0] = in_val;
}
if (integer)
params.indata[0] = LLVMBuildBitCast(builder, params.indata[0], bld->int_bld.vec_type, "");
else
params.indata[0] = LLVMBuildBitCast(builder, params.indata[0], bld->base.vec_type, "");
params.indata[0] = LLVMBuildBitCast(builder, params.indata[0], indata_type, "");
params.outdata = result;
lp_img_op_from_intrinsic(&params, instr);
params.packed_op = lp_packed_img_op_from_intrinsic(instr);
img_params_init_resource(bld, &params, &instr->src[0]);

View file

@ -156,6 +156,17 @@ struct lp_sampler_size_query_params
#define LP_IMG_ATOMIC_CAS 4
#define LP_IMG_OP_COUNT 5
#if LLVM_VERSION_MAJOR >= 15
#define LP_IMAGE_OP_COUNT (LP_IMG_OP_COUNT + LLVMAtomicRMWBinOpFMin)
#else
#define LP_IMAGE_OP_COUNT (LP_IMG_OP_COUNT + 14)
#endif
#define LP_IMAGE_OP_MS 1
#define LP_IMAGE_OP_64 2
#define LP_TOTAL_IMAGE_OP_COUNT (LP_IMAGE_OP_COUNT * 4)
struct lp_img_params
{
struct lp_type type;
@ -163,6 +174,7 @@ struct lp_img_params
LLVMValueRef image_index_offset;
unsigned img_op;
unsigned target;
unsigned packed_op;
LLVMAtomicRMWBinOp op;
LLVMValueRef exec_mask;
bool exec_mask_nz;

View file

@ -3114,6 +3114,10 @@ struct lp_type
lp_build_texel_type(struct lp_type texel_type,
const struct util_format_description *format_desc)
{
if (format_desc->channel[0].size == 64 && format_desc->block.width == 1 &&
format_desc->block.height == 1 && format_desc->block.depth == 1)
texel_type.width = 64;
/* always using the first channel hopefully should be safe,
* if not things WILL break in other places anyway.
*/
@ -3830,6 +3834,10 @@ lp_build_sample_soa_code(struct gallivm_state *gallivm,
if (!bld.texel_type.floating) {
unsigned chan;
for (chan = 0; chan < 4; chan++) {
if (bld.texel_type.width == 64) {
texel_out[chan] =
LLVMBuildTrunc(builder, texel_out[chan], lp_build_int_vec_type(gallivm, type), "");
}
texel_out[chan] = LLVMBuildBitCast(builder, texel_out[chan],
lp_build_vec_type(gallivm, type), "");
}
@ -4539,7 +4547,9 @@ lp_build_do_atomic_soa(struct gallivm_state *gallivm,
{
const enum pipe_format format = format_desc->format;
bool valid = format == PIPE_FORMAT_R32_UINT ||
bool valid = format == PIPE_FORMAT_R64_UINT ||
format == PIPE_FORMAT_R64_SINT ||
format == PIPE_FORMAT_R32_UINT ||
format == PIPE_FORMAT_R32_SINT ||
format == PIPE_FORMAT_R32_FLOAT;
@ -4581,6 +4591,10 @@ lp_build_do_atomic_soa(struct gallivm_state *gallivm,
LLVMTypeRef ref_type = (format == PIPE_FORMAT_R32_FLOAT) ?
LLVMFloatTypeInContext(gallivm->context) :
LLVMInt32TypeInContext(gallivm->context);
if (format_desc->block.bits == 64) {
assert(integer);
ref_type = LLVMInt64TypeInContext(gallivm->context);
}
LLVMTypeRef atom_res_elem_type =
LLVMVectorType(ref_type, type.length);

View file

@ -537,22 +537,28 @@ lp_storage_image_format_supported(enum pipe_format format)
case PIPE_FORMAT_R11G11B10_FLOAT:
case PIPE_FORMAT_R32_FLOAT:
case PIPE_FORMAT_R16_FLOAT:
case PIPE_FORMAT_R64G64B64A64_UINT:
case PIPE_FORMAT_R32G32B32A32_UINT:
case PIPE_FORMAT_R16G16B16A16_UINT:
case PIPE_FORMAT_R10G10B10A2_UINT:
case PIPE_FORMAT_R8G8B8A8_UINT:
case PIPE_FORMAT_R64G64_UINT:
case PIPE_FORMAT_R32G32_UINT:
case PIPE_FORMAT_R16G16_UINT:
case PIPE_FORMAT_R8G8_UINT:
case PIPE_FORMAT_R64_UINT:
case PIPE_FORMAT_R32_UINT:
case PIPE_FORMAT_R16_UINT:
case PIPE_FORMAT_R8_UINT:
case PIPE_FORMAT_R64G64B64A64_SINT:
case PIPE_FORMAT_R32G32B32A32_SINT:
case PIPE_FORMAT_R16G16B16A16_SINT:
case PIPE_FORMAT_R8G8B8A8_SINT:
case PIPE_FORMAT_R64G64_SINT:
case PIPE_FORMAT_R32G32_SINT:
case PIPE_FORMAT_R16G16_SINT:
case PIPE_FORMAT_R8G8_SINT:
case PIPE_FORMAT_R64_SINT:
case PIPE_FORMAT_R32_SINT:
case PIPE_FORMAT_R16_SINT:
case PIPE_FORMAT_R8_SINT:

View file

@ -278,30 +278,48 @@ compile_image_function(struct llvmpipe_context *ctx, struct lp_static_texture_st
if (desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS && !lp_storage_render_image_format_supported(texture->format))
return NULL;
bool ms = op >= LP_TOTAL_IMAGE_OP_COUNT / 2;
if (ms)
op -= LP_TOTAL_IMAGE_OP_COUNT / 2;
uint32_t flags = op / LP_IMAGE_OP_COUNT;
bool ms = flags & LP_IMAGE_OP_MS;
bool is64 = flags & LP_IMAGE_OP_64;
struct lp_img_params params = { 0 };
params.img_op = op;
if (op >= LP_IMG_OP_COUNT - 1) {
params.img_op = op % LP_IMAGE_OP_COUNT;
if (params.img_op >= LP_IMG_OP_COUNT - 1) {
params.op = params.img_op - (LP_IMG_OP_COUNT - 1);
params.img_op = LP_IMG_ATOMIC;
params.op = op - (LP_IMG_OP_COUNT - 1);
} else if (op != LP_IMG_LOAD && op != LP_IMG_LOAD_SPARSE && op != LP_IMG_STORE) {
} else if (params.img_op != LP_IMG_LOAD && params.img_op != LP_IMG_LOAD_SPARSE && params.img_op != LP_IMG_STORE) {
params.img_op = LP_IMG_ATOMIC_CAS;
}
struct lp_static_texture_state local_texture = *texture;
/* Rewrite rg32 stype formats as r64 for 64-bit atomics. */
if (params.img_op == LP_IMG_ATOMIC && is64) {
switch (local_texture.res_format) {
case PIPE_FORMAT_R32G32_SINT:
local_texture.format = PIPE_FORMAT_R64_SINT;
local_texture.res_format = PIPE_FORMAT_R64_SINT;
break;
case PIPE_FORMAT_R32G32_UINT:
local_texture.format = PIPE_FORMAT_R64_UINT;
local_texture.res_format = PIPE_FORMAT_R64_UINT;
break;
default:
/* Nothing to do. */
break;
}
}
/* Loads need to support a wider range of formats for input attachments. */
if (params.img_op != LP_IMG_LOAD)
if (texture->format != PIPE_FORMAT_NONE && !lp_storage_image_format_supported(texture->format))
if (local_texture.format != PIPE_FORMAT_NONE && !lp_storage_image_format_supported(local_texture.format))
return NULL;
uint8_t cache_key[SHA1_DIGEST_LENGTH];
struct mesa_sha1 hash_ctx;
_mesa_sha1_init(&hash_ctx);
_mesa_sha1_update(&hash_ctx, image_function_base_hash, strlen(image_function_base_hash));
_mesa_sha1_update(&hash_ctx, texture, sizeof(*texture));
_mesa_sha1_update(&hash_ctx, &local_texture, sizeof(local_texture));
_mesa_sha1_update(&hash_ctx, &op, sizeof(op));
_mesa_sha1_update(&hash_ctx, &ms, sizeof(ms));
_mesa_sha1_final(&hash_ctx, cache_key);
@ -313,7 +331,7 @@ compile_image_function(struct llvmpipe_context *ctx, struct lp_static_texture_st
struct gallivm_state *gallivm = gallivm_create("sample_function", get_llvm_context(ctx), &cached);
struct lp_image_static_state state = {
.image_state = *texture,
.image_state = local_texture,
};
struct lp_build_image_soa *image_soa = lp_bld_llvm_image_soa_create(&state, 1);
@ -329,11 +347,11 @@ compile_image_function(struct llvmpipe_context *ctx, struct lp_static_texture_st
lp_jit_init_cs_types(&cs);
params.type = type;
params.target = texture->target;
params.target = local_texture.target;
params.resources_type = cs.jit_resources_type;
params.format = texture->format;
params.format = local_texture.format;
LLVMTypeRef function_type = lp_build_image_function_type(gallivm, &params, ms);
LLVMTypeRef function_type = lp_build_image_function_type(gallivm, &params, ms, is64);
if (!function_type) {
free(image_soa);
gallivm_destroy(gallivm);
@ -373,7 +391,7 @@ compile_image_function(struct llvmpipe_context *ctx, struct lp_static_texture_st
LLVMPositionBuilderAtEnd(gallivm->builder, block);
LLVMValueRef outdata[5] = { 0 };
lp_build_img_op_soa(texture, lp_build_image_soa_dynamic_state(image_soa), gallivm, &params, outdata);
lp_build_img_op_soa(&local_texture, lp_build_image_soa_dynamic_state(image_soa), gallivm, &params, outdata);
for (uint32_t i = 1; i < 4; i++)
if (!outdata[i])
@ -1027,23 +1045,9 @@ register_instr(nir_builder *b, nir_instr *instr, void *data)
} else if (instr->type == nir_instr_type_intrinsic) {
nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
struct lp_img_params params;
lp_img_op_from_intrinsic(&params, intrin);
if (params.img_op == -1)
return false;
uint32_t op = params.img_op;
if (op == LP_IMG_ATOMIC_CAS)
op--;
else if (op == LP_IMG_ATOMIC)
op = params.op + (LP_IMG_OP_COUNT - 1);
if (nir_intrinsic_image_dim(intrin) == GLSL_SAMPLER_DIM_MS ||
nir_intrinsic_image_dim(intrin) == GLSL_SAMPLER_DIM_SUBPASS_MS)
op += LP_TOTAL_IMAGE_OP_COUNT / 2;
register_image_op(ctx, op);
uint32_t op = lp_packed_img_op_from_intrinsic(intrin);
if (op != -1)
register_image_op(ctx, op);
}
return false;