Path: blob/21.2-virgl/src/gallium/drivers/freedreno/ir3/ir3_cache.c
4574 views
/*1* Copyright (C) 2015 Rob Clark <[email protected]>2*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, sublicense,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 the next11* paragraph) shall be included in all copies or substantial portions of the12* 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 NONINFRINGEMENT. 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, ARISING FROM,19* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE20* SOFTWARE.21*22* Authors:23* Rob Clark <[email protected]>24*/2526#include "util/hash_table.h"27#include "util/ralloc.h"28#define XXH_INLINE_ALL29#include "util/xxhash.h"3031#include "ir3_cache.h"32#include "ir3_gallium.h"3334static uint32_t35key_hash(const void *_key)36{37const struct ir3_cache_key *key = _key;38return XXH32(key, sizeof(*key), 0);39}4041static bool42key_equals(const void *_a, const void *_b)43{44const struct ir3_cache_key *a = _a;45const struct ir3_cache_key *b = _b;46// TODO we could optimize the key shader-variant key comparison by not47// ignoring has_per_samp.. not really sure if that helps..48return memcmp(a, b, sizeof(struct ir3_cache_key)) == 0;49}5051struct ir3_cache {52/* cache mapping gallium/etc shader state-objs + shader-key to backend53* specific state-object54*/55struct hash_table *ht;5657const struct ir3_cache_funcs *funcs;58void *data;59};6061struct ir3_cache *62ir3_cache_create(const struct ir3_cache_funcs *funcs, void *data)63{64struct ir3_cache *cache = rzalloc(NULL, struct ir3_cache);6566cache->ht = _mesa_hash_table_create(cache, key_hash, key_equals);67cache->funcs = funcs;68cache->data = data;6970return cache;71}7273void74ir3_cache_destroy(struct ir3_cache *cache)75{76if (!cache)77return;7879/* _mesa_hash_table_destroy is so *almost* useful.. */80hash_table_foreach (cache->ht, entry) {81cache->funcs->destroy_state(cache->data, entry->data);82}8384ralloc_free(cache);85}8687struct ir3_program_state *88ir3_cache_lookup(struct ir3_cache *cache, const struct ir3_cache_key *key,89struct pipe_debug_callback *debug)90{91uint32_t hash = key_hash(key);92struct hash_entry *entry =93_mesa_hash_table_search_pre_hashed(cache->ht, hash, key);9495if (entry) {96return entry->data;97}9899if (key->hs)100debug_assert(key->ds);101102struct ir3_shader *shaders[MESA_SHADER_STAGES] = {103[MESA_SHADER_VERTEX] = ir3_get_shader(key->vs),104[MESA_SHADER_TESS_CTRL] = ir3_get_shader(key->hs),105[MESA_SHADER_TESS_EVAL] = ir3_get_shader(key->ds),106[MESA_SHADER_GEOMETRY] = ir3_get_shader(key->gs),107[MESA_SHADER_FRAGMENT] = ir3_get_shader(key->fs),108};109110struct ir3_shader_variant *variants[MESA_SHADER_STAGES];111struct ir3_shader_key shader_key = key->key;112113for (gl_shader_stage stage = MESA_SHADER_VERTEX; stage < MESA_SHADER_STAGES;114stage++) {115if (shaders[stage]) {116variants[stage] =117ir3_shader_variant(shaders[stage], shader_key, false, debug);118if (!variants[stage])119return NULL;120} else {121variants[stage] = NULL;122}123}124125struct ir3_compiler *compiler = shaders[MESA_SHADER_VERTEX]->compiler;126uint32_t safe_constlens = ir3_trim_constlen(variants, compiler);127shader_key.safe_constlen = true;128129for (gl_shader_stage stage = MESA_SHADER_VERTEX; stage < MESA_SHADER_STAGES;130stage++) {131if (safe_constlens & (1 << stage)) {132variants[stage] =133ir3_shader_variant(shaders[stage], shader_key, false, debug);134if (!variants[stage])135return NULL;136}137}138139struct ir3_shader_variant *bs;140141if (ir3_has_binning_vs(&key->key)) {142shader_key.safe_constlen = !!(safe_constlens & (1 << MESA_SHADER_VERTEX));143bs =144ir3_shader_variant(shaders[MESA_SHADER_VERTEX], key->key, true, debug);145if (!bs)146return NULL;147} else {148bs = variants[MESA_SHADER_VERTEX];149}150151struct ir3_program_state *state = cache->funcs->create_state(152cache->data, bs, variants[MESA_SHADER_VERTEX],153variants[MESA_SHADER_TESS_CTRL], variants[MESA_SHADER_TESS_EVAL],154variants[MESA_SHADER_GEOMETRY], variants[MESA_SHADER_FRAGMENT],155&key->key);156state->key = *key;157158/* NOTE: uses copy of key in state obj, because pointer passed by caller159* is probably on the stack160*/161_mesa_hash_table_insert_pre_hashed(cache->ht, hash, &state->key, state);162163return state;164}165166/* call when an API level state object is destroyed, to invalidate167* cache entries which reference that state object.168*/169void170ir3_cache_invalidate(struct ir3_cache *cache, void *stobj)171{172if (!cache)173return;174175hash_table_foreach (cache->ht, entry) {176const struct ir3_cache_key *key = entry->key;177if ((key->fs == stobj) || (key->vs == stobj) || (key->ds == stobj) ||178(key->hs == stobj) || (key->gs == stobj)) {179cache->funcs->destroy_state(cache->data, entry->data);180_mesa_hash_table_remove(cache->ht, entry);181return;182}183}184}185186187