1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2020 Google, Inc.
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
24bf215546Sopenharmony_ci#include "nir_serialize.h"
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci#include "ir3_compiler.h"
27bf215546Sopenharmony_ci#include "ir3_nir.h"
28bf215546Sopenharmony_ci
29bf215546Sopenharmony_ci#define debug 0
30bf215546Sopenharmony_ci
31bf215546Sopenharmony_ci/*
32bf215546Sopenharmony_ci * Shader disk-cache implementation.
33bf215546Sopenharmony_ci *
34bf215546Sopenharmony_ci * Note that at least in the EGL_ANDROID_blob_cache, we should never
35bf215546Sopenharmony_ci * rely on inter-dependencies between different cache entries:
36bf215546Sopenharmony_ci *
37bf215546Sopenharmony_ci *    No guarantees are made as to whether a given key/value pair is present in
38bf215546Sopenharmony_ci *    the cache after the set call.  If a different value has been associated
39bf215546Sopenharmony_ci *    with the given key in the past then it is undefined which value, if any,
40bf215546Sopenharmony_ci *    is associated with the key after the set call.  Note that while there are
41bf215546Sopenharmony_ci *    no guarantees, the cache implementation should attempt to cache the most
42bf215546Sopenharmony_ci *    recently set value for a given key.
43bf215546Sopenharmony_ci *
44bf215546Sopenharmony_ci * for this reason, because binning pass variants share const_state with
45bf215546Sopenharmony_ci * their draw-pass counterpart, both variants are serialized together.
46bf215546Sopenharmony_ci */
47bf215546Sopenharmony_ci
48bf215546Sopenharmony_civoid
49bf215546Sopenharmony_ciir3_disk_cache_init(struct ir3_compiler *compiler)
50bf215546Sopenharmony_ci{
51bf215546Sopenharmony_ci   if (ir3_shader_debug & IR3_DBG_NOCACHE)
52bf215546Sopenharmony_ci      return;
53bf215546Sopenharmony_ci
54bf215546Sopenharmony_ci   const char *renderer = fd_dev_name(compiler->dev_id);
55bf215546Sopenharmony_ci   const struct build_id_note *note =
56bf215546Sopenharmony_ci      build_id_find_nhdr_for_addr(ir3_disk_cache_init);
57bf215546Sopenharmony_ci   assert(note && build_id_length(note) == 20); /* sha1 */
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci   const uint8_t *id_sha1 = build_id_data(note);
60bf215546Sopenharmony_ci   assert(id_sha1);
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci   char timestamp[41];
63bf215546Sopenharmony_ci   _mesa_sha1_format(timestamp, id_sha1);
64bf215546Sopenharmony_ci
65bf215546Sopenharmony_ci   uint64_t driver_flags = ir3_shader_debug;
66bf215546Sopenharmony_ci   if (compiler->robust_buffer_access2)
67bf215546Sopenharmony_ci      driver_flags |= IR3_DBG_ROBUST_UBO_ACCESS;
68bf215546Sopenharmony_ci   compiler->disk_cache = disk_cache_create(renderer, timestamp, driver_flags);
69bf215546Sopenharmony_ci}
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_civoid
72bf215546Sopenharmony_ciir3_disk_cache_init_shader_key(struct ir3_compiler *compiler,
73bf215546Sopenharmony_ci                               struct ir3_shader *shader)
74bf215546Sopenharmony_ci{
75bf215546Sopenharmony_ci   if (!compiler->disk_cache)
76bf215546Sopenharmony_ci      return;
77bf215546Sopenharmony_ci
78bf215546Sopenharmony_ci   struct mesa_sha1 ctx;
79bf215546Sopenharmony_ci
80bf215546Sopenharmony_ci   _mesa_sha1_init(&ctx);
81bf215546Sopenharmony_ci
82bf215546Sopenharmony_ci   /* Serialize the NIR to a binary blob that we can hash for the disk
83bf215546Sopenharmony_ci    * cache.  Drop unnecessary information (like variable names)
84bf215546Sopenharmony_ci    * so the serialized NIR is smaller, and also to let us detect more
85bf215546Sopenharmony_ci    * isomorphic shaders when hashing, increasing cache hits.
86bf215546Sopenharmony_ci    */
87bf215546Sopenharmony_ci   struct blob blob;
88bf215546Sopenharmony_ci   blob_init(&blob);
89bf215546Sopenharmony_ci   nir_serialize(&blob, shader->nir, true);
90bf215546Sopenharmony_ci   _mesa_sha1_update(&ctx, blob.data, blob.size);
91bf215546Sopenharmony_ci   blob_finish(&blob);
92bf215546Sopenharmony_ci
93bf215546Sopenharmony_ci   _mesa_sha1_update(&ctx, &shader->api_wavesize,
94bf215546Sopenharmony_ci                     sizeof(shader->api_wavesize));
95bf215546Sopenharmony_ci   _mesa_sha1_update(&ctx, &shader->real_wavesize,
96bf215546Sopenharmony_ci                     sizeof(shader->real_wavesize));
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_ci   /* Note that on some gens stream-out is lowered in ir3 to stg.  For later
99bf215546Sopenharmony_ci    * gens we maybe don't need to include stream-out in the cache key.
100bf215546Sopenharmony_ci    */
101bf215546Sopenharmony_ci   _mesa_sha1_update(&ctx, &shader->stream_output,
102bf215546Sopenharmony_ci                     sizeof(shader->stream_output));
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_ci   _mesa_sha1_final(&ctx, shader->cache_key);
105bf215546Sopenharmony_ci}
106bf215546Sopenharmony_ci
107bf215546Sopenharmony_cistatic void
108bf215546Sopenharmony_cicompute_variant_key(struct ir3_shader *shader, struct ir3_shader_variant *v,
109bf215546Sopenharmony_ci                    cache_key cache_key)
110bf215546Sopenharmony_ci{
111bf215546Sopenharmony_ci   struct blob blob;
112bf215546Sopenharmony_ci   blob_init(&blob);
113bf215546Sopenharmony_ci
114bf215546Sopenharmony_ci   blob_write_bytes(&blob, &shader->cache_key, sizeof(shader->cache_key));
115bf215546Sopenharmony_ci   blob_write_bytes(&blob, &v->key, sizeof(v->key));
116bf215546Sopenharmony_ci   blob_write_uint8(&blob, v->binning_pass);
117bf215546Sopenharmony_ci
118bf215546Sopenharmony_ci   disk_cache_compute_key(shader->compiler->disk_cache, blob.data, blob.size,
119bf215546Sopenharmony_ci                          cache_key);
120bf215546Sopenharmony_ci
121bf215546Sopenharmony_ci   blob_finish(&blob);
122bf215546Sopenharmony_ci}
123bf215546Sopenharmony_ci
124bf215546Sopenharmony_cistatic void
125bf215546Sopenharmony_ciretrieve_variant(struct blob_reader *blob, struct ir3_shader_variant *v)
126bf215546Sopenharmony_ci{
127bf215546Sopenharmony_ci   blob_copy_bytes(blob, VARIANT_CACHE_PTR(v), VARIANT_CACHE_SIZE);
128bf215546Sopenharmony_ci
129bf215546Sopenharmony_ci   /*
130bf215546Sopenharmony_ci    * pointers need special handling:
131bf215546Sopenharmony_ci    */
132bf215546Sopenharmony_ci
133bf215546Sopenharmony_ci   v->bin = rzalloc_size(v, v->info.size);
134bf215546Sopenharmony_ci   blob_copy_bytes(blob, v->bin, v->info.size);
135bf215546Sopenharmony_ci
136bf215546Sopenharmony_ci   if (!v->binning_pass) {
137bf215546Sopenharmony_ci      blob_copy_bytes(blob, v->const_state, sizeof(*v->const_state));
138bf215546Sopenharmony_ci      unsigned immeds_sz = v->const_state->immediates_size *
139bf215546Sopenharmony_ci                           sizeof(v->const_state->immediates[0]);
140bf215546Sopenharmony_ci      v->const_state->immediates = ralloc_size(v->const_state, immeds_sz);
141bf215546Sopenharmony_ci      blob_copy_bytes(blob, v->const_state->immediates, immeds_sz);
142bf215546Sopenharmony_ci   }
143bf215546Sopenharmony_ci}
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_cistatic void
146bf215546Sopenharmony_cistore_variant(struct blob *blob, struct ir3_shader_variant *v)
147bf215546Sopenharmony_ci{
148bf215546Sopenharmony_ci   blob_write_bytes(blob, VARIANT_CACHE_PTR(v), VARIANT_CACHE_SIZE);
149bf215546Sopenharmony_ci
150bf215546Sopenharmony_ci   /*
151bf215546Sopenharmony_ci    * pointers need special handling:
152bf215546Sopenharmony_ci    */
153bf215546Sopenharmony_ci
154bf215546Sopenharmony_ci   blob_write_bytes(blob, v->bin, v->info.size);
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_ci   /* No saving constant_data, it's already baked into bin at this point. */
157bf215546Sopenharmony_ci
158bf215546Sopenharmony_ci   if (!v->binning_pass) {
159bf215546Sopenharmony_ci      blob_write_bytes(blob, v->const_state, sizeof(*v->const_state));
160bf215546Sopenharmony_ci      unsigned immeds_sz = v->const_state->immediates_size *
161bf215546Sopenharmony_ci                           sizeof(v->const_state->immediates[0]);
162bf215546Sopenharmony_ci      blob_write_bytes(blob, v->const_state->immediates, immeds_sz);
163bf215546Sopenharmony_ci   }
164bf215546Sopenharmony_ci}
165bf215546Sopenharmony_ci
166bf215546Sopenharmony_cistruct ir3_shader_variant *
167bf215546Sopenharmony_ciir3_retrieve_variant(struct blob_reader *blob, struct ir3_compiler *compiler,
168bf215546Sopenharmony_ci                     void *mem_ctx)
169bf215546Sopenharmony_ci{
170bf215546Sopenharmony_ci   struct ir3_shader_variant *v = rzalloc_size(mem_ctx, sizeof(*v));
171bf215546Sopenharmony_ci
172bf215546Sopenharmony_ci   v->id = 0;
173bf215546Sopenharmony_ci   v->compiler = compiler;
174bf215546Sopenharmony_ci   v->binning_pass = false;
175bf215546Sopenharmony_ci   v->nonbinning = NULL;
176bf215546Sopenharmony_ci   v->binning = NULL;
177bf215546Sopenharmony_ci   blob_copy_bytes(blob, &v->key, sizeof(v->key));
178bf215546Sopenharmony_ci   v->type = blob_read_uint32(blob);
179bf215546Sopenharmony_ci   v->mergedregs = blob_read_uint32(blob);
180bf215546Sopenharmony_ci   v->const_state = rzalloc_size(v, sizeof(*v->const_state));
181bf215546Sopenharmony_ci
182bf215546Sopenharmony_ci   retrieve_variant(blob, v);
183bf215546Sopenharmony_ci
184bf215546Sopenharmony_ci   if (v->type == MESA_SHADER_VERTEX && ir3_has_binning_vs(&v->key)) {
185bf215546Sopenharmony_ci      v->binning = rzalloc_size(v, sizeof(*v->binning));
186bf215546Sopenharmony_ci      v->binning->id = 0;
187bf215546Sopenharmony_ci      v->binning->compiler = compiler;
188bf215546Sopenharmony_ci      v->binning->binning_pass = true;
189bf215546Sopenharmony_ci      v->binning->nonbinning = v;
190bf215546Sopenharmony_ci      v->binning->key = v->key;
191bf215546Sopenharmony_ci      v->binning->type = MESA_SHADER_VERTEX;
192bf215546Sopenharmony_ci      v->binning->mergedregs = v->mergedregs;
193bf215546Sopenharmony_ci      v->binning->const_state = v->const_state;
194bf215546Sopenharmony_ci
195bf215546Sopenharmony_ci      retrieve_variant(blob, v->binning);
196bf215546Sopenharmony_ci   }
197bf215546Sopenharmony_ci
198bf215546Sopenharmony_ci   return v;
199bf215546Sopenharmony_ci}
200bf215546Sopenharmony_ci
201bf215546Sopenharmony_civoid
202bf215546Sopenharmony_ciir3_store_variant(struct blob *blob, struct ir3_shader_variant *v)
203bf215546Sopenharmony_ci{
204bf215546Sopenharmony_ci   blob_write_bytes(blob, &v->key, sizeof(v->key));
205bf215546Sopenharmony_ci   blob_write_uint32(blob, v->type);
206bf215546Sopenharmony_ci   blob_write_uint32(blob, v->mergedregs);
207bf215546Sopenharmony_ci
208bf215546Sopenharmony_ci   store_variant(blob, v);
209bf215546Sopenharmony_ci
210bf215546Sopenharmony_ci   if (v->type == MESA_SHADER_VERTEX && ir3_has_binning_vs(&v->key)) {
211bf215546Sopenharmony_ci      store_variant(blob, v->binning);
212bf215546Sopenharmony_ci   }
213bf215546Sopenharmony_ci}
214bf215546Sopenharmony_ci
215bf215546Sopenharmony_cibool
216bf215546Sopenharmony_ciir3_disk_cache_retrieve(struct ir3_shader *shader,
217bf215546Sopenharmony_ci                        struct ir3_shader_variant *v)
218bf215546Sopenharmony_ci{
219bf215546Sopenharmony_ci   if (!shader->compiler->disk_cache)
220bf215546Sopenharmony_ci      return false;
221bf215546Sopenharmony_ci
222bf215546Sopenharmony_ci   cache_key cache_key;
223bf215546Sopenharmony_ci
224bf215546Sopenharmony_ci   compute_variant_key(shader, v, cache_key);
225bf215546Sopenharmony_ci
226bf215546Sopenharmony_ci   if (debug) {
227bf215546Sopenharmony_ci      char sha1[41];
228bf215546Sopenharmony_ci      _mesa_sha1_format(sha1, cache_key);
229bf215546Sopenharmony_ci      fprintf(stderr, "[mesa disk cache] retrieving variant %s: ", sha1);
230bf215546Sopenharmony_ci   }
231bf215546Sopenharmony_ci
232bf215546Sopenharmony_ci   size_t size;
233bf215546Sopenharmony_ci   void *buffer = disk_cache_get(shader->compiler->disk_cache, cache_key, &size);
234bf215546Sopenharmony_ci
235bf215546Sopenharmony_ci   if (debug)
236bf215546Sopenharmony_ci      fprintf(stderr, "%s\n", buffer ? "found" : "missing");
237bf215546Sopenharmony_ci
238bf215546Sopenharmony_ci   if (!buffer)
239bf215546Sopenharmony_ci      return false;
240bf215546Sopenharmony_ci
241bf215546Sopenharmony_ci   struct blob_reader blob;
242bf215546Sopenharmony_ci   blob_reader_init(&blob, buffer, size);
243bf215546Sopenharmony_ci
244bf215546Sopenharmony_ci   retrieve_variant(&blob, v);
245bf215546Sopenharmony_ci
246bf215546Sopenharmony_ci   if (v->binning)
247bf215546Sopenharmony_ci      retrieve_variant(&blob, v->binning);
248bf215546Sopenharmony_ci
249bf215546Sopenharmony_ci   free(buffer);
250bf215546Sopenharmony_ci
251bf215546Sopenharmony_ci   return true;
252bf215546Sopenharmony_ci}
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_civoid
255bf215546Sopenharmony_ciir3_disk_cache_store(struct ir3_shader *shader,
256bf215546Sopenharmony_ci                     struct ir3_shader_variant *v)
257bf215546Sopenharmony_ci{
258bf215546Sopenharmony_ci   if (!shader->compiler->disk_cache)
259bf215546Sopenharmony_ci      return;
260bf215546Sopenharmony_ci
261bf215546Sopenharmony_ci   cache_key cache_key;
262bf215546Sopenharmony_ci
263bf215546Sopenharmony_ci   compute_variant_key(shader, v, cache_key);
264bf215546Sopenharmony_ci
265bf215546Sopenharmony_ci   if (debug) {
266bf215546Sopenharmony_ci      char sha1[41];
267bf215546Sopenharmony_ci      _mesa_sha1_format(sha1, cache_key);
268bf215546Sopenharmony_ci      fprintf(stderr, "[mesa disk cache] storing variant %s\n", sha1);
269bf215546Sopenharmony_ci   }
270bf215546Sopenharmony_ci
271bf215546Sopenharmony_ci   struct blob blob;
272bf215546Sopenharmony_ci   blob_init(&blob);
273bf215546Sopenharmony_ci
274bf215546Sopenharmony_ci   store_variant(&blob, v);
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_ci   if (v->binning)
277bf215546Sopenharmony_ci      store_variant(&blob, v->binning);
278bf215546Sopenharmony_ci
279bf215546Sopenharmony_ci   disk_cache_put(shader->compiler->disk_cache, cache_key, blob.data, blob.size, NULL);
280bf215546Sopenharmony_ci   blob_finish(&blob);
281bf215546Sopenharmony_ci}
282