1 /*
2 * Copyright (c) 2022 Amazon.com, Inc. or its affiliates.
3 * Copyright © 2018 Intel Corporation
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR 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
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 #include <assert.h>
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <string.h>
28
29 #include "compiler/nir/nir.h"
30 #include "util/blob.h"
31 #include "util/build_id.h"
32 #include "util/disk_cache.h"
33 #include "util/mesa-sha1.h"
34
35 #include "pan_context.h"
36
37 #ifdef ENABLE_SHADER_CACHE
38 static bool debug = false;
39 #endif
40
41 extern int midgard_debug;
42 extern int bifrost_debug;
43
44 /**
45 * Compute a disk cache key for the given uncompiled shader and shader key.
46 */
47 static void
panfrost_disk_cache_compute_key(struct disk_cache * cache,const struct panfrost_uncompiled_shader * uncompiled,const struct panfrost_shader_key * shader_key,cache_key cache_key)48 panfrost_disk_cache_compute_key(
49 struct disk_cache *cache,
50 const struct panfrost_uncompiled_shader *uncompiled,
51 const struct panfrost_shader_key *shader_key, cache_key cache_key)
52 {
53 uint8_t data[sizeof(uncompiled->nir_sha1) + sizeof(*shader_key)];
54
55 memcpy(data, uncompiled->nir_sha1, sizeof(uncompiled->nir_sha1));
56 memcpy(data + sizeof(uncompiled->nir_sha1), shader_key, sizeof(*shader_key));
57
58 disk_cache_compute_key(cache, data, sizeof(data), cache_key);
59 }
60
61 /**
62 * Store the given compiled shader in the disk cache.
63 *
64 * This should only be called on newly compiled shaders. No checking is
65 * done to prevent repeated stores of the same shader.
66 */
67 void
panfrost_disk_cache_store(struct disk_cache * cache,const struct panfrost_uncompiled_shader * uncompiled,const struct panfrost_shader_key * key,const struct panfrost_shader_binary * binary)68 panfrost_disk_cache_store(struct disk_cache *cache,
69 const struct panfrost_uncompiled_shader *uncompiled,
70 const struct panfrost_shader_key *key,
71 const struct panfrost_shader_binary *binary)
72 {
73 #ifdef ENABLE_SHADER_CACHE
74 if (!cache)
75 return;
76
77 cache_key cache_key;
78 panfrost_disk_cache_compute_key(cache, uncompiled, key, cache_key);
79
80 if (debug) {
81 char sha1[41];
82 _mesa_sha1_format(sha1, cache_key);
83 fprintf(stderr, "[mesa disk cache] storing %s\n", sha1);
84 }
85
86 struct blob blob;
87 blob_init(&blob);
88
89 /* We write the following data to the cache blob:
90 *
91 * 1. Size of program binary
92 * 2. Program binary
93 * 3. Shader info
94 * 4. System values
95 */
96 blob_write_uint32(&blob, binary->binary.size);
97 blob_write_bytes(&blob, binary->binary.data, binary->binary.size);
98 blob_write_bytes(&blob, &binary->info, sizeof(binary->info));
99 blob_write_bytes(&blob, &binary->sysvals, sizeof(binary->sysvals));
100
101 disk_cache_put(cache, cache_key, blob.data, blob.size, NULL);
102 blob_finish(&blob);
103 #endif
104 }
105
106 /**
107 * Search for a compiled shader in the disk cache.
108 */
109 bool
panfrost_disk_cache_retrieve(struct disk_cache * cache,const struct panfrost_uncompiled_shader * uncompiled,const struct panfrost_shader_key * key,struct panfrost_shader_binary * binary)110 panfrost_disk_cache_retrieve(struct disk_cache *cache,
111 const struct panfrost_uncompiled_shader *uncompiled,
112 const struct panfrost_shader_key *key,
113 struct panfrost_shader_binary *binary)
114 {
115 #ifdef ENABLE_SHADER_CACHE
116 if (!cache)
117 return false;
118
119 cache_key cache_key;
120 panfrost_disk_cache_compute_key(cache, uncompiled, key, cache_key);
121
122 if (debug) {
123 char sha1[41];
124 _mesa_sha1_format(sha1, cache_key);
125 fprintf(stderr, "[mesa disk cache] retrieving %s: ", sha1);
126 }
127
128 size_t size;
129 void *buffer = disk_cache_get(cache, cache_key, &size);
130
131 if (debug)
132 fprintf(stderr, "%s\n", buffer ? "found" : "missing");
133
134 if (!buffer)
135 return false;
136
137 struct blob_reader blob;
138 blob_reader_init(&blob, buffer, size);
139
140 util_dynarray_init(&binary->binary, NULL);
141
142 uint32_t binary_size = blob_read_uint32(&blob);
143 void *ptr = util_dynarray_resize_bytes(&binary->binary, binary_size, 1);
144
145 blob_copy_bytes(&blob, ptr, binary_size);
146 blob_copy_bytes(&blob, &binary->info, sizeof(binary->info));
147 blob_copy_bytes(&blob, &binary->sysvals, sizeof(binary->sysvals));
148
149 free(buffer);
150
151 return true;
152 #else
153 return false;
154 #endif
155 }
156
157 /**
158 * Initialize the on-disk shader cache.
159 */
160 void
panfrost_disk_cache_init(struct panfrost_screen * screen)161 panfrost_disk_cache_init(struct panfrost_screen *screen)
162 {
163 #ifdef ENABLE_SHADER_CACHE
164 const char *renderer = screen->base.get_name(&screen->base);
165
166 const struct build_id_note *note =
167 build_id_find_nhdr_for_addr(panfrost_disk_cache_init);
168 assert(note && build_id_length(note) == 20); /* sha1 */
169
170 const uint8_t *id_sha1 = build_id_data(note);
171 assert(id_sha1);
172
173 char timestamp[41];
174 _mesa_sha1_format(timestamp, id_sha1);
175
176 /* Consider any flags affecting the compile when caching */
177 uint64_t driver_flags = screen->dev.debug;
178 driver_flags |= ((uint64_t)(midgard_debug | bifrost_debug) << 32);
179
180 screen->disk_cache = disk_cache_create(renderer, timestamp, driver_flags);
181 #endif
182 }
183