1 /*
2 * Copyright © 2015 Rob Clark <[email protected]>
3 * SPDX-License-Identifier: MIT
4 *
5 * Authors:
6 * Rob Clark <[email protected]>
7 */
8
9 #include "util/hash_table.h"
10 #include "util/ralloc.h"
11 #define XXH_INLINE_ALL
12 #include "util/xxhash.h"
13
14 #include "ir3_cache.h"
15 #include "ir3_gallium.h"
16
17 static uint32_t
key_hash(const void * _key)18 key_hash(const void *_key)
19 {
20 const struct ir3_cache_key *key = _key;
21 return XXH32(key, sizeof(*key), 0);
22 }
23
24 static bool
key_equals(const void * _a,const void * _b)25 key_equals(const void *_a, const void *_b)
26 {
27 const struct ir3_cache_key *a = _a;
28 const struct ir3_cache_key *b = _b;
29 // TODO we could optimize the key shader-variant key comparison by not
30 // ignoring has_per_samp.. not really sure if that helps..
31 return memcmp(a, b, sizeof(struct ir3_cache_key)) == 0;
32 }
33
34 struct ir3_cache {
35 /* cache mapping gallium/etc shader state-objs + shader-key to backend
36 * specific state-object
37 */
38 struct hash_table *ht;
39
40 const struct ir3_cache_funcs *funcs;
41 void *data;
42 };
43
44 struct ir3_cache *
ir3_cache_create(const struct ir3_cache_funcs * funcs,void * data)45 ir3_cache_create(const struct ir3_cache_funcs *funcs, void *data)
46 {
47 struct ir3_cache *cache = rzalloc(NULL, struct ir3_cache);
48
49 cache->ht = _mesa_hash_table_create(cache, key_hash, key_equals);
50 cache->funcs = funcs;
51 cache->data = data;
52
53 return cache;
54 }
55
56 void
ir3_cache_destroy(struct ir3_cache * cache)57 ir3_cache_destroy(struct ir3_cache *cache)
58 {
59 if (!cache)
60 return;
61
62 /* _mesa_hash_table_destroy is so *almost* useful.. */
63 hash_table_foreach (cache->ht, entry) {
64 cache->funcs->destroy_state(cache->data, entry->data);
65 }
66
67 ralloc_free(cache);
68 }
69
70 struct ir3_program_state *
ir3_cache_lookup(struct ir3_cache * cache,const struct ir3_cache_key * key,struct util_debug_callback * debug)71 ir3_cache_lookup(struct ir3_cache *cache, const struct ir3_cache_key *key,
72 struct util_debug_callback *debug)
73 {
74 uint32_t hash = key_hash(key);
75 struct hash_entry *entry =
76 _mesa_hash_table_search_pre_hashed(cache->ht, hash, key);
77
78 if (entry) {
79 return entry->data;
80 }
81
82 MESA_TRACE_FUNC();
83
84 if (key->hs)
85 assert(key->ds);
86
87 struct ir3_shader *shaders[MESA_SHADER_STAGES] = {
88 [MESA_SHADER_VERTEX] = ir3_get_shader(key->vs),
89 [MESA_SHADER_TESS_CTRL] = ir3_get_shader(key->hs),
90 [MESA_SHADER_TESS_EVAL] = ir3_get_shader(key->ds),
91 [MESA_SHADER_GEOMETRY] = ir3_get_shader(key->gs),
92 [MESA_SHADER_FRAGMENT] = ir3_get_shader(key->fs),
93 };
94
95 if (shaders[MESA_SHADER_TESS_EVAL] && !shaders[MESA_SHADER_TESS_CTRL]) {
96 struct ir3_shader *vs = shaders[MESA_SHADER_VERTEX];
97 struct ir3_shader *hs =
98 ir3_shader_passthrough_tcs(vs, key->patch_vertices);
99 shaders[MESA_SHADER_TESS_CTRL] = hs;
100 }
101
102 const struct ir3_shader_variant *variants[MESA_SHADER_STAGES];
103 struct ir3_shader_key shader_key = key->key;
104
105 for (gl_shader_stage stage = MESA_SHADER_VERTEX; stage < MESA_SHADER_STAGES;
106 stage++) {
107 if (shaders[stage]) {
108 variants[stage] =
109 ir3_shader_variant(shaders[stage], shader_key, false, debug);
110 if (!variants[stage])
111 return NULL;
112 } else {
113 variants[stage] = NULL;
114 }
115 }
116
117 struct ir3_compiler *compiler = shaders[MESA_SHADER_VERTEX]->compiler;
118 uint32_t safe_constlens = ir3_trim_constlen(variants, compiler);
119 shader_key.safe_constlen = true;
120
121 for (gl_shader_stage stage = MESA_SHADER_VERTEX; stage < MESA_SHADER_STAGES;
122 stage++) {
123 if (safe_constlens & (1 << stage)) {
124 variants[stage] =
125 ir3_shader_variant(shaders[stage], shader_key, false, debug);
126 if (!variants[stage])
127 return NULL;
128 }
129 }
130
131 const struct ir3_shader_variant *bs;
132
133 if (ir3_has_binning_vs(&key->key)) {
134 /* starting with a6xx, the same const state is used for binning and draw
135 * passes, so the binning pass VS variant needs to match the main VS
136 */
137 shader_key.safe_constlen = (compiler->gen >= 6) &&
138 !!(safe_constlens & (1 << MESA_SHADER_VERTEX));
139 bs =
140 ir3_shader_variant(shaders[MESA_SHADER_VERTEX], shader_key, true, debug);
141 if (!bs)
142 return NULL;
143 } else {
144 bs = variants[MESA_SHADER_VERTEX];
145 }
146
147 struct ir3_program_state *state = cache->funcs->create_state(
148 cache->data, bs, variants[MESA_SHADER_VERTEX],
149 variants[MESA_SHADER_TESS_CTRL], variants[MESA_SHADER_TESS_EVAL],
150 variants[MESA_SHADER_GEOMETRY], variants[MESA_SHADER_FRAGMENT],
151 key);
152 state->key = *key;
153
154 /* NOTE: uses copy of key in state obj, because pointer passed by caller
155 * is probably on the stack
156 */
157 _mesa_hash_table_insert_pre_hashed(cache->ht, hash, &state->key, state);
158
159 return state;
160 }
161
162 /* call when an API level state object is destroyed, to invalidate
163 * cache entries which reference that state object.
164 */
165 void
ir3_cache_invalidate(struct ir3_cache * cache,void * stobj)166 ir3_cache_invalidate(struct ir3_cache *cache, void *stobj)
167 {
168 if (!cache)
169 return;
170
171 hash_table_foreach (cache->ht, entry) {
172 const struct ir3_cache_key *key = entry->key;
173 if ((key->fs == stobj) || (key->vs == stobj) || (key->ds == stobj) ||
174 (key->hs == stobj) || (key->gs == stobj)) {
175 cache->funcs->destroy_state(cache->data, entry->data);
176 _mesa_hash_table_remove(cache->ht, entry);
177 return;
178 }
179 }
180 }
181