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