llvmpipe: introduce variant building infrastrucutre.
[mesa.git] / src / gallium / drivers / llvmpipe / lp_state_cs.c
1 /**************************************************************************
2 *
3 * Copyright 2019 Red Hat.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 *
24 **************************************************************************/
25 #include "util/u_memory.h"
26 #include "util/simple_list.h"
27 #include "util/os_time.h"
28 #include "tgsi/tgsi_dump.h"
29 #include "tgsi/tgsi_parse.h"
30 #include "gallivm/lp_bld_debug.h"
31 #include "lp_state_cs.h"
32 #include "lp_context.h"
33 #include "lp_debug.h"
34 #include "lp_state.h"
35 #include "lp_perf.h"
36
37 static void *
38 llvmpipe_create_compute_state(struct pipe_context *pipe,
39 const struct pipe_compute_state *templ)
40 {
41 struct lp_compute_shader *shader;
42
43 shader = CALLOC_STRUCT(lp_compute_shader);
44 if (!shader)
45 return NULL;
46
47 assert(templ->ir_type == PIPE_SHADER_IR_TGSI);
48 shader->base.tokens = tgsi_dup_tokens(templ->prog);
49
50 lp_build_tgsi_info(shader->base.tokens, &shader->info);
51 make_empty_list(&shader->variants);
52
53 return shader;
54 }
55
56 static void
57 llvmpipe_bind_compute_state(struct pipe_context *pipe,
58 void *cs)
59 {
60 struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
61
62 if (llvmpipe->cs == cs)
63 return;
64
65 llvmpipe->cs = (struct lp_compute_shader *)cs;
66 llvmpipe->cs_dirty |= LP_CSNEW_CS;
67 }
68
69 /**
70 * Remove shader variant from two lists: the shader's variant list
71 * and the context's variant list.
72 */
73 static void
74 llvmpipe_remove_cs_shader_variant(struct llvmpipe_context *lp,
75 struct lp_compute_shader_variant *variant)
76 {
77 if ((LP_DEBUG & DEBUG_CS) || (gallivm_debug & GALLIVM_DEBUG_IR)) {
78 debug_printf("llvmpipe: del cs #%u var %u v created %u v cached %u "
79 "v total cached %u inst %u total inst %u\n",
80 variant->shader->no, variant->no,
81 variant->shader->variants_created,
82 variant->shader->variants_cached,
83 lp->nr_cs_variants, variant->nr_instrs, lp->nr_cs_instrs);
84 }
85
86 gallivm_destroy(variant->gallivm);
87
88 /* remove from shader's list */
89 remove_from_list(&variant->list_item_local);
90 variant->shader->variants_cached--;
91
92 /* remove from context's list */
93 remove_from_list(&variant->list_item_global);
94 lp->nr_fs_variants--;
95 lp->nr_fs_instrs -= variant->nr_instrs;
96
97 FREE(variant);
98 }
99
100 static void
101 llvmpipe_delete_compute_state(struct pipe_context *pipe,
102 void *cs)
103 {
104 struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
105 struct lp_compute_shader *shader = cs;
106 struct lp_cs_variant_list_item *li;
107
108 /* Delete all the variants */
109 li = first_elem(&shader->variants);
110 while(!at_end(&shader->variants, li)) {
111 struct lp_cs_variant_list_item *next = next_elem(li);
112 llvmpipe_remove_cs_shader_variant(llvmpipe, li->base);
113 li = next;
114 }
115 tgsi_free_tokens(shader->base.tokens);
116 FREE(shader);
117 }
118
119 static void
120 make_variant_key(struct llvmpipe_context *lp,
121 struct lp_compute_shader *shader,
122 struct lp_compute_shader_variant_key *key)
123 {
124 memset(key, 0, shader->variant_key_size);
125 }
126
127 static void
128 dump_cs_variant_key(const struct lp_compute_shader_variant_key *key)
129 {
130 debug_printf("cs variant %p:\n", (void *) key);
131 }
132
133 static void
134 lp_debug_cs_variant(const struct lp_compute_shader_variant *variant)
135 {
136 debug_printf("llvmpipe: Compute shader #%u variant #%u:\n",
137 variant->shader->no, variant->no);
138 tgsi_dump(variant->shader->base.tokens, 0);
139 dump_cs_variant_key(&variant->key);
140 debug_printf("\n");
141 }
142
143 static struct lp_compute_shader_variant *
144 generate_variant(struct llvmpipe_context *lp,
145 struct lp_compute_shader *shader,
146 const struct lp_compute_shader_variant_key *key)
147 {
148 struct lp_compute_shader_variant *variant;
149 char module_name[64];
150
151 variant = CALLOC_STRUCT(lp_compute_shader_variant);
152 if (!variant)
153 return NULL;
154
155 snprintf(module_name, sizeof(module_name), "cs%u_variant%u",
156 shader->no, shader->variants_created);
157
158 variant->gallivm = gallivm_create(module_name, lp->context);
159 if (!variant->gallivm) {
160 FREE(variant);
161 return NULL;
162 }
163
164 variant->shader = shader;
165 variant->list_item_global.base = variant;
166 variant->list_item_local.base = variant;
167 variant->no = shader->variants_created++;
168
169 memcpy(&variant->key, key, shader->variant_key_size);
170
171 if ((LP_DEBUG & DEBUG_CS) || (gallivm_debug & GALLIVM_DEBUG_IR)) {
172 lp_debug_cs_variant(variant);
173 }
174
175 lp_jit_init_cs_types(variant);
176
177 gallivm_free_ir(variant->gallivm);
178 return variant;
179 }
180
181 static void
182 lp_cs_ctx_set_cs_variant( struct lp_cs_context *csctx,
183 struct lp_compute_shader_variant *variant)
184 {
185 csctx->cs.current.variant = variant;
186 }
187
188 static void
189 llvmpipe_update_cs(struct llvmpipe_context *lp)
190 {
191 struct lp_compute_shader *shader = lp->cs;
192
193 struct lp_compute_shader_variant_key key;
194 struct lp_compute_shader_variant *variant = NULL;
195 struct lp_cs_variant_list_item *li;
196
197 make_variant_key(lp, shader, &key);
198
199 /* Search the variants for one which matches the key */
200 li = first_elem(&shader->variants);
201 while(!at_end(&shader->variants, li)) {
202 if(memcmp(&li->base->key, &key, shader->variant_key_size) == 0) {
203 variant = li->base;
204 break;
205 }
206 li = next_elem(li);
207 }
208
209 if (variant) {
210 /* Move this variant to the head of the list to implement LRU
211 * deletion of shader's when we have too many.
212 */
213 move_to_head(&lp->cs_variants_list, &variant->list_item_global);
214 }
215 else {
216 /* variant not found, create it now */
217 int64_t t0, t1, dt;
218 unsigned i;
219 unsigned variants_to_cull;
220
221 if (LP_DEBUG & DEBUG_CS) {
222 debug_printf("%u variants,\t%u instrs,\t%u instrs/variant\n",
223 lp->nr_cs_variants,
224 lp->nr_cs_instrs,
225 lp->nr_cs_variants ? lp->nr_cs_instrs / lp->nr_cs_variants : 0);
226 }
227
228 /* First, check if we've exceeded the max number of shader variants.
229 * If so, free 6.25% of them (the least recently used ones).
230 */
231 variants_to_cull = lp->nr_cs_variants >= LP_MAX_SHADER_VARIANTS ? LP_MAX_SHADER_VARIANTS / 16 : 0;
232
233 if (variants_to_cull ||
234 lp->nr_cs_instrs >= LP_MAX_SHADER_INSTRUCTIONS) {
235 if (gallivm_debug & GALLIVM_DEBUG_PERF) {
236 debug_printf("Evicting CS: %u cs variants,\t%u total variants,"
237 "\t%u instrs,\t%u instrs/variant\n",
238 shader->variants_cached,
239 lp->nr_cs_variants, lp->nr_cs_instrs,
240 lp->nr_cs_instrs / lp->nr_cs_variants);
241 }
242
243 /*
244 * We need to re-check lp->nr_cs_variants because an arbitrarliy large
245 * number of shader variants (potentially all of them) could be
246 * pending for destruction on flush.
247 */
248
249 for (i = 0; i < variants_to_cull || lp->nr_cs_instrs >= LP_MAX_SHADER_INSTRUCTIONS; i++) {
250 struct lp_cs_variant_list_item *item;
251 if (is_empty_list(&lp->cs_variants_list)) {
252 break;
253 }
254 item = last_elem(&lp->cs_variants_list);
255 assert(item);
256 assert(item->base);
257 llvmpipe_remove_cs_shader_variant(lp, item->base);
258 }
259 }
260 /*
261 * Generate the new variant.
262 */
263 t0 = os_time_get();
264 variant = generate_variant(lp, shader, &key);
265 t1 = os_time_get();
266 dt = t1 - t0;
267 LP_COUNT_ADD(llvm_compile_time, dt);
268 LP_COUNT_ADD(nr_llvm_compiles, 2); /* emit vs. omit in/out test */
269
270 /* Put the new variant into the list */
271 if (variant) {
272 insert_at_head(&shader->variants, &variant->list_item_local);
273 insert_at_head(&lp->cs_variants_list, &variant->list_item_global);
274 lp->nr_cs_variants++;
275 lp->nr_cs_instrs += variant->nr_instrs;
276 shader->variants_cached++;
277 }
278 }
279 /* Bind this variant */
280 lp_cs_ctx_set_cs_variant(lp->csctx, variant);
281 }
282
283 static void
284 llvmpipe_cs_update_derived(struct llvmpipe_context *llvmpipe)
285 {
286 if (llvmpipe->cs_dirty & (LP_CSNEW_CS))
287 llvmpipe_update_cs(llvmpipe);
288
289 llvmpipe->cs_dirty = 0;
290 }
291
292 static void llvmpipe_launch_grid(struct pipe_context *pipe,
293 const struct pipe_grid_info *info)
294 {
295 struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
296
297 llvmpipe_cs_update_derived(llvmpipe);
298 }
299
300 void
301 llvmpipe_init_compute_funcs(struct llvmpipe_context *llvmpipe)
302 {
303 llvmpipe->pipe.create_compute_state = llvmpipe_create_compute_state;
304 llvmpipe->pipe.bind_compute_state = llvmpipe_bind_compute_state;
305 llvmpipe->pipe.delete_compute_state = llvmpipe_delete_compute_state;
306 llvmpipe->pipe.launch_grid = llvmpipe_launch_grid;
307 }
308
309 void
310 lp_csctx_destroy(struct lp_cs_context *csctx)
311 {
312 FREE(csctx);
313 }
314
315 struct lp_cs_context *lp_csctx_create(struct pipe_context *pipe)
316 {
317 struct lp_cs_context *csctx;
318
319 csctx = CALLOC_STRUCT(lp_cs_context);
320 if (!csctx)
321 return NULL;
322
323 csctx->pipe = pipe;
324 return csctx;
325 }