1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright (C) 2015 Rob Clark <robclark@freedesktop.org> 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21bf215546Sopenharmony_ci * SOFTWARE. 22bf215546Sopenharmony_ci * 23bf215546Sopenharmony_ci * Authors: 24bf215546Sopenharmony_ci * Rob Clark <robclark@freedesktop.org> 25bf215546Sopenharmony_ci */ 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ci#include "util/hash_table.h" 28bf215546Sopenharmony_ci#include "util/ralloc.h" 29bf215546Sopenharmony_ci#define XXH_INLINE_ALL 30bf215546Sopenharmony_ci#include "util/xxhash.h" 31bf215546Sopenharmony_ci 32bf215546Sopenharmony_ci#include "ir3_cache.h" 33bf215546Sopenharmony_ci#include "ir3_gallium.h" 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_cistatic uint32_t 36bf215546Sopenharmony_cikey_hash(const void *_key) 37bf215546Sopenharmony_ci{ 38bf215546Sopenharmony_ci const struct ir3_cache_key *key = _key; 39bf215546Sopenharmony_ci return XXH32(key, sizeof(*key), 0); 40bf215546Sopenharmony_ci} 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_cistatic bool 43bf215546Sopenharmony_cikey_equals(const void *_a, const void *_b) 44bf215546Sopenharmony_ci{ 45bf215546Sopenharmony_ci const struct ir3_cache_key *a = _a; 46bf215546Sopenharmony_ci const struct ir3_cache_key *b = _b; 47bf215546Sopenharmony_ci // TODO we could optimize the key shader-variant key comparison by not 48bf215546Sopenharmony_ci // ignoring has_per_samp.. not really sure if that helps.. 49bf215546Sopenharmony_ci return memcmp(a, b, sizeof(struct ir3_cache_key)) == 0; 50bf215546Sopenharmony_ci} 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_cistruct ir3_cache { 53bf215546Sopenharmony_ci /* cache mapping gallium/etc shader state-objs + shader-key to backend 54bf215546Sopenharmony_ci * specific state-object 55bf215546Sopenharmony_ci */ 56bf215546Sopenharmony_ci struct hash_table *ht; 57bf215546Sopenharmony_ci 58bf215546Sopenharmony_ci const struct ir3_cache_funcs *funcs; 59bf215546Sopenharmony_ci void *data; 60bf215546Sopenharmony_ci}; 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_cistruct ir3_cache * 63bf215546Sopenharmony_ciir3_cache_create(const struct ir3_cache_funcs *funcs, void *data) 64bf215546Sopenharmony_ci{ 65bf215546Sopenharmony_ci struct ir3_cache *cache = rzalloc(NULL, struct ir3_cache); 66bf215546Sopenharmony_ci 67bf215546Sopenharmony_ci cache->ht = _mesa_hash_table_create(cache, key_hash, key_equals); 68bf215546Sopenharmony_ci cache->funcs = funcs; 69bf215546Sopenharmony_ci cache->data = data; 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_ci return cache; 72bf215546Sopenharmony_ci} 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_civoid 75bf215546Sopenharmony_ciir3_cache_destroy(struct ir3_cache *cache) 76bf215546Sopenharmony_ci{ 77bf215546Sopenharmony_ci if (!cache) 78bf215546Sopenharmony_ci return; 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_ci /* _mesa_hash_table_destroy is so *almost* useful.. */ 81bf215546Sopenharmony_ci hash_table_foreach (cache->ht, entry) { 82bf215546Sopenharmony_ci cache->funcs->destroy_state(cache->data, entry->data); 83bf215546Sopenharmony_ci } 84bf215546Sopenharmony_ci 85bf215546Sopenharmony_ci ralloc_free(cache); 86bf215546Sopenharmony_ci} 87bf215546Sopenharmony_ci 88bf215546Sopenharmony_cistruct ir3_program_state * 89bf215546Sopenharmony_ciir3_cache_lookup(struct ir3_cache *cache, const struct ir3_cache_key *key, 90bf215546Sopenharmony_ci struct util_debug_callback *debug) 91bf215546Sopenharmony_ci{ 92bf215546Sopenharmony_ci uint32_t hash = key_hash(key); 93bf215546Sopenharmony_ci struct hash_entry *entry = 94bf215546Sopenharmony_ci _mesa_hash_table_search_pre_hashed(cache->ht, hash, key); 95bf215546Sopenharmony_ci 96bf215546Sopenharmony_ci if (entry) { 97bf215546Sopenharmony_ci return entry->data; 98bf215546Sopenharmony_ci } 99bf215546Sopenharmony_ci 100bf215546Sopenharmony_ci if (key->hs) 101bf215546Sopenharmony_ci assert(key->ds); 102bf215546Sopenharmony_ci 103bf215546Sopenharmony_ci struct ir3_shader *shaders[MESA_SHADER_STAGES] = { 104bf215546Sopenharmony_ci [MESA_SHADER_VERTEX] = ir3_get_shader(key->vs), 105bf215546Sopenharmony_ci [MESA_SHADER_TESS_CTRL] = ir3_get_shader(key->hs), 106bf215546Sopenharmony_ci [MESA_SHADER_TESS_EVAL] = ir3_get_shader(key->ds), 107bf215546Sopenharmony_ci [MESA_SHADER_GEOMETRY] = ir3_get_shader(key->gs), 108bf215546Sopenharmony_ci [MESA_SHADER_FRAGMENT] = ir3_get_shader(key->fs), 109bf215546Sopenharmony_ci }; 110bf215546Sopenharmony_ci 111bf215546Sopenharmony_ci struct ir3_shader_variant *variants[MESA_SHADER_STAGES]; 112bf215546Sopenharmony_ci struct ir3_shader_key shader_key = key->key; 113bf215546Sopenharmony_ci 114bf215546Sopenharmony_ci for (gl_shader_stage stage = MESA_SHADER_VERTEX; stage < MESA_SHADER_STAGES; 115bf215546Sopenharmony_ci stage++) { 116bf215546Sopenharmony_ci if (shaders[stage]) { 117bf215546Sopenharmony_ci variants[stage] = 118bf215546Sopenharmony_ci ir3_shader_variant(shaders[stage], shader_key, false, debug); 119bf215546Sopenharmony_ci if (!variants[stage]) 120bf215546Sopenharmony_ci return NULL; 121bf215546Sopenharmony_ci } else { 122bf215546Sopenharmony_ci variants[stage] = NULL; 123bf215546Sopenharmony_ci } 124bf215546Sopenharmony_ci } 125bf215546Sopenharmony_ci 126bf215546Sopenharmony_ci struct ir3_compiler *compiler = shaders[MESA_SHADER_VERTEX]->compiler; 127bf215546Sopenharmony_ci uint32_t safe_constlens = ir3_trim_constlen(variants, compiler); 128bf215546Sopenharmony_ci shader_key.safe_constlen = true; 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_ci for (gl_shader_stage stage = MESA_SHADER_VERTEX; stage < MESA_SHADER_STAGES; 131bf215546Sopenharmony_ci stage++) { 132bf215546Sopenharmony_ci if (safe_constlens & (1 << stage)) { 133bf215546Sopenharmony_ci variants[stage] = 134bf215546Sopenharmony_ci ir3_shader_variant(shaders[stage], shader_key, false, debug); 135bf215546Sopenharmony_ci if (!variants[stage]) 136bf215546Sopenharmony_ci return NULL; 137bf215546Sopenharmony_ci } 138bf215546Sopenharmony_ci } 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci struct ir3_shader_variant *bs; 141bf215546Sopenharmony_ci 142bf215546Sopenharmony_ci if (ir3_has_binning_vs(&key->key)) { 143bf215546Sopenharmony_ci /* starting with a6xx, the same const state is used for binning and draw 144bf215546Sopenharmony_ci * passes, so the binning pass VS variant needs to match the main VS 145bf215546Sopenharmony_ci */ 146bf215546Sopenharmony_ci shader_key.safe_constlen = (compiler->gen >= 6) && 147bf215546Sopenharmony_ci !!(safe_constlens & (1 << MESA_SHADER_VERTEX)); 148bf215546Sopenharmony_ci bs = 149bf215546Sopenharmony_ci ir3_shader_variant(shaders[MESA_SHADER_VERTEX], shader_key, true, debug); 150bf215546Sopenharmony_ci if (!bs) 151bf215546Sopenharmony_ci return NULL; 152bf215546Sopenharmony_ci } else { 153bf215546Sopenharmony_ci bs = variants[MESA_SHADER_VERTEX]; 154bf215546Sopenharmony_ci } 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci struct ir3_program_state *state = cache->funcs->create_state( 157bf215546Sopenharmony_ci cache->data, bs, variants[MESA_SHADER_VERTEX], 158bf215546Sopenharmony_ci variants[MESA_SHADER_TESS_CTRL], variants[MESA_SHADER_TESS_EVAL], 159bf215546Sopenharmony_ci variants[MESA_SHADER_GEOMETRY], variants[MESA_SHADER_FRAGMENT], 160bf215546Sopenharmony_ci key); 161bf215546Sopenharmony_ci state->key = *key; 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci /* NOTE: uses copy of key in state obj, because pointer passed by caller 164bf215546Sopenharmony_ci * is probably on the stack 165bf215546Sopenharmony_ci */ 166bf215546Sopenharmony_ci _mesa_hash_table_insert_pre_hashed(cache->ht, hash, &state->key, state); 167bf215546Sopenharmony_ci 168bf215546Sopenharmony_ci return state; 169bf215546Sopenharmony_ci} 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_ci/* call when an API level state object is destroyed, to invalidate 172bf215546Sopenharmony_ci * cache entries which reference that state object. 173bf215546Sopenharmony_ci */ 174bf215546Sopenharmony_civoid 175bf215546Sopenharmony_ciir3_cache_invalidate(struct ir3_cache *cache, void *stobj) 176bf215546Sopenharmony_ci{ 177bf215546Sopenharmony_ci if (!cache) 178bf215546Sopenharmony_ci return; 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci hash_table_foreach (cache->ht, entry) { 181bf215546Sopenharmony_ci const struct ir3_cache_key *key = entry->key; 182bf215546Sopenharmony_ci if ((key->fs == stobj) || (key->vs == stobj) || (key->ds == stobj) || 183bf215546Sopenharmony_ci (key->hs == stobj) || (key->gs == stobj)) { 184bf215546Sopenharmony_ci cache->funcs->destroy_state(cache->data, entry->data); 185bf215546Sopenharmony_ci _mesa_hash_table_remove(cache->ht, entry); 186bf215546Sopenharmony_ci return; 187bf215546Sopenharmony_ci } 188bf215546Sopenharmony_ci } 189bf215546Sopenharmony_ci} 190