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 static bool debug = false;
38
39 extern int midgard_debug;
40 extern int bifrost_debug;
41
42 /**
43 * Compute a disk cache key for the given uncompiled shader and shader key.
44 */
45 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)46 panfrost_disk_cache_compute_key(
47 struct disk_cache *cache,
48 const struct panfrost_uncompiled_shader *uncompiled,
49 const struct panfrost_shader_key *shader_key, cache_key cache_key)
50 {
51 uint8_t data[sizeof(uncompiled->nir_sha1) + sizeof(*shader_key)];
52
53 memcpy(data, uncompiled->nir_sha1, sizeof(uncompiled->nir_sha1));
54 memcpy(data + sizeof(uncompiled->nir_sha1), shader_key, sizeof(*shader_key));
55
56 disk_cache_compute_key(cache, data, sizeof(data), cache_key);
57 }
58
59 /**
60 * Store the given compiled shader in the disk cache.
61 *
62 * This should only be called on newly compiled shaders. No checking is
63 * done to prevent repeated stores of the same shader.
64 */
65 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)66 panfrost_disk_cache_store(struct disk_cache *cache,
67 const struct panfrost_uncompiled_shader *uncompiled,
68 const struct panfrost_shader_key *key,
69 const struct panfrost_shader_binary *binary)
70 {
71 #ifdef ENABLE_SHADER_CACHE
72 if (!cache)
73 return;
74
75 cache_key cache_key;
76 panfrost_disk_cache_compute_key(cache, uncompiled, key, cache_key);
77
78 if (debug) {
79 char sha1[41];
80 _mesa_sha1_format(sha1, cache_key);
81 fprintf(stderr, "[mesa disk cache] storing %s\n", sha1);
82 }
83
84 struct blob blob;
85 blob_init(&blob);
86
87 /* We write the following data to the cache blob:
88 *
89 * 1. Size of program binary
90 * 2. Program binary
91 * 3. Shader info
92 * 4. System values
93 */
94 blob_write_uint32(&blob, binary->binary.size);
95 blob_write_bytes(&blob, binary->binary.data, binary->binary.size);
96 blob_write_bytes(&blob, &binary->info, sizeof(binary->info));
97 blob_write_bytes(&blob, &binary->sysvals, sizeof(binary->sysvals));
98
99 disk_cache_put(cache, cache_key, blob.data, blob.size, NULL);
100 blob_finish(&blob);
101 #endif
102 }
103
104 /**
105 * Search for a compiled shader in the disk cache.
106 */
107 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)108 panfrost_disk_cache_retrieve(struct disk_cache *cache,
109 const struct panfrost_uncompiled_shader *uncompiled,
110 const struct panfrost_shader_key *key,
111 struct panfrost_shader_binary *binary)
112 {
113 #ifdef ENABLE_SHADER_CACHE
114 if (!cache)
115 return false;
116
117 cache_key cache_key;
118 panfrost_disk_cache_compute_key(cache, uncompiled, key, cache_key);
119
120 if (debug) {
121 char sha1[41];
122 _mesa_sha1_format(sha1, cache_key);
123 fprintf(stderr, "[mesa disk cache] retrieving %s: ", sha1);
124 }
125
126 size_t size;
127 void *buffer = disk_cache_get(cache, cache_key, &size);
128
129 if (debug)
130 fprintf(stderr, "%s\n", buffer ? "found" : "missing");
131
132 if (!buffer)
133 return false;
134
135 struct blob_reader blob;
136 blob_reader_init(&blob, buffer, size);
137
138 util_dynarray_init(&binary->binary, NULL);
139
140 uint32_t binary_size = blob_read_uint32(&blob);
141 void *ptr = util_dynarray_resize_bytes(&binary->binary, binary_size, 1);
142
143 blob_copy_bytes(&blob, ptr, binary_size);
144 blob_copy_bytes(&blob, &binary->info, sizeof(binary->info));
145 blob_copy_bytes(&blob, &binary->sysvals, sizeof(binary->sysvals));
146
147 free(buffer);
148
149 return true;
150 #else
151 return false;
152 #endif
153 }
154
155 /**
156 * Initialize the on-disk shader cache.
157 */
158 void
panfrost_disk_cache_init(struct panfrost_screen * screen)159 panfrost_disk_cache_init(struct panfrost_screen *screen)
160 {
161 #ifdef ENABLE_SHADER_CACHE
162 const char *renderer = screen->base.get_name(&screen->base);
163
164 const struct build_id_note *note =
165 build_id_find_nhdr_for_addr(panfrost_disk_cache_init);
166 assert(note && build_id_length(note) == 20); /* sha1 */
167
168 const uint8_t *id_sha1 = build_id_data(note);
169 assert(id_sha1);
170
171 char timestamp[41];
172 _mesa_sha1_format(timestamp, id_sha1);
173
174 /* Consider any flags affecting the compile when caching */
175 uint64_t driver_flags = screen->dev.debug;
176 driver_flags |= ((uint64_t)(midgard_debug | bifrost_debug) << 32);
177
178 screen->disk_cache = disk_cache_create(renderer, timestamp, driver_flags);
179 #endif
180 }
181