• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2020 Google, Inc.
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 FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23 
24 #include "nir_serialize.h"
25 
26 #include "ir3_compiler.h"
27 #include "ir3_nir.h"
28 
29 #define debug 0
30 
31 /*
32  * Shader disk-cache implementation.
33  *
34  * Note that at least in the EGL_ANDROID_blob_cache, we should never
35  * rely on inter-dependencies between different cache entries:
36  *
37  *    No guarantees are made as to whether a given key/value pair is present in
38  *    the cache after the set call.  If a different value has been associated
39  *    with the given key in the past then it is undefined which value, if any, is
40  *    associated with the key after the set call.  Note that while there are no
41  *    guarantees, the cache implementation should attempt to cache the most
42  *    recently set value for a given key.
43  *
44  * for this reason, because binning pass variants share const_state with
45  * their draw-pass counterpart, both variants are serialized together.
46  */
47 
48 void
ir3_disk_cache_init(struct ir3_compiler * compiler)49 ir3_disk_cache_init(struct ir3_compiler *compiler)
50 {
51 	if (ir3_shader_debug & IR3_DBG_NOCACHE)
52 		return;
53 
54 	/* array length = print length + nul char + 1 extra to verify it's unused */
55 	char renderer[7];
56 	ASSERTED int len =
57 			snprintf(renderer, sizeof(renderer), "FD%03d", compiler->gpu_id);
58 	assert(len == sizeof(renderer) - 2);
59 
60 	const struct build_id_note *note =
61 			build_id_find_nhdr_for_addr(ir3_disk_cache_init);
62 	assert(note && build_id_length(note) == 20); /* sha1 */
63 
64 	const uint8_t *id_sha1 = build_id_data(note);
65 	assert(id_sha1);
66 
67 	char timestamp[41];
68 	_mesa_sha1_format(timestamp, id_sha1);
69 
70 	const uint64_t driver_flags = ir3_shader_debug;
71 	compiler->disk_cache = disk_cache_create(renderer, timestamp, driver_flags);
72 }
73 
74 void
ir3_disk_cache_init_shader_key(struct ir3_compiler * compiler,struct ir3_shader * shader)75 ir3_disk_cache_init_shader_key(struct ir3_compiler *compiler,
76 		struct ir3_shader *shader)
77 {
78 	if (!compiler->disk_cache)
79 		return;
80 
81 	struct mesa_sha1 ctx;
82 
83 	_mesa_sha1_init(&ctx);
84 
85 	/* Serialize the NIR to a binary blob that we can hash for the disk
86 	 * cache.  Drop unnecessary information (like variable names)
87 	 * so the serialized NIR is smaller, and also to let us detect more
88 	 * isomorphic shaders when hashing, increasing cache hits.
89 	 */
90 	struct blob blob;
91 	blob_init(&blob);
92 	nir_serialize(&blob, shader->nir, true);
93 	_mesa_sha1_update(&ctx, blob.data, blob.size);
94 	blob_finish(&blob);
95 
96 	/* Note that on some gens stream-out is lowered in ir3 to stg.  For later
97 	 * gens we maybe don't need to include stream-out in the cache key.
98 	 */
99 	_mesa_sha1_update(&ctx, &shader->stream_output, sizeof(shader->stream_output));
100 
101 	_mesa_sha1_final(&ctx, shader->cache_key);
102 }
103 
104 static void
compute_variant_key(struct ir3_compiler * compiler,struct ir3_shader_variant * v,cache_key cache_key)105 compute_variant_key(struct ir3_compiler *compiler,
106 		struct ir3_shader_variant *v, cache_key cache_key)
107 {
108 	struct blob blob;
109 	blob_init(&blob);
110 
111 	blob_write_bytes(&blob, &v->shader->cache_key, sizeof(v->shader->cache_key));
112 	blob_write_bytes(&blob, &v->key, sizeof(v->key));
113 	blob_write_uint8(&blob, v->binning_pass);
114 
115 	disk_cache_compute_key(compiler->disk_cache, blob.data, blob.size, cache_key);
116 
117 	blob_finish(&blob);
118 }
119 
120 static void
retrieve_variant(struct blob_reader * blob,struct ir3_shader_variant * v)121 retrieve_variant(struct blob_reader *blob, struct ir3_shader_variant *v)
122 {
123 	blob_copy_bytes(blob, VARIANT_CACHE_PTR(v), VARIANT_CACHE_SIZE);
124 
125 	/*
126 	 * pointers need special handling:
127 	 */
128 
129 	v->bin = rzalloc_size(v, 4 * v->info.sizedwords);
130 	blob_copy_bytes(blob, v->bin, 4 * v->info.sizedwords);
131 
132 	if (!v->binning_pass) {
133 		blob_copy_bytes(blob, v->const_state, sizeof(*v->const_state));
134 		unsigned immeds_sz = v->const_state->immediates_size *
135 				sizeof(v->const_state->immediates[0]);
136 		v->const_state->immediates = ralloc_size(v->const_state, immeds_sz);
137 		blob_copy_bytes(blob, v->const_state->immediates, immeds_sz);
138 	}
139 }
140 
141 static void
store_variant(struct blob * blob,struct ir3_shader_variant * v)142 store_variant(struct blob *blob, struct ir3_shader_variant *v)
143 {
144 	blob_write_bytes(blob, VARIANT_CACHE_PTR(v), VARIANT_CACHE_SIZE);
145 
146 	/*
147 	 * pointers need special handling:
148 	 */
149 
150 	blob_write_bytes(blob, v->bin, 4 * v->info.sizedwords);
151 
152 	if (!v->binning_pass) {
153 		blob_write_bytes(blob, v->const_state, sizeof(*v->const_state));
154 		unsigned immeds_sz = v->const_state->immediates_size *
155 				sizeof(v->const_state->immediates[0]);
156 		blob_write_bytes(blob, v->const_state->immediates, immeds_sz);
157 	}
158 }
159 
160 bool
ir3_disk_cache_retrieve(struct ir3_compiler * compiler,struct ir3_shader_variant * v)161 ir3_disk_cache_retrieve(struct ir3_compiler *compiler,
162 		struct ir3_shader_variant *v)
163 {
164 	if (!compiler->disk_cache)
165 		return false;
166 
167 	cache_key cache_key;
168 
169 	compute_variant_key(compiler, v, cache_key);
170 
171 	if (debug) {
172 		char sha1[41];
173 		_mesa_sha1_format(sha1, cache_key);
174 		fprintf(stderr, "[mesa disk cache] retrieving variant %s: ", sha1);
175 	}
176 
177 	size_t size;
178 	void *buffer = disk_cache_get(compiler->disk_cache, cache_key, &size);
179 
180 	if (debug)
181 		fprintf(stderr, "%s\n", buffer ? "found" : "missing");
182 
183 	if (!buffer)
184 		return false;
185 
186 	struct blob_reader blob;
187 	blob_reader_init(&blob, buffer, size);
188 
189 	retrieve_variant(&blob, v);
190 
191 	if (v->binning)
192 		retrieve_variant(&blob, v->binning);
193 
194 	free(buffer);
195 
196 	return true;
197 }
198 
199 void
ir3_disk_cache_store(struct ir3_compiler * compiler,struct ir3_shader_variant * v)200 ir3_disk_cache_store(struct ir3_compiler *compiler,
201 		struct ir3_shader_variant *v)
202 {
203 	if (!compiler->disk_cache)
204 		return;
205 
206 	cache_key cache_key;
207 
208 	compute_variant_key(compiler, v, cache_key);
209 
210 	if (debug) {
211 		char sha1[41];
212 		_mesa_sha1_format(sha1, cache_key);
213 		fprintf(stderr, "[mesa disk cache] storing variant %s\n", sha1);
214 	}
215 
216 	struct blob blob;
217 	blob_init(&blob);
218 
219 	store_variant(&blob, v);
220 
221 	if (v->binning)
222 		store_variant(&blob, v->binning);
223 
224 	disk_cache_put(compiler->disk_cache, cache_key, blob.data, blob.size, NULL);
225 	blob_finish(&blob);
226 }
227