• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2022 Raspberry Pi Ltd
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 /**
25  * V3D on-disk shader cache.
26  */
27 
28 #include "v3d_context.h"
29 
30 #include "util/blob.h"
31 #include "util/u_upload_mgr.h"
32 
33 #ifdef ENABLE_SHADER_CACHE
34 
35 static uint32_t
v3d_key_size(gl_shader_stage stage)36 v3d_key_size(gl_shader_stage stage)
37 {
38         static const int key_size[] = {
39                 [MESA_SHADER_VERTEX] = sizeof(struct v3d_vs_key),
40                 [MESA_SHADER_GEOMETRY] = sizeof(struct v3d_gs_key),
41                 [MESA_SHADER_FRAGMENT] = sizeof(struct v3d_fs_key),
42                 [MESA_SHADER_COMPUTE] = sizeof(struct v3d_key),
43         };
44 
45         assert(stage >= 0 &&
46                stage < ARRAY_SIZE(key_size) &&
47                key_size[stage]);
48 
49         return key_size[stage];
50 }
51 
v3d_disk_cache_init(struct v3d_screen * screen)52 void v3d_disk_cache_init(struct v3d_screen *screen)
53 {
54         char *renderer;
55 
56         ASSERTED int len =
57                 asprintf(&renderer, "V3D %d.%d",
58                          screen->devinfo.ver / 10,
59                          screen->devinfo.ver % 10);
60         assert(len > 0);
61 
62         const struct build_id_note *note =
63                 build_id_find_nhdr_for_addr(v3d_disk_cache_init);
64         assert(note && build_id_length(note) == 20);
65 
66         const uint8_t *id_sha1 = build_id_data(note);
67         assert(id_sha1);
68 
69         char timestamp[41];
70         _mesa_sha1_format(timestamp, id_sha1);
71 
72         screen->disk_cache = disk_cache_create(renderer, timestamp, v3d_mesa_debug);
73 
74         free(renderer);
75 }
76 
77 static void
v3d_disk_cache_compute_key(struct disk_cache * cache,const struct v3d_key * key,cache_key cache_key,const struct v3d_uncompiled_shader * uncompiled)78 v3d_disk_cache_compute_key(struct disk_cache *cache,
79                            const struct v3d_key *key,
80                            cache_key cache_key,
81                            const struct v3d_uncompiled_shader *uncompiled)
82 {
83         assert(cache);
84 
85         assert(uncompiled->base.type == PIPE_SHADER_IR_NIR);
86         nir_shader *nir = uncompiled->base.ir.nir;
87 
88         uint32_t ckey_size = v3d_key_size(nir->info.stage);
89         struct v3d_key *ckey = malloc(ckey_size);
90         memcpy(ckey, key, ckey_size);
91 
92         struct blob blob;
93         blob_init(&blob);
94         blob_write_bytes(&blob, ckey, ckey_size);
95         blob_write_bytes(&blob, uncompiled->sha1, 20);
96 
97         disk_cache_compute_key(cache, blob.data, blob.size, cache_key);
98 
99         blob_finish(&blob);
100         free(ckey);
101 }
102 
103 struct v3d_compiled_shader *
v3d_disk_cache_retrieve(struct v3d_context * v3d,const struct v3d_key * key,const struct v3d_uncompiled_shader * uncompiled)104 v3d_disk_cache_retrieve(struct v3d_context *v3d,
105                         const struct v3d_key *key,
106                         const struct v3d_uncompiled_shader *uncompiled)
107 {
108         struct v3d_screen *screen = v3d->screen;
109         struct disk_cache *cache = screen->disk_cache;
110 
111         if (!cache)
112                 return NULL;
113 
114         assert(uncompiled->base.type == PIPE_SHADER_IR_NIR);
115         nir_shader *nir = uncompiled->base.ir.nir;
116 
117         cache_key cache_key;
118         v3d_disk_cache_compute_key(cache, key, cache_key, uncompiled);
119 
120         size_t buffer_size;
121         void *buffer = disk_cache_get(cache, cache_key, &buffer_size);
122 
123         if (V3D_DBG(CACHE)) {
124                 char sha1[41];
125                 _mesa_sha1_format(sha1, cache_key);
126                 fprintf(stderr, "[v3d on-disk cache] %s %s\n",
127                         buffer ? "hit" : "miss",
128                         sha1);
129         }
130 
131         if (!buffer)
132                 return NULL;
133 
134         /* Load data */
135         struct blob_reader blob;
136         blob_reader_init(&blob, buffer, buffer_size);
137 
138         uint32_t prog_data_size = v3d_prog_data_size(nir->info.stage);
139         const void *prog_data = blob_read_bytes(&blob, prog_data_size);
140         if (blob.overrun)
141                 return NULL;
142 
143         uint32_t ulist_count = blob_read_uint32(&blob);
144         uint32_t ulist_contents_size = ulist_count * sizeof(enum quniform_contents);
145         const void *ulist_contents = blob_read_bytes(&blob, ulist_contents_size);
146         if (blob.overrun)
147                 return NULL;
148 
149         uint32_t ulist_data_size = ulist_count * sizeof(uint32_t);
150         const void *ulist_data = blob_read_bytes(&blob, ulist_data_size);
151         if (blob.overrun)
152                 return NULL;
153 
154         uint32_t qpu_size = blob_read_uint32(&blob);
155         const void *qpu_insts =
156                 blob_read_bytes(&blob, qpu_size);
157         if (blob.overrun)
158                 return NULL;
159 
160         /* Assemble data */
161         struct v3d_compiled_shader *shader = rzalloc(NULL, struct v3d_compiled_shader);
162 
163         shader->prog_data.base = rzalloc_size(shader, prog_data_size);
164         memcpy(shader->prog_data.base, prog_data, prog_data_size);
165 
166         shader->prog_data.base->uniforms.count = ulist_count;
167 
168         shader->prog_data.base->uniforms.contents =
169                 ralloc_array(shader->prog_data.base, enum quniform_contents, ulist_count);
170         memcpy(shader->prog_data.base->uniforms.contents, ulist_contents, ulist_contents_size);
171 
172         shader->prog_data.base->uniforms.data =
173                 ralloc_array(shader->prog_data.base, uint32_t, ulist_count);
174         memcpy(shader->prog_data.base->uniforms.data, ulist_data, ulist_data_size);
175 
176         u_upload_data(v3d->state_uploader, 0, qpu_size, 8,
177                       qpu_insts, &shader->offset, &shader->resource);
178 
179         free(buffer);
180 
181         return shader;
182 }
183 
184 void
v3d_disk_cache_store(struct v3d_context * v3d,const struct v3d_key * key,const struct v3d_uncompiled_shader * uncompiled,const struct v3d_compiled_shader * shader,uint64_t * qpu_insts,uint32_t qpu_size)185 v3d_disk_cache_store(struct v3d_context *v3d,
186                      const struct v3d_key *key,
187                      const struct v3d_uncompiled_shader *uncompiled,
188                      const struct v3d_compiled_shader *shader,
189                      uint64_t *qpu_insts,
190                      uint32_t qpu_size)
191 {
192         struct v3d_screen *screen = v3d->screen;
193         struct disk_cache *cache = screen->disk_cache;
194 
195         if (!cache)
196                 return;
197 
198         assert(uncompiled->base.type == PIPE_SHADER_IR_NIR);
199         nir_shader *nir = uncompiled->base.ir.nir;
200 
201         cache_key cache_key;
202         v3d_disk_cache_compute_key(cache, key, cache_key, uncompiled);
203 
204         if (V3D_DBG(CACHE)) {
205                 char sha1[41];
206                 _mesa_sha1_format(sha1, cache_key);
207                 fprintf(stderr, "[v3d on-disk cache] storing %s\n", sha1);
208         }
209 
210         struct blob blob;
211         blob_init(&blob);
212 
213         blob_write_bytes(&blob, shader->prog_data.base, v3d_prog_data_size(nir->info.stage));
214         uint32_t ulist_count = shader->prog_data.base->uniforms.count;
215         blob_write_uint32(&blob, ulist_count);
216         blob_write_bytes(&blob,
217                          shader->prog_data.base->uniforms.contents,
218                          ulist_count * sizeof(enum quniform_contents));
219         blob_write_bytes(&blob,
220                          shader->prog_data.base->uniforms.data,
221                          ulist_count * sizeof(uint32_t));
222 
223         blob_write_uint32(&blob, qpu_size);
224         blob_write_bytes(&blob, qpu_insts, qpu_size);
225 
226         disk_cache_put(cache, cache_key, blob.data, blob.size, NULL);
227 
228         blob_finish(&blob);
229 }
230 
231 #endif /* ENABLE_SHADER_CACHE */
232 
233