Path: blob/21.2-virgl/src/panfrost/lib/pan_blend.c
4560 views
/*1* Copyright (C) 2018 Alyssa Rosenzweig2* Copyright (C) 2019-2021 Collabora, Ltd.3*4* Permission is hereby granted, free of charge, to any person obtaining a5* copy of this software and associated documentation files (the "Software"),6* to deal in the Software without restriction, including without limitation7* the rights to use, copy, modify, merge, publish, distribute, sublicense,8* and/or sell copies of the Software, and to permit persons to whom the9* Software is furnished to do so, subject to the following conditions:10*11* The above copyright notice and this permission notice (including the next12* paragraph) shall be included in all copies or substantial portions of the13* Software.14*15* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR16* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,17* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL18* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER19* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,20* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE21* SOFTWARE.22*/2324#include "pan_blend.h"25#include "pan_shader.h"26#include "pan_texture.h"27#include "panfrost/util/pan_lower_framebuffer.h"28#include "util/format/u_format.h"29#include "compiler/nir/nir.h"30#include "compiler/nir/nir_builder.h"31#include "compiler/nir/nir_conversion_builder.h"32#include "compiler/nir/nir_lower_blend.h"3334/* Blending is shared across all supported Malis with only minor differences,35* so pin a particular version */36#define ARCH 737#include <midgard_pack.h>3839/* Fixed function blending */4041static bool42factor_is_supported(enum blend_factor factor)43{44return factor != BLEND_FACTOR_SRC_ALPHA_SATURATE &&45factor != BLEND_FACTOR_SRC1_COLOR &&46factor != BLEND_FACTOR_SRC1_ALPHA;47}4849static bool50can_fixed_function_equation(enum blend_func blend_func,51enum blend_factor src_factor,52enum blend_factor dest_factor)53{54if (blend_func != BLEND_FUNC_ADD &&55blend_func != BLEND_FUNC_SUBTRACT &&56blend_func != BLEND_FUNC_REVERSE_SUBTRACT)57return false;5859if (!factor_is_supported(src_factor) ||60!factor_is_supported(dest_factor))61return false;6263if (src_factor != dest_factor &&64src_factor != BLEND_FACTOR_ZERO &&65dest_factor != BLEND_FACTOR_ZERO)66return false;6768return true;69}7071static unsigned72blend_factor_constant_mask(enum blend_factor factor)73{74unsigned mask = 0;7576if (factor == BLEND_FACTOR_CONSTANT_COLOR)77mask |= 0b0111; /* RGB */78else if (factor == BLEND_FACTOR_CONSTANT_ALPHA)79mask |= 0b1000; /* A */8081return mask;82}8384unsigned85pan_blend_constant_mask(const struct pan_blend_equation eq)86{87return blend_factor_constant_mask(eq.rgb_src_factor) |88blend_factor_constant_mask(eq.rgb_dst_factor) |89blend_factor_constant_mask(eq.alpha_src_factor) |90blend_factor_constant_mask(eq.alpha_dst_factor);91}9293/* Only "homogenous" (scalar or vector with all components equal) constants are94* valid for fixed-function, so check for this condition */9596bool97pan_blend_is_homogenous_constant(unsigned mask, const float *constants)98{99float constant = pan_blend_get_constant(mask, constants);100101u_foreach_bit(i, mask) {102if (constants[i] != constant)103return false;104}105106return true;107}108109/* Determines if an equation can run in fixed function */110111bool112pan_blend_can_fixed_function(const struct pan_blend_equation equation)113{114return !equation.blend_enable ||115(can_fixed_function_equation(equation.rgb_func,116equation.rgb_src_factor,117equation.rgb_dst_factor) &&118can_fixed_function_equation(equation.alpha_func,119equation.alpha_src_factor,120equation.alpha_dst_factor));121}122123static enum mali_blend_operand_c124to_c_factor(enum blend_factor factor)125{126switch (factor) {127case BLEND_FACTOR_ZERO:128return MALI_BLEND_OPERAND_C_ZERO;129130case BLEND_FACTOR_SRC_ALPHA:131return MALI_BLEND_OPERAND_C_SRC_ALPHA;132133case BLEND_FACTOR_DST_ALPHA:134return MALI_BLEND_OPERAND_C_DEST_ALPHA;135136case BLEND_FACTOR_SRC_COLOR:137return MALI_BLEND_OPERAND_C_SRC;138139case BLEND_FACTOR_DST_COLOR:140return MALI_BLEND_OPERAND_C_DEST;141142case BLEND_FACTOR_CONSTANT_COLOR:143case BLEND_FACTOR_CONSTANT_ALPHA:144return MALI_BLEND_OPERAND_C_CONSTANT;145146default:147unreachable("Unsupported blend factor");148}149}150151static void152to_panfrost_function(enum blend_func blend_func,153enum blend_factor src_factor,154bool invert_src,155enum blend_factor dest_factor,156bool invert_dest,157struct MALI_BLEND_FUNCTION *function)158{159assert(can_fixed_function_equation(blend_func, src_factor, dest_factor));160161if (src_factor == BLEND_FACTOR_ZERO && !invert_src) {162function->a = MALI_BLEND_OPERAND_A_ZERO;163function->b = MALI_BLEND_OPERAND_B_DEST;164if (blend_func == BLEND_FUNC_SUBTRACT)165function->negate_b = true;166function->invert_c = invert_dest;167function->c = to_c_factor(dest_factor);168} else if (src_factor == BLEND_FACTOR_ZERO && invert_src) {169function->a = MALI_BLEND_OPERAND_A_SRC;170function->b = MALI_BLEND_OPERAND_B_DEST;171if (blend_func == BLEND_FUNC_SUBTRACT)172function->negate_b = true;173else if (blend_func == BLEND_FUNC_REVERSE_SUBTRACT)174function->negate_a = true;175function->invert_c = invert_dest;176function->c = to_c_factor(dest_factor);177} else if (dest_factor == BLEND_FACTOR_ZERO && !invert_dest) {178function->a = MALI_BLEND_OPERAND_A_ZERO;179function->b = MALI_BLEND_OPERAND_B_SRC;180if (blend_func == BLEND_FUNC_REVERSE_SUBTRACT)181function->negate_b = true;182function->invert_c = invert_src;183function->c = to_c_factor(src_factor);184} else if (dest_factor == BLEND_FACTOR_ZERO && invert_dest) {185function->a = MALI_BLEND_OPERAND_A_DEST;186function->b = MALI_BLEND_OPERAND_B_SRC;187if (blend_func == BLEND_FUNC_SUBTRACT)188function->negate_a = true;189else if (blend_func == BLEND_FUNC_REVERSE_SUBTRACT)190function->negate_b = true;191function->invert_c = invert_src;192function->c = to_c_factor(src_factor);193} else if (src_factor == dest_factor && invert_src == invert_dest) {194function->a = MALI_BLEND_OPERAND_A_ZERO;195function->invert_c = invert_src;196function->c = to_c_factor(src_factor);197198switch (blend_func) {199case BLEND_FUNC_ADD:200function->b = MALI_BLEND_OPERAND_B_SRC_PLUS_DEST;201break;202case BLEND_FUNC_REVERSE_SUBTRACT:203function->negate_b = true;204FALLTHROUGH;205case BLEND_FUNC_SUBTRACT:206function->b = MALI_BLEND_OPERAND_B_SRC_MINUS_DEST;207break;208default:209unreachable("Invalid blend function");210}211} else {212assert(src_factor == dest_factor && invert_src != invert_dest);213214function->a = MALI_BLEND_OPERAND_A_DEST;215function->invert_c = invert_src;216function->c = to_c_factor(src_factor);217218switch (blend_func) {219case BLEND_FUNC_ADD:220function->b = MALI_BLEND_OPERAND_B_SRC_MINUS_DEST;221break;222case BLEND_FUNC_REVERSE_SUBTRACT:223function->b = MALI_BLEND_OPERAND_B_SRC_PLUS_DEST;224function->negate_b = true;225break;226case BLEND_FUNC_SUBTRACT:227function->b = MALI_BLEND_OPERAND_B_SRC_PLUS_DEST;228function->negate_a = true;229break;230default:231unreachable("Invalid blend function\n");232}233}234}235236bool237pan_blend_is_opaque(const struct pan_blend_equation equation)238{239return equation.rgb_src_factor == BLEND_FACTOR_ZERO &&240equation.rgb_invert_src_factor &&241equation.rgb_dst_factor == BLEND_FACTOR_ZERO &&242!equation.rgb_invert_dst_factor &&243(equation.rgb_func == BLEND_FUNC_ADD ||244equation.rgb_func == BLEND_FUNC_SUBTRACT) &&245equation.alpha_src_factor == BLEND_FACTOR_ZERO &&246equation.alpha_invert_src_factor &&247equation.alpha_dst_factor == BLEND_FACTOR_ZERO &&248!equation.alpha_invert_dst_factor &&249(equation.alpha_func == BLEND_FUNC_ADD ||250equation.alpha_func == BLEND_FUNC_SUBTRACT) &&251equation.color_mask == 0xf;252}253254static bool255is_dest_factor(enum blend_factor factor, bool alpha)256{257return factor == BLEND_FACTOR_DST_ALPHA ||258factor == BLEND_FACTOR_DST_COLOR ||259(factor == BLEND_FACTOR_SRC_ALPHA_SATURATE && !alpha);260}261262/* Determines if a blend equation reads back the destination. This can occur by263* explicitly referencing the destination in the blend equation, or by using a264* partial writemask. */265266bool267pan_blend_reads_dest(const struct pan_blend_equation equation)268{269return (equation.color_mask && equation.color_mask != 0xF) ||270is_dest_factor(equation.rgb_src_factor, false) ||271is_dest_factor(equation.alpha_src_factor, true) ||272equation.rgb_dst_factor != BLEND_FACTOR_ZERO ||273equation.rgb_invert_dst_factor ||274equation.alpha_dst_factor != BLEND_FACTOR_ZERO ||275equation.alpha_invert_dst_factor;276}277278/* Create the descriptor for a fixed blend mode given the corresponding API279* state. Assumes the equation can be represented as fixed-function. */280281void282pan_blend_to_fixed_function_equation(const struct pan_blend_equation equation,283struct MALI_BLEND_EQUATION *out)284{285/* If no blending is enabled, default back on `replace` mode */286if (!equation.blend_enable) {287out->color_mask = equation.color_mask;288out->rgb.a = MALI_BLEND_OPERAND_A_SRC;289out->rgb.b = MALI_BLEND_OPERAND_B_SRC;290out->rgb.c = MALI_BLEND_OPERAND_C_ZERO;291out->alpha.a = MALI_BLEND_OPERAND_A_SRC;292out->alpha.b = MALI_BLEND_OPERAND_B_SRC;293out->alpha.c = MALI_BLEND_OPERAND_C_ZERO;294return;295}296297/* Compile the fixed-function blend */298to_panfrost_function(equation.rgb_func,299equation.rgb_src_factor,300equation.rgb_invert_src_factor,301equation.rgb_dst_factor,302equation.rgb_invert_dst_factor,303&out->rgb);304305to_panfrost_function(equation.alpha_func,306equation.alpha_src_factor,307equation.alpha_invert_src_factor,308equation.alpha_dst_factor,309equation.alpha_invert_dst_factor,310&out->alpha);311out->color_mask = equation.color_mask;312}313314static const char *315logicop_str(enum pipe_logicop logicop)316{317switch (logicop) {318case PIPE_LOGICOP_CLEAR: return "clear";319case PIPE_LOGICOP_NOR: return "nor";320case PIPE_LOGICOP_AND_INVERTED: return "and-inverted";321case PIPE_LOGICOP_COPY_INVERTED: return "copy-inverted";322case PIPE_LOGICOP_AND_REVERSE: return "and-reverse";323case PIPE_LOGICOP_INVERT: return "invert";324case PIPE_LOGICOP_XOR: return "xor";325case PIPE_LOGICOP_NAND: return "nand";326case PIPE_LOGICOP_AND: return "and";327case PIPE_LOGICOP_EQUIV: return "equiv";328case PIPE_LOGICOP_NOOP: return "noop";329case PIPE_LOGICOP_OR_INVERTED: return "or-inverted";330case PIPE_LOGICOP_COPY: return "copy";331case PIPE_LOGICOP_OR_REVERSE: return "or-reverse";332case PIPE_LOGICOP_OR: return "or";333case PIPE_LOGICOP_SET: return "set";334default: unreachable("Invalid logicop\n");335}336}337338static void339get_equation_str(const struct pan_blend_rt_state *rt_state,340char *str, unsigned len)341{342const char *funcs[] = {343"add", "sub", "reverse_sub", "min", "max",344};345const char *factors[] = {346"zero", "src_color", "src1_color", "dst_color",347"src_alpha", "src1_alpha", "dst_alpha",348"const_color", "const_alpha", "src_alpha_sat",349};350int ret;351352if (!rt_state->equation.blend_enable) {353ret = snprintf(str, len, "replace");354assert(ret > 0);355return;356}357358if (rt_state->equation.color_mask & 7) {359assert(rt_state->equation.rgb_func < ARRAY_SIZE(funcs));360assert(rt_state->equation.rgb_src_factor < ARRAY_SIZE(factors));361assert(rt_state->equation.rgb_dst_factor < ARRAY_SIZE(factors));362ret = snprintf(str, len, "%s%s%s(func=%s,src_factor=%s%s,dst_factor=%s%s)%s",363(rt_state->equation.color_mask & 1) ? "R" : "",364(rt_state->equation.color_mask & 2) ? "G" : "",365(rt_state->equation.color_mask & 4) ? "B" : "",366funcs[rt_state->equation.rgb_func],367rt_state->equation.rgb_invert_src_factor ? "-" : "",368factors[rt_state->equation.rgb_src_factor],369rt_state->equation.rgb_invert_dst_factor ? "-" : "",370factors[rt_state->equation.rgb_dst_factor],371rt_state->equation.color_mask & 8 ? ";" : "");372assert(ret > 0);373str += ret;374len -= ret;375}376377if (rt_state->equation.color_mask & 8) {378assert(rt_state->equation.alpha_func < ARRAY_SIZE(funcs));379assert(rt_state->equation.alpha_src_factor < ARRAY_SIZE(factors));380assert(rt_state->equation.alpha_dst_factor < ARRAY_SIZE(factors));381ret = snprintf(str, len, "A(func=%s,src_factor=%s%s,dst_factor=%s%s)",382funcs[rt_state->equation.alpha_func],383rt_state->equation.alpha_invert_src_factor ? "-" : "",384factors[rt_state->equation.alpha_src_factor],385rt_state->equation.alpha_invert_dst_factor ? "-" : "",386factors[rt_state->equation.alpha_dst_factor]);387assert(ret > 0);388str += ret;389len -= ret;390}391}392393static bool394pan_inline_blend_constants(nir_builder *b, nir_instr *instr, void *data)395{396if (instr->type != nir_instr_type_intrinsic)397return false;398399nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);400if (intr->intrinsic != nir_intrinsic_load_blend_const_color_rgba)401return false;402403float *floats = data;404const nir_const_value constants[4] = {405{ .f32 = floats[0] },406{ .f32 = floats[1] },407{ .f32 = floats[2] },408{ .f32 = floats[3] }409};410411b->cursor = nir_after_instr(instr);412nir_ssa_def *constant = nir_build_imm(b, 4, 32, constants);413nir_ssa_def_rewrite_uses(&intr->dest.ssa, constant);414nir_instr_remove(instr);415return true;416}417418nir_shader *419pan_blend_create_shader(const struct panfrost_device *dev,420const struct pan_blend_state *state,421nir_alu_type src0_type,422nir_alu_type src1_type,423unsigned rt)424{425const struct pan_blend_rt_state *rt_state = &state->rts[rt];426char equation_str[128] = { 0 };427428get_equation_str(rt_state, equation_str, sizeof(equation_str));429430nir_builder b =431nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT,432pan_shader_get_compiler_options(dev),433"pan_blend(rt=%d,fmt=%s,nr_samples=%d,%s=%s)",434rt, util_format_name(rt_state->format),435rt_state->nr_samples,436state->logicop_enable ? "logicop" : "equation",437state->logicop_enable ?438logicop_str(state->logicop_func) : equation_str);439440const struct util_format_description *format_desc =441util_format_description(rt_state->format);442nir_alu_type nir_type = pan_unpacked_type_for_format(format_desc);443enum glsl_base_type glsl_type = nir_get_glsl_base_type_for_nir_type(nir_type);444445nir_lower_blend_options options = {446.logicop_enable = state->logicop_enable,447.logicop_func = state->logicop_func,448.rt[0].colormask = rt_state->equation.color_mask,449.format[0] = rt_state->format450};451452if (!rt_state->equation.blend_enable) {453static const nir_lower_blend_channel replace = {454.func = BLEND_FUNC_ADD,455.src_factor = BLEND_FACTOR_ZERO,456.invert_src_factor = true,457.dst_factor = BLEND_FACTOR_ZERO,458.invert_dst_factor = false,459};460461options.rt[0].rgb = replace;462options.rt[0].alpha = replace;463} else {464options.rt[0].rgb.func = rt_state->equation.rgb_func;465options.rt[0].rgb.src_factor = rt_state->equation.rgb_src_factor;466options.rt[0].rgb.invert_src_factor = rt_state->equation.rgb_invert_src_factor;467options.rt[0].rgb.dst_factor = rt_state->equation.rgb_dst_factor;468options.rt[0].rgb.invert_dst_factor = rt_state->equation.rgb_invert_dst_factor;469options.rt[0].alpha.func = rt_state->equation.alpha_func;470options.rt[0].alpha.src_factor = rt_state->equation.alpha_src_factor;471options.rt[0].alpha.invert_src_factor = rt_state->equation.alpha_invert_src_factor;472options.rt[0].alpha.dst_factor = rt_state->equation.alpha_dst_factor;473options.rt[0].alpha.invert_dst_factor = rt_state->equation.alpha_invert_dst_factor;474}475476nir_alu_type src_types[] = { src0_type ?: nir_type_float32, src1_type ?: nir_type_float32 };477478/* HACK: workaround buggy TGSI shaders (u_blitter) */479for (unsigned i = 0; i < ARRAY_SIZE(src_types); ++i) {480src_types[i] = nir_alu_type_get_base_type(nir_type) |481nir_alu_type_get_type_size(src_types[i]);482}483484nir_variable *c_src =485nir_variable_create(b.shader, nir_var_shader_in,486glsl_vector_type(nir_get_glsl_base_type_for_nir_type(src_types[0]), 4),487"gl_Color");488c_src->data.location = VARYING_SLOT_COL0;489nir_variable *c_src1 =490nir_variable_create(b.shader, nir_var_shader_in,491glsl_vector_type(nir_get_glsl_base_type_for_nir_type(src_types[1]), 4),492"gl_Color1");493c_src1->data.location = VARYING_SLOT_VAR0;494c_src1->data.driver_location = 1;495nir_variable *c_out =496nir_variable_create(b.shader, nir_var_shader_out,497glsl_vector_type(glsl_type, 4),498"gl_FragColor");499c_out->data.location = FRAG_RESULT_DATA0;500501nir_ssa_def *s_src[] = {nir_load_var(&b, c_src), nir_load_var(&b, c_src1)};502503/* Saturate integer conversions */504for (int i = 0; i < ARRAY_SIZE(s_src); ++i) {505nir_alu_type T = nir_alu_type_get_base_type(nir_type);506s_src[i] = nir_convert_with_rounding(&b, s_src[i],507src_types[i], nir_type,508nir_rounding_mode_undef,509T != nir_type_float);510}511512/* Build a trivial blend shader */513nir_store_var(&b, c_out, s_src[0], 0xFF);514515options.src1 = s_src[1];516517NIR_PASS_V(b.shader, nir_lower_blend, options);518nir_shader_instructions_pass(b.shader, pan_inline_blend_constants,519nir_metadata_block_index | nir_metadata_dominance,520(void *) state->constants);521522return b.shader;523}524525uint64_t526pan_blend_get_bifrost_desc(const struct panfrost_device *dev,527enum pipe_format fmt, unsigned rt,528unsigned force_size)529{530const struct util_format_description *desc = util_format_description(fmt);531uint64_t res;532533pan_pack(&res, BIFROST_INTERNAL_BLEND, cfg) {534cfg.mode = MALI_BIFROST_BLEND_MODE_OPAQUE;535cfg.fixed_function.num_comps = desc->nr_channels;536cfg.fixed_function.rt = rt;537538nir_alu_type T = pan_unpacked_type_for_format(desc);539540if (force_size)541T = nir_alu_type_get_base_type(T) | force_size;542543switch (T) {544case nir_type_float16:545cfg.fixed_function.conversion.register_format =546MALI_BIFROST_REGISTER_FILE_FORMAT_F16;547break;548case nir_type_float32:549cfg.fixed_function.conversion.register_format =550MALI_BIFROST_REGISTER_FILE_FORMAT_F32;551break;552case nir_type_int8:553case nir_type_int16:554cfg.fixed_function.conversion.register_format =555MALI_BIFROST_REGISTER_FILE_FORMAT_I16;556break;557case nir_type_int32:558cfg.fixed_function.conversion.register_format =559MALI_BIFROST_REGISTER_FILE_FORMAT_I32;560break;561case nir_type_uint8:562case nir_type_uint16:563cfg.fixed_function.conversion.register_format =564MALI_BIFROST_REGISTER_FILE_FORMAT_U16;565break;566case nir_type_uint32:567cfg.fixed_function.conversion.register_format =568MALI_BIFROST_REGISTER_FILE_FORMAT_U32;569break;570default:571unreachable("Invalid format");572}573574cfg.fixed_function.conversion.memory_format =575panfrost_format_to_bifrost_blend(dev, fmt);576}577578return res;579}580581struct pan_blend_shader_variant *582pan_blend_get_shader_locked(const struct panfrost_device *dev,583const struct pan_blend_state *state,584nir_alu_type src0_type,585nir_alu_type src1_type,586unsigned rt)587{588struct pan_blend_shader_key key = {589.format = state->rts[rt].format,590.src0_type = src0_type,591.src1_type = src1_type,592.rt = rt,593.has_constants = pan_blend_constant_mask(state->rts[rt].equation) != 0,594.logicop_enable = state->logicop_enable,595.logicop_func = state->logicop_func,596.nr_samples = state->rts[rt].nr_samples,597.equation = state->rts[rt].equation,598};599600struct hash_entry *he = _mesa_hash_table_search(dev->blend_shaders.shaders, &key);601struct pan_blend_shader *shader = he ? he->data : NULL;602603if (!shader) {604shader = rzalloc(dev->blend_shaders.shaders, struct pan_blend_shader);605shader->key = key;606list_inithead(&shader->variants);607_mesa_hash_table_insert(dev->blend_shaders.shaders, &shader->key, shader);608}609610list_for_each_entry(struct pan_blend_shader_variant, iter,611&shader->variants, node) {612if (!key.has_constants ||613!memcmp(iter->constants, state->constants, sizeof(iter->constants))) {614return iter;615}616}617618struct pan_blend_shader_variant *variant = NULL;619620if (shader->nvariants < PAN_BLEND_SHADER_MAX_VARIANTS) {621variant = rzalloc(shader, struct pan_blend_shader_variant);622memcpy(variant->constants, state->constants, sizeof(variant->constants));623util_dynarray_init(&variant->binary, variant);624list_add(&variant->node, &shader->variants);625shader->nvariants++;626} else {627variant = list_last_entry(&shader->variants, struct pan_blend_shader_variant, node);628list_del(&variant->node);629list_add(&variant->node, &shader->variants);630util_dynarray_clear(&variant->binary);631}632633nir_shader *nir = pan_blend_create_shader(dev, state, src0_type, src1_type, rt);634635/* Compile the NIR shader */636struct panfrost_compile_inputs inputs = {637.gpu_id = dev->gpu_id,638.is_blend = true,639.blend.rt = shader->key.rt,640.blend.nr_samples = key.nr_samples,641.rt_formats = { key.format },642};643644if (pan_is_bifrost(dev)) {645inputs.blend.bifrost_blend_desc =646pan_blend_get_bifrost_desc(dev, key.format, key.rt, 0);647}648649struct pan_shader_info info;650651pan_shader_compile(dev, nir, &inputs, &variant->binary, &info);652653variant->work_reg_count = info.work_reg_count;654if (!pan_is_bifrost(dev))655variant->first_tag = info.midgard.first_tag;656657ralloc_free(nir);658659return variant;660}661662static uint32_t pan_blend_shader_key_hash(const void *key)663{664return _mesa_hash_data(key, sizeof(struct pan_blend_shader_key));665}666667static bool pan_blend_shader_key_equal(const void *a, const void *b)668{669return !memcmp(a, b, sizeof(struct pan_blend_shader_key));670}671672void673pan_blend_shaders_init(struct panfrost_device *dev)674{675dev->blend_shaders.shaders =676_mesa_hash_table_create(NULL, pan_blend_shader_key_hash,677pan_blend_shader_key_equal);678pthread_mutex_init(&dev->blend_shaders.lock, NULL);679}680681void682pan_blend_shaders_cleanup(struct panfrost_device *dev)683{684_mesa_hash_table_destroy(dev->blend_shaders.shaders, NULL);685}686687688