Path: blob/21.2-virgl/src/gallium/drivers/lima/lima_program.c
4565 views
/*1* Copyright (c) 2017-2019 Lima Project2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sub license,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the11* next paragraph) shall be included in all copies or substantial portions12* of the Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER20* DEALINGS IN THE SOFTWARE.21*22*/2324#include "util/u_memory.h"25#include "util/ralloc.h"26#include "util/u_debug.h"2728#include "tgsi/tgsi_dump.h"29#include "compiler/nir/nir.h"30#include "compiler/nir/nir_serialize.h"31#include "nir/tgsi_to_nir.h"3233#include "pipe/p_state.h"3435#include "lima_screen.h"36#include "lima_context.h"37#include "lima_job.h"38#include "lima_program.h"39#include "lima_bo.h"40#include "lima_disk_cache.h"4142#include "ir/lima_ir.h"4344static const nir_shader_compiler_options vs_nir_options = {45.lower_ffma16 = true,46.lower_ffma32 = true,47.lower_ffma64 = true,48.lower_fpow = true,49.lower_ffract = true,50.lower_fdiv = true,51.lower_fmod = true,52.lower_fsqrt = true,53.lower_flrp32 = true,54.lower_flrp64 = true,55/* could be implemented by clamp */56.lower_fsat = true,57.lower_bitops = true,58.lower_rotate = true,59.lower_sincos = true,60.lower_fceil = true,61.lower_insert_byte = true,62.lower_insert_word = true,63};6465static const nir_shader_compiler_options fs_nir_options = {66.lower_ffma16 = true,67.lower_ffma32 = true,68.lower_ffma64 = true,69.lower_fpow = true,70.lower_fdiv = true,71.lower_fmod = true,72.lower_flrp32 = true,73.lower_flrp64 = true,74.lower_fsign = true,75.lower_rotate = true,76.lower_fdot = true,77.lower_fdph = true,78.lower_insert_byte = true,79.lower_insert_word = true,80.lower_bitops = true,81.lower_vector_cmp = true,82};8384const void *85lima_program_get_compiler_options(enum pipe_shader_type shader)86{87switch (shader) {88case PIPE_SHADER_VERTEX:89return &vs_nir_options;90case PIPE_SHADER_FRAGMENT:91return &fs_nir_options;92default:93return NULL;94}95}9697static int98type_size(const struct glsl_type *type, bool bindless)99{100return glsl_count_attribute_slots(type, false);101}102103void104lima_program_optimize_vs_nir(struct nir_shader *s)105{106bool progress;107108NIR_PASS_V(s, nir_lower_viewport_transform);109NIR_PASS_V(s, nir_lower_point_size, 1.0f, 100.0f);110NIR_PASS_V(s, nir_lower_io,111nir_var_shader_in | nir_var_shader_out, type_size, 0);112NIR_PASS_V(s, nir_lower_load_const_to_scalar);113NIR_PASS_V(s, lima_nir_lower_uniform_to_scalar);114NIR_PASS_V(s, nir_lower_io_to_scalar,115nir_var_shader_in|nir_var_shader_out);116117do {118progress = false;119120NIR_PASS_V(s, nir_lower_vars_to_ssa);121NIR_PASS(progress, s, nir_lower_alu_to_scalar, NULL, NULL);122NIR_PASS(progress, s, nir_lower_phis_to_scalar, false);123NIR_PASS(progress, s, nir_copy_prop);124NIR_PASS(progress, s, nir_opt_remove_phis);125NIR_PASS(progress, s, nir_opt_dce);126NIR_PASS(progress, s, nir_opt_dead_cf);127NIR_PASS(progress, s, nir_opt_cse);128NIR_PASS(progress, s, nir_opt_peephole_select, 8, true, true);129NIR_PASS(progress, s, nir_opt_algebraic);130NIR_PASS(progress, s, lima_nir_lower_ftrunc);131NIR_PASS(progress, s, nir_opt_constant_folding);132NIR_PASS(progress, s, nir_opt_undef);133NIR_PASS(progress, s, nir_opt_loop_unroll,134nir_var_shader_in |135nir_var_shader_out |136nir_var_function_temp);137} while (progress);138139NIR_PASS_V(s, nir_lower_int_to_float);140/* int_to_float pass generates ftrunc, so lower it */141NIR_PASS(progress, s, lima_nir_lower_ftrunc);142NIR_PASS_V(s, nir_lower_bool_to_float);143144NIR_PASS_V(s, nir_copy_prop);145NIR_PASS_V(s, nir_opt_dce);146NIR_PASS_V(s, nir_lower_locals_to_regs);147NIR_PASS_V(s, nir_convert_from_ssa, true);148NIR_PASS_V(s, nir_remove_dead_variables, nir_var_function_temp, NULL);149nir_sweep(s);150}151152static bool153lima_alu_to_scalar_filter_cb(const nir_instr *instr, const void *data)154{155if (instr->type != nir_instr_type_alu)156return false;157158nir_alu_instr *alu = nir_instr_as_alu(instr);159switch (alu->op) {160case nir_op_frcp:161case nir_op_frsq:162case nir_op_flog2:163case nir_op_fexp2:164case nir_op_fsqrt:165case nir_op_fsin:166case nir_op_fcos:167return true;168default:169break;170}171172/* nir vec4 fcsel assumes that each component of the condition will be173* used to select the same component from the two options, but Utgard PP174* has only 1 component condition. If all condition components are not the175* same we need to lower it to scalar.176*/177switch (alu->op) {178case nir_op_bcsel:179case nir_op_fcsel:180break;181default:182return false;183}184185int num_components = nir_dest_num_components(alu->dest.dest);186187uint8_t swizzle = alu->src[0].swizzle[0];188189for (int i = 1; i < num_components; i++)190if (alu->src[0].swizzle[i] != swizzle)191return true;192193return false;194}195196static bool197lima_vec_to_movs_filter_cb(const nir_instr *instr, unsigned writemask,198const void *data)199{200assert(writemask > 0);201if (util_bitcount(writemask) == 1)202return true;203204return !lima_alu_to_scalar_filter_cb(instr, data);205}206207void208lima_program_optimize_fs_nir(struct nir_shader *s,209struct nir_lower_tex_options *tex_options)210{211bool progress;212213NIR_PASS_V(s, nir_lower_fragcoord_wtrans);214NIR_PASS_V(s, nir_lower_io,215nir_var_shader_in | nir_var_shader_out, type_size, 0);216NIR_PASS_V(s, nir_lower_regs_to_ssa);217NIR_PASS_V(s, nir_lower_tex, tex_options);218219do {220progress = false;221NIR_PASS(progress, s, nir_opt_vectorize, NULL, NULL);222} while (progress);223224do {225progress = false;226227NIR_PASS_V(s, nir_lower_vars_to_ssa);228NIR_PASS(progress, s, nir_lower_alu_to_scalar, lima_alu_to_scalar_filter_cb, NULL);229NIR_PASS(progress, s, nir_copy_prop);230NIR_PASS(progress, s, nir_opt_remove_phis);231NIR_PASS(progress, s, nir_opt_dce);232NIR_PASS(progress, s, nir_opt_dead_cf);233NIR_PASS(progress, s, nir_opt_cse);234NIR_PASS(progress, s, nir_opt_peephole_select, 8, true, true);235NIR_PASS(progress, s, nir_opt_algebraic);236NIR_PASS(progress, s, nir_opt_constant_folding);237NIR_PASS(progress, s, nir_opt_undef);238NIR_PASS(progress, s, nir_opt_loop_unroll,239nir_var_shader_in |240nir_var_shader_out |241nir_var_function_temp);242NIR_PASS(progress, s, lima_nir_split_load_input);243} while (progress);244245NIR_PASS_V(s, nir_lower_int_to_float);246NIR_PASS_V(s, nir_lower_bool_to_float);247248/* Some ops must be lowered after being converted from int ops,249* so re-run nir_opt_algebraic after int lowering. */250do {251progress = false;252NIR_PASS(progress, s, nir_opt_algebraic);253} while (progress);254255/* Must be run after optimization loop */256NIR_PASS_V(s, lima_nir_scale_trig);257258/* Lower modifiers */259NIR_PASS_V(s, nir_lower_to_source_mods, nir_lower_all_source_mods);260NIR_PASS_V(s, nir_copy_prop);261NIR_PASS_V(s, nir_opt_dce);262263NIR_PASS_V(s, nir_lower_locals_to_regs);264NIR_PASS_V(s, nir_convert_from_ssa, true);265NIR_PASS_V(s, nir_remove_dead_variables, nir_var_function_temp, NULL);266267NIR_PASS_V(s, nir_move_vec_src_uses_to_dest);268NIR_PASS_V(s, nir_lower_vec_to_movs, lima_vec_to_movs_filter_cb, NULL);269NIR_PASS_V(s, nir_opt_dce); /* clean up any new dead code from vec to movs */270271NIR_PASS_V(s, lima_nir_duplicate_load_uniforms);272NIR_PASS_V(s, lima_nir_duplicate_load_inputs);273NIR_PASS_V(s, lima_nir_duplicate_load_consts);274275nir_sweep(s);276}277278static bool279lima_fs_compile_shader(struct lima_context *ctx,280struct lima_fs_key *key,281struct lima_fs_uncompiled_shader *ufs,282struct lima_fs_compiled_shader *fs)283{284struct lima_screen *screen = lima_screen(ctx->base.screen);285nir_shader *nir = nir_shader_clone(fs, ufs->base.ir.nir);286287struct nir_lower_tex_options tex_options = {288.lower_txp = ~0u,289.swizzle_result = ~0u,290};291292for (int i = 0; i < ARRAY_SIZE(key->tex); i++) {293for (int j = 0; j < 4; j++)294tex_options.swizzles[i][j] = key->tex[i].swizzle[j];295}296297lima_program_optimize_fs_nir(nir, &tex_options);298299if (lima_debug & LIMA_DEBUG_PP)300nir_print_shader(nir, stdout);301302if (!ppir_compile_nir(fs, nir, screen->pp_ra, &ctx->debug)) {303ralloc_free(nir);304return false;305}306307fs->state.uses_discard = nir->info.fs.uses_discard;308ralloc_free(nir);309310return true;311}312313static bool314lima_fs_upload_shader(struct lima_context *ctx,315struct lima_fs_compiled_shader *fs)316{317struct lima_screen *screen = lima_screen(ctx->base.screen);318319fs->bo = lima_bo_create(screen, fs->state.shader_size, 0);320if (!fs->bo) {321fprintf(stderr, "lima: create fs shader bo fail\n");322return false;323}324325memcpy(lima_bo_map(fs->bo), fs->shader, fs->state.shader_size);326327return true;328}329330static struct lima_fs_compiled_shader *331lima_get_compiled_fs(struct lima_context *ctx,332struct lima_fs_uncompiled_shader *ufs,333struct lima_fs_key *key)334{335struct lima_screen *screen = lima_screen(ctx->base.screen);336struct hash_table *ht;337uint32_t key_size;338339ht = ctx->fs_cache;340key_size = sizeof(struct lima_fs_key);341342struct hash_entry *entry = _mesa_hash_table_search(ht, key);343if (entry)344return entry->data;345346/* Not on memory cache, try disk cache */347struct lima_fs_compiled_shader *fs =348lima_fs_disk_cache_retrieve(screen->disk_cache, key);349350if (!fs) {351/* Not on disk cache, compile and insert into disk cache*/352fs = rzalloc(NULL, struct lima_fs_compiled_shader);353if (!fs)354return NULL;355356if (!lima_fs_compile_shader(ctx, key, ufs, fs))357goto err;358359lima_fs_disk_cache_store(screen->disk_cache, key, fs);360}361362if (!lima_fs_upload_shader(ctx, fs))363goto err;364365ralloc_free(fs->shader);366fs->shader = NULL;367368/* Insert into memory cache */369struct lima_key *dup_key;370dup_key = rzalloc_size(fs, key_size);371memcpy(dup_key, key, key_size);372_mesa_hash_table_insert(ht, dup_key, fs);373374return fs;375376err:377ralloc_free(fs);378return NULL;379}380381static void *382lima_create_fs_state(struct pipe_context *pctx,383const struct pipe_shader_state *cso)384{385struct lima_context *ctx = lima_context(pctx);386struct lima_fs_uncompiled_shader *so = rzalloc(NULL, struct lima_fs_uncompiled_shader);387388if (!so)389return NULL;390391nir_shader *nir;392if (cso->type == PIPE_SHADER_IR_NIR)393/* The backend takes ownership of the NIR shader on state394* creation. */395nir = cso->ir.nir;396else {397assert(cso->type == PIPE_SHADER_IR_TGSI);398399nir = tgsi_to_nir(cso->tokens, pctx->screen, false);400}401402so->base.type = PIPE_SHADER_IR_NIR;403so->base.ir.nir = nir;404405/* Serialize the NIR to a binary blob that we can hash for the disk406* cache. Drop unnecessary information (like variable names)407* so the serialized NIR is smaller, and also to let us detect more408* isomorphic shaders when hashing, increasing cache hits.409*/410struct blob blob;411blob_init(&blob);412nir_serialize(&blob, nir, true);413_mesa_sha1_compute(blob.data, blob.size, so->nir_sha1);414blob_finish(&blob);415416if (lima_debug & LIMA_DEBUG_PRECOMPILE) {417/* Trigger initial compilation with default settings */418struct lima_fs_key key;419memset(&key, 0, sizeof(key));420memcpy(key.nir_sha1, so->nir_sha1, sizeof(so->nir_sha1));421for (int i = 0; i < ARRAY_SIZE(key.tex); i++) {422for (int j = 0; j < 4; j++)423key.tex[i].swizzle[j] = j;424}425lima_get_compiled_fs(ctx, so, &key);426}427428return so;429}430431static void432lima_bind_fs_state(struct pipe_context *pctx, void *hwcso)433{434struct lima_context *ctx = lima_context(pctx);435436ctx->uncomp_fs = hwcso;437ctx->dirty |= LIMA_CONTEXT_DIRTY_UNCOMPILED_FS;438}439440static void441lima_delete_fs_state(struct pipe_context *pctx, void *hwcso)442{443struct lima_context *ctx = lima_context(pctx);444struct lima_fs_uncompiled_shader *so = hwcso;445446hash_table_foreach(ctx->fs_cache, entry) {447const struct lima_fs_key *key = entry->key;448if (!memcmp(key->nir_sha1, so->nir_sha1, sizeof(so->nir_sha1))) {449struct lima_fs_compiled_shader *fs = entry->data;450_mesa_hash_table_remove(ctx->fs_cache, entry);451if (fs->bo)452lima_bo_unreference(fs->bo);453454if (fs == ctx->fs)455ctx->fs = NULL;456457ralloc_free(fs);458}459}460461ralloc_free(so->base.ir.nir);462ralloc_free(so);463}464465static bool466lima_vs_compile_shader(struct lima_context *ctx,467struct lima_vs_key *key,468struct lima_vs_uncompiled_shader *uvs,469struct lima_vs_compiled_shader *vs)470{471nir_shader *nir = nir_shader_clone(vs, uvs->base.ir.nir);472473lima_program_optimize_vs_nir(nir);474475if (lima_debug & LIMA_DEBUG_GP)476nir_print_shader(nir, stdout);477478if (!gpir_compile_nir(vs, nir, &ctx->debug)) {479ralloc_free(nir);480return false;481}482483ralloc_free(nir);484485return true;486}487488static bool489lima_vs_upload_shader(struct lima_context *ctx,490struct lima_vs_compiled_shader *vs)491{492struct lima_screen *screen = lima_screen(ctx->base.screen);493vs->bo = lima_bo_create(screen, vs->state.shader_size, 0);494if (!vs->bo) {495fprintf(stderr, "lima: create vs shader bo fail\n");496return false;497}498499memcpy(lima_bo_map(vs->bo), vs->shader, vs->state.shader_size);500501return true;502}503504static struct lima_vs_compiled_shader *505lima_get_compiled_vs(struct lima_context *ctx,506struct lima_vs_uncompiled_shader *uvs,507struct lima_vs_key *key)508{509struct lima_screen *screen = lima_screen(ctx->base.screen);510struct hash_table *ht;511uint32_t key_size;512513ht = ctx->vs_cache;514key_size = sizeof(struct lima_vs_key);515516struct hash_entry *entry = _mesa_hash_table_search(ht, key);517if (entry)518return entry->data;519520/* Not on memory cache, try disk cache */521struct lima_vs_compiled_shader *vs =522lima_vs_disk_cache_retrieve(screen->disk_cache, key);523524if (!vs) {525/* Not on disk cache, compile and insert into disk cache */526vs = rzalloc(NULL, struct lima_vs_compiled_shader);527if (!vs)528return NULL;529if (!lima_vs_compile_shader(ctx, key, uvs, vs))530goto err;531532lima_vs_disk_cache_store(screen->disk_cache, key, vs);533}534535if (!lima_vs_upload_shader(ctx, vs))536goto err;537538ralloc_free(vs->shader);539vs->shader = NULL;540541struct lima_key *dup_key;542dup_key = rzalloc_size(vs, key_size);543memcpy(dup_key, key, key_size);544_mesa_hash_table_insert(ht, dup_key, vs);545546return vs;547548err:549ralloc_free(vs);550return NULL;551}552553bool554lima_update_vs_state(struct lima_context *ctx)555{556if (!(ctx->dirty & LIMA_CONTEXT_DIRTY_UNCOMPILED_VS)) {557return true;558}559560struct lima_vs_key local_key;561struct lima_vs_key *key = &local_key;562memset(key, 0, sizeof(*key));563memcpy(key->nir_sha1, ctx->uncomp_vs->nir_sha1,564sizeof(ctx->uncomp_vs->nir_sha1));565566struct lima_vs_compiled_shader *old_vs = ctx->vs;567struct lima_vs_compiled_shader *vs = lima_get_compiled_vs(ctx,568ctx->uncomp_vs,569key);570if (!vs)571return false;572573ctx->vs = vs;574575if (ctx->vs != old_vs)576ctx->dirty |= LIMA_CONTEXT_DIRTY_COMPILED_VS;577578return true;579}580581bool582lima_update_fs_state(struct lima_context *ctx)583{584if (!(ctx->dirty & (LIMA_CONTEXT_DIRTY_UNCOMPILED_FS |585LIMA_CONTEXT_DIRTY_TEXTURES))) {586return true;587}588589struct lima_texture_stateobj *lima_tex = &ctx->tex_stateobj;590struct lima_fs_key local_key;591struct lima_fs_key *key = &local_key;592memset(key, 0, sizeof(*key));593memcpy(key->nir_sha1, ctx->uncomp_fs->nir_sha1,594sizeof(ctx->uncomp_fs->nir_sha1));595596for (int i = 0; i < lima_tex->num_textures; i++) {597struct lima_sampler_view *sampler = lima_sampler_view(lima_tex->textures[i]);598for (int j = 0; j < 4; j++)599key->tex[i].swizzle[j] = sampler->swizzle[j];600}601602/* Fill rest with identity swizzle */603uint8_t identity[4] = { PIPE_SWIZZLE_X, PIPE_SWIZZLE_Y,604PIPE_SWIZZLE_Z, PIPE_SWIZZLE_W };605for (int i = lima_tex->num_textures; i < ARRAY_SIZE(key->tex); i++)606memcpy(key->tex[i].swizzle, identity, 4);607608struct lima_fs_compiled_shader *old_fs = ctx->fs;609610struct lima_fs_compiled_shader *fs = lima_get_compiled_fs(ctx,611ctx->uncomp_fs,612key);613if (!fs)614return false;615616ctx->fs = fs;617618if (ctx->fs != old_fs)619ctx->dirty |= LIMA_CONTEXT_DIRTY_COMPILED_FS;620621return true;622}623624static void *625lima_create_vs_state(struct pipe_context *pctx,626const struct pipe_shader_state *cso)627{628struct lima_context *ctx = lima_context(pctx);629struct lima_vs_uncompiled_shader *so = rzalloc(NULL, struct lima_vs_uncompiled_shader);630631if (!so)632return NULL;633634nir_shader *nir;635if (cso->type == PIPE_SHADER_IR_NIR)636/* The backend takes ownership of the NIR shader on state637* creation. */638nir = cso->ir.nir;639else {640assert(cso->type == PIPE_SHADER_IR_TGSI);641642nir = tgsi_to_nir(cso->tokens, pctx->screen, false);643}644645so->base.type = PIPE_SHADER_IR_NIR;646so->base.ir.nir = nir;647648/* Serialize the NIR to a binary blob that we can hash for the disk649* cache. Drop unnecessary information (like variable names)650* so the serialized NIR is smaller, and also to let us detect more651* isomorphic shaders when hashing, increasing cache hits.652*/653struct blob blob;654blob_init(&blob);655nir_serialize(&blob, nir, true);656_mesa_sha1_compute(blob.data, blob.size, so->nir_sha1);657blob_finish(&blob);658659if (lima_debug & LIMA_DEBUG_PRECOMPILE) {660/* Trigger initial compilation with default settings */661struct lima_vs_key key;662memset(&key, 0, sizeof(key));663memcpy(key.nir_sha1, so->nir_sha1, sizeof(so->nir_sha1));664lima_get_compiled_vs(ctx, so, &key);665}666667return so;668}669670static void671lima_bind_vs_state(struct pipe_context *pctx, void *hwcso)672{673struct lima_context *ctx = lima_context(pctx);674675ctx->uncomp_vs = hwcso;676ctx->dirty |= LIMA_CONTEXT_DIRTY_UNCOMPILED_VS;677}678679static void680lima_delete_vs_state(struct pipe_context *pctx, void *hwcso)681{682struct lima_context *ctx = lima_context(pctx);683struct lima_vs_uncompiled_shader *so = hwcso;684685hash_table_foreach(ctx->vs_cache, entry) {686const struct lima_vs_key *key = entry->key;687if (!memcmp(key->nir_sha1, so->nir_sha1, sizeof(so->nir_sha1))) {688struct lima_vs_compiled_shader *vs = entry->data;689_mesa_hash_table_remove(ctx->vs_cache, entry);690if (vs->bo)691lima_bo_unreference(vs->bo);692693if (vs == ctx->vs)694ctx->vs = NULL;695696ralloc_free(vs);697}698}699700ralloc_free(so->base.ir.nir);701ralloc_free(so);702}703704static uint32_t705lima_fs_cache_hash(const void *key)706{707return _mesa_hash_data(key, sizeof(struct lima_fs_key));708}709710static uint32_t711lima_vs_cache_hash(const void *key)712{713return _mesa_hash_data(key, sizeof(struct lima_vs_key));714}715716static bool717lima_fs_cache_compare(const void *key1, const void *key2)718{719return memcmp(key1, key2, sizeof(struct lima_fs_key)) == 0;720}721722static bool723lima_vs_cache_compare(const void *key1, const void *key2)724{725return memcmp(key1, key2, sizeof(struct lima_vs_key)) == 0;726}727728void729lima_program_init(struct lima_context *ctx)730{731ctx->base.create_fs_state = lima_create_fs_state;732ctx->base.bind_fs_state = lima_bind_fs_state;733ctx->base.delete_fs_state = lima_delete_fs_state;734735ctx->base.create_vs_state = lima_create_vs_state;736ctx->base.bind_vs_state = lima_bind_vs_state;737ctx->base.delete_vs_state = lima_delete_vs_state;738739ctx->fs_cache = _mesa_hash_table_create(ctx, lima_fs_cache_hash,740lima_fs_cache_compare);741ctx->vs_cache = _mesa_hash_table_create(ctx, lima_vs_cache_hash,742lima_vs_cache_compare);743}744745void746lima_program_fini(struct lima_context *ctx)747{748hash_table_foreach(ctx->vs_cache, entry) {749struct lima_vs_compiled_shader *vs = entry->data;750if (vs->bo)751lima_bo_unreference(vs->bo);752ralloc_free(vs);753_mesa_hash_table_remove(ctx->vs_cache, entry);754}755756hash_table_foreach(ctx->fs_cache, entry) {757struct lima_fs_compiled_shader *fs = entry->data;758if (fs->bo)759lima_bo_unreference(fs->bo);760ralloc_free(fs);761_mesa_hash_table_remove(ctx->fs_cache, entry);762}763}764765766