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