1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2020 Intel Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include "nir.h"
25bf215546Sopenharmony_ci#include "nir_serialize.h"
26bf215546Sopenharmony_ci#include "nir_spirv.h"
27bf215546Sopenharmony_ci#include "util/mesa-sha1.h"
28bf215546Sopenharmony_ci
29bf215546Sopenharmony_ci#ifdef DYNAMIC_LIBCLC_PATH
30bf215546Sopenharmony_ci#include <fcntl.h>
31bf215546Sopenharmony_ci#include <sys/types.h>
32bf215546Sopenharmony_ci#include <sys/stat.h>
33bf215546Sopenharmony_ci#include <sys/mman.h>
34bf215546Sopenharmony_ci#include <unistd.h>
35bf215546Sopenharmony_ci#endif
36bf215546Sopenharmony_ci
37bf215546Sopenharmony_ci#ifdef HAVE_STATIC_LIBCLC_ZSTD
38bf215546Sopenharmony_ci#include <zstd.h>
39bf215546Sopenharmony_ci#endif
40bf215546Sopenharmony_ci
41bf215546Sopenharmony_ci#ifdef HAVE_STATIC_LIBCLC_SPIRV
42bf215546Sopenharmony_ci#include "spirv-mesa3d-.spv.h"
43bf215546Sopenharmony_ci#endif
44bf215546Sopenharmony_ci
45bf215546Sopenharmony_ci#ifdef HAVE_STATIC_LIBCLC_SPIRV64
46bf215546Sopenharmony_ci#include "spirv64-mesa3d-.spv.h"
47bf215546Sopenharmony_ci#endif
48bf215546Sopenharmony_ci
49bf215546Sopenharmony_cistruct clc_file {
50bf215546Sopenharmony_ci   unsigned bit_size;
51bf215546Sopenharmony_ci   const char *static_data;
52bf215546Sopenharmony_ci   size_t static_data_size;
53bf215546Sopenharmony_ci   const char *sys_path;
54bf215546Sopenharmony_ci};
55bf215546Sopenharmony_ci
56bf215546Sopenharmony_cistatic const struct clc_file libclc_files[] = {
57bf215546Sopenharmony_ci   {
58bf215546Sopenharmony_ci      .bit_size = 32,
59bf215546Sopenharmony_ci#ifdef HAVE_STATIC_LIBCLC_SPIRV
60bf215546Sopenharmony_ci      .static_data = libclc_spirv_mesa3d_spv,
61bf215546Sopenharmony_ci      .static_data_size = sizeof(libclc_spirv_mesa3d_spv),
62bf215546Sopenharmony_ci#endif
63bf215546Sopenharmony_ci#ifdef DYNAMIC_LIBCLC_PATH
64bf215546Sopenharmony_ci      .sys_path = DYNAMIC_LIBCLC_PATH "spirv-mesa3d-.spv",
65bf215546Sopenharmony_ci#endif
66bf215546Sopenharmony_ci   },
67bf215546Sopenharmony_ci   {
68bf215546Sopenharmony_ci      .bit_size = 64,
69bf215546Sopenharmony_ci#ifdef HAVE_STATIC_LIBCLC_SPIRV64
70bf215546Sopenharmony_ci      .static_data = libclc_spirv64_mesa3d_spv,
71bf215546Sopenharmony_ci      .static_data_size = sizeof(libclc_spirv64_mesa3d_spv),
72bf215546Sopenharmony_ci#endif
73bf215546Sopenharmony_ci#ifdef DYNAMIC_LIBCLC_PATH
74bf215546Sopenharmony_ci      .sys_path = DYNAMIC_LIBCLC_PATH "spirv64-mesa3d-.spv",
75bf215546Sopenharmony_ci#endif
76bf215546Sopenharmony_ci   },
77bf215546Sopenharmony_ci};
78bf215546Sopenharmony_ci
79bf215546Sopenharmony_cistatic const struct clc_file *
80bf215546Sopenharmony_ciget_libclc_file(unsigned ptr_bit_size)
81bf215546Sopenharmony_ci{
82bf215546Sopenharmony_ci   assert(ptr_bit_size == 32 || ptr_bit_size == 64);
83bf215546Sopenharmony_ci   return &libclc_files[ptr_bit_size / 64];
84bf215546Sopenharmony_ci}
85bf215546Sopenharmony_ci
86bf215546Sopenharmony_cistruct clc_data {
87bf215546Sopenharmony_ci   const struct clc_file *file;
88bf215546Sopenharmony_ci
89bf215546Sopenharmony_ci   unsigned char cache_key[20];
90bf215546Sopenharmony_ci
91bf215546Sopenharmony_ci   int fd;
92bf215546Sopenharmony_ci   const void *data;
93bf215546Sopenharmony_ci   size_t size;
94bf215546Sopenharmony_ci};
95bf215546Sopenharmony_ci
96bf215546Sopenharmony_cistatic bool
97bf215546Sopenharmony_ciopen_clc_data(struct clc_data *clc, unsigned ptr_bit_size)
98bf215546Sopenharmony_ci{
99bf215546Sopenharmony_ci   memset(clc, 0, sizeof(*clc));
100bf215546Sopenharmony_ci   clc->file = get_libclc_file(ptr_bit_size);
101bf215546Sopenharmony_ci   clc->fd = -1;
102bf215546Sopenharmony_ci
103bf215546Sopenharmony_ci   if (clc->file->static_data) {
104bf215546Sopenharmony_ci      snprintf((char *)clc->cache_key, sizeof(clc->cache_key),
105bf215546Sopenharmony_ci               "libclc-spirv%d", ptr_bit_size);
106bf215546Sopenharmony_ci      return true;
107bf215546Sopenharmony_ci   }
108bf215546Sopenharmony_ci
109bf215546Sopenharmony_ci#ifdef DYNAMIC_LIBCLC_PATH
110bf215546Sopenharmony_ci   if (clc->file->sys_path != NULL) {
111bf215546Sopenharmony_ci      int fd = open(clc->file->sys_path, O_RDONLY);
112bf215546Sopenharmony_ci      if (fd < 0)
113bf215546Sopenharmony_ci         return false;
114bf215546Sopenharmony_ci
115bf215546Sopenharmony_ci      struct stat stat;
116bf215546Sopenharmony_ci      int ret = fstat(fd, &stat);
117bf215546Sopenharmony_ci      if (ret < 0) {
118bf215546Sopenharmony_ci         fprintf(stderr, "fstat failed on %s: %m\n", clc->file->sys_path);
119bf215546Sopenharmony_ci         close(fd);
120bf215546Sopenharmony_ci         return false;
121bf215546Sopenharmony_ci      }
122bf215546Sopenharmony_ci
123bf215546Sopenharmony_ci      struct mesa_sha1 ctx;
124bf215546Sopenharmony_ci      _mesa_sha1_init(&ctx);
125bf215546Sopenharmony_ci      _mesa_sha1_update(&ctx, clc->file->sys_path, strlen(clc->file->sys_path));
126bf215546Sopenharmony_ci      _mesa_sha1_update(&ctx, &stat.st_mtim, sizeof(stat.st_mtim));
127bf215546Sopenharmony_ci      _mesa_sha1_final(&ctx, clc->cache_key);
128bf215546Sopenharmony_ci
129bf215546Sopenharmony_ci      clc->fd = fd;
130bf215546Sopenharmony_ci
131bf215546Sopenharmony_ci      return true;
132bf215546Sopenharmony_ci   }
133bf215546Sopenharmony_ci#endif
134bf215546Sopenharmony_ci
135bf215546Sopenharmony_ci   return false;
136bf215546Sopenharmony_ci}
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_ci#define SPIRV_WORD_SIZE 4
139bf215546Sopenharmony_ci
140bf215546Sopenharmony_cistatic bool
141bf215546Sopenharmony_cimap_clc_data(struct clc_data *clc)
142bf215546Sopenharmony_ci{
143bf215546Sopenharmony_ci   if (clc->file->static_data) {
144bf215546Sopenharmony_ci#ifdef HAVE_STATIC_LIBCLC_ZSTD
145bf215546Sopenharmony_ci      unsigned long long cmp_size =
146bf215546Sopenharmony_ci         ZSTD_getFrameContentSize(clc->file->static_data,
147bf215546Sopenharmony_ci                                  clc->file->static_data_size);
148bf215546Sopenharmony_ci      if (cmp_size == ZSTD_CONTENTSIZE_UNKNOWN ||
149bf215546Sopenharmony_ci          cmp_size == ZSTD_CONTENTSIZE_ERROR) {
150bf215546Sopenharmony_ci         fprintf(stderr, "Could not determine the decompressed size of the "
151bf215546Sopenharmony_ci                         "libclc SPIR-V\n");
152bf215546Sopenharmony_ci         return false;
153bf215546Sopenharmony_ci      }
154bf215546Sopenharmony_ci
155bf215546Sopenharmony_ci      size_t frame_size =
156bf215546Sopenharmony_ci         ZSTD_findFrameCompressedSize(clc->file->static_data,
157bf215546Sopenharmony_ci                                      clc->file->static_data_size);
158bf215546Sopenharmony_ci      if (ZSTD_isError(frame_size)) {
159bf215546Sopenharmony_ci         fprintf(stderr, "Could not determine the size of the first ZSTD frame "
160bf215546Sopenharmony_ci                         "when decompressing libclc SPIR-V: %s\n",
161bf215546Sopenharmony_ci                 ZSTD_getErrorName(frame_size));
162bf215546Sopenharmony_ci         return false;
163bf215546Sopenharmony_ci      }
164bf215546Sopenharmony_ci
165bf215546Sopenharmony_ci      void *dest = malloc(cmp_size + 1);
166bf215546Sopenharmony_ci      size_t size = ZSTD_decompress(dest, cmp_size, clc->file->static_data,
167bf215546Sopenharmony_ci                                    frame_size);
168bf215546Sopenharmony_ci      if (ZSTD_isError(size)) {
169bf215546Sopenharmony_ci         free(dest);
170bf215546Sopenharmony_ci         fprintf(stderr, "Error decompressing libclc SPIR-V: %s\n",
171bf215546Sopenharmony_ci                 ZSTD_getErrorName(size));
172bf215546Sopenharmony_ci         return false;
173bf215546Sopenharmony_ci      }
174bf215546Sopenharmony_ci
175bf215546Sopenharmony_ci      clc->data = dest;
176bf215546Sopenharmony_ci      clc->size = size;
177bf215546Sopenharmony_ci#else
178bf215546Sopenharmony_ci      clc->data = clc->file->static_data;
179bf215546Sopenharmony_ci      clc->size = clc->file->static_data_size;
180bf215546Sopenharmony_ci#endif
181bf215546Sopenharmony_ci      return true;
182bf215546Sopenharmony_ci   }
183bf215546Sopenharmony_ci
184bf215546Sopenharmony_ci#ifdef DYNAMIC_LIBCLC_PATH
185bf215546Sopenharmony_ci   if (clc->file->sys_path != NULL) {
186bf215546Sopenharmony_ci      off_t len = lseek(clc->fd, 0, SEEK_END);
187bf215546Sopenharmony_ci      if (len % SPIRV_WORD_SIZE != 0) {
188bf215546Sopenharmony_ci         fprintf(stderr, "File length isn't a multiple of the word size\n");
189bf215546Sopenharmony_ci         return false;
190bf215546Sopenharmony_ci      }
191bf215546Sopenharmony_ci      clc->size = len;
192bf215546Sopenharmony_ci
193bf215546Sopenharmony_ci      clc->data = mmap(NULL, len, PROT_READ, MAP_PRIVATE, clc->fd, 0);
194bf215546Sopenharmony_ci      if (clc->data == MAP_FAILED) {
195bf215546Sopenharmony_ci         fprintf(stderr, "Failed to mmap libclc SPIR-V: %m\n");
196bf215546Sopenharmony_ci         return false;
197bf215546Sopenharmony_ci      }
198bf215546Sopenharmony_ci
199bf215546Sopenharmony_ci      return true;
200bf215546Sopenharmony_ci   }
201bf215546Sopenharmony_ci#endif
202bf215546Sopenharmony_ci
203bf215546Sopenharmony_ci   return true;
204bf215546Sopenharmony_ci}
205bf215546Sopenharmony_ci
206bf215546Sopenharmony_cistatic void
207bf215546Sopenharmony_ciclose_clc_data(struct clc_data *clc)
208bf215546Sopenharmony_ci{
209bf215546Sopenharmony_ci   if (clc->file->static_data) {
210bf215546Sopenharmony_ci#ifdef HAVE_STATIC_LIBCLC_ZSTD
211bf215546Sopenharmony_ci      free((void *)clc->data);
212bf215546Sopenharmony_ci#endif
213bf215546Sopenharmony_ci      return;
214bf215546Sopenharmony_ci   }
215bf215546Sopenharmony_ci
216bf215546Sopenharmony_ci#ifdef DYNAMIC_LIBCLC_PATH
217bf215546Sopenharmony_ci   if (clc->file->sys_path != NULL) {
218bf215546Sopenharmony_ci      if (clc->data)
219bf215546Sopenharmony_ci         munmap((void *)clc->data, clc->size);
220bf215546Sopenharmony_ci      close(clc->fd);
221bf215546Sopenharmony_ci   }
222bf215546Sopenharmony_ci#endif
223bf215546Sopenharmony_ci}
224bf215546Sopenharmony_ci
225bf215546Sopenharmony_ci/** Returns true if libclc is found
226bf215546Sopenharmony_ci *
227bf215546Sopenharmony_ci * If libclc is compiled in statically, this always returns true.  If we
228bf215546Sopenharmony_ci * depend on a dynamic libclc, this opens and tries to stat the file.
229bf215546Sopenharmony_ci */
230bf215546Sopenharmony_cibool
231bf215546Sopenharmony_cinir_can_find_libclc(unsigned ptr_bit_size)
232bf215546Sopenharmony_ci{
233bf215546Sopenharmony_ci   struct clc_data clc;
234bf215546Sopenharmony_ci   if (open_clc_data(&clc, ptr_bit_size)) {
235bf215546Sopenharmony_ci      close_clc_data(&clc);
236bf215546Sopenharmony_ci      return true;
237bf215546Sopenharmony_ci   } else {
238bf215546Sopenharmony_ci      return false;
239bf215546Sopenharmony_ci   }
240bf215546Sopenharmony_ci}
241bf215546Sopenharmony_ci
242bf215546Sopenharmony_ci/** Adds generic pointer variants of libclc functions
243bf215546Sopenharmony_ci *
244bf215546Sopenharmony_ci * Libclc currently doesn't contain generic variants for a bunch of functions
245bf215546Sopenharmony_ci * like `frexp` but the OpenCL spec with generic pointers requires them.  We
246bf215546Sopenharmony_ci * really should fix libclc but, in the mean time, we can easily duplicate
247bf215546Sopenharmony_ci * every function that works on global memory and make it also work on generic
248bf215546Sopenharmony_ci * memory.
249bf215546Sopenharmony_ci */
250bf215546Sopenharmony_cistatic void
251bf215546Sopenharmony_cilibclc_add_generic_variants(nir_shader *shader)
252bf215546Sopenharmony_ci{
253bf215546Sopenharmony_ci   nir_foreach_function(func, shader) {
254bf215546Sopenharmony_ci      /* These don't need generic variants */
255bf215546Sopenharmony_ci      if (strstr(func->name, "async_work_group_strided_copy"))
256bf215546Sopenharmony_ci         continue;
257bf215546Sopenharmony_ci
258bf215546Sopenharmony_ci      char *U3AS1 = strstr(func->name, "U3AS1");
259bf215546Sopenharmony_ci      if (U3AS1 == NULL)
260bf215546Sopenharmony_ci         continue;
261bf215546Sopenharmony_ci
262bf215546Sopenharmony_ci      ptrdiff_t offset_1 = U3AS1 - func->name + 4;
263bf215546Sopenharmony_ci      assert(offset_1 < strlen(func->name) && func->name[offset_1] == '1');
264bf215546Sopenharmony_ci
265bf215546Sopenharmony_ci      char *generic_name = ralloc_strdup(shader, func->name);
266bf215546Sopenharmony_ci      assert(generic_name[offset_1] == '1');
267bf215546Sopenharmony_ci      generic_name[offset_1] = '4';
268bf215546Sopenharmony_ci
269bf215546Sopenharmony_ci      nir_function *gfunc = nir_function_create(shader, generic_name);
270bf215546Sopenharmony_ci      gfunc->num_params = func->num_params;
271bf215546Sopenharmony_ci      gfunc->params = ralloc_array(shader, nir_parameter, gfunc->num_params);
272bf215546Sopenharmony_ci      for (unsigned i = 0; i < gfunc->num_params; i++)
273bf215546Sopenharmony_ci         gfunc->params[i] = func->params[i];
274bf215546Sopenharmony_ci
275bf215546Sopenharmony_ci      gfunc->impl = nir_function_impl_clone(shader, func->impl);
276bf215546Sopenharmony_ci      gfunc->impl->function = gfunc;
277bf215546Sopenharmony_ci
278bf215546Sopenharmony_ci      /* Rewrite any global pointers to generic */
279bf215546Sopenharmony_ci      nir_foreach_block(block, gfunc->impl) {
280bf215546Sopenharmony_ci         nir_foreach_instr(instr, block) {
281bf215546Sopenharmony_ci            if (instr->type != nir_instr_type_deref)
282bf215546Sopenharmony_ci               continue;
283bf215546Sopenharmony_ci
284bf215546Sopenharmony_ci            nir_deref_instr *deref = nir_instr_as_deref(instr);
285bf215546Sopenharmony_ci            if (!nir_deref_mode_may_be(deref, nir_var_mem_global))
286bf215546Sopenharmony_ci               continue;
287bf215546Sopenharmony_ci
288bf215546Sopenharmony_ci            assert(deref->type != nir_deref_type_var);
289bf215546Sopenharmony_ci            assert(nir_deref_mode_is(deref, nir_var_mem_global));
290bf215546Sopenharmony_ci
291bf215546Sopenharmony_ci            deref->modes = nir_var_mem_generic;
292bf215546Sopenharmony_ci         }
293bf215546Sopenharmony_ci      }
294bf215546Sopenharmony_ci
295bf215546Sopenharmony_ci      nir_metadata_preserve(gfunc->impl, nir_metadata_none);
296bf215546Sopenharmony_ci   }
297bf215546Sopenharmony_ci}
298bf215546Sopenharmony_ci
299bf215546Sopenharmony_cinir_shader *
300bf215546Sopenharmony_cinir_load_libclc_shader(unsigned ptr_bit_size,
301bf215546Sopenharmony_ci                       struct disk_cache *disk_cache,
302bf215546Sopenharmony_ci                       const struct spirv_to_nir_options *spirv_options,
303bf215546Sopenharmony_ci                       const nir_shader_compiler_options *nir_options)
304bf215546Sopenharmony_ci{
305bf215546Sopenharmony_ci   assert(ptr_bit_size ==
306bf215546Sopenharmony_ci          nir_address_format_bit_size(spirv_options->global_addr_format));
307bf215546Sopenharmony_ci
308bf215546Sopenharmony_ci   struct clc_data clc;
309bf215546Sopenharmony_ci   if (!open_clc_data(&clc, ptr_bit_size))
310bf215546Sopenharmony_ci      return NULL;
311bf215546Sopenharmony_ci
312bf215546Sopenharmony_ci#ifdef ENABLE_SHADER_CACHE
313bf215546Sopenharmony_ci   cache_key cache_key;
314bf215546Sopenharmony_ci   if (disk_cache) {
315bf215546Sopenharmony_ci      disk_cache_compute_key(disk_cache, clc.cache_key,
316bf215546Sopenharmony_ci                             sizeof(clc.cache_key), cache_key);
317bf215546Sopenharmony_ci
318bf215546Sopenharmony_ci      size_t buffer_size;
319bf215546Sopenharmony_ci      uint8_t *buffer = disk_cache_get(disk_cache, cache_key, &buffer_size);
320bf215546Sopenharmony_ci      if (buffer) {
321bf215546Sopenharmony_ci         struct blob_reader blob;
322bf215546Sopenharmony_ci         blob_reader_init(&blob, buffer, buffer_size);
323bf215546Sopenharmony_ci         nir_shader *nir = nir_deserialize(NULL, nir_options, &blob);
324bf215546Sopenharmony_ci         free(buffer);
325bf215546Sopenharmony_ci         close_clc_data(&clc);
326bf215546Sopenharmony_ci         return nir;
327bf215546Sopenharmony_ci      }
328bf215546Sopenharmony_ci   }
329bf215546Sopenharmony_ci#endif
330bf215546Sopenharmony_ci
331bf215546Sopenharmony_ci   if (!map_clc_data(&clc)) {
332bf215546Sopenharmony_ci      close_clc_data(&clc);
333bf215546Sopenharmony_ci      return NULL;
334bf215546Sopenharmony_ci   }
335bf215546Sopenharmony_ci
336bf215546Sopenharmony_ci   struct spirv_to_nir_options spirv_lib_options = *spirv_options;
337bf215546Sopenharmony_ci   spirv_lib_options.create_library = true;
338bf215546Sopenharmony_ci
339bf215546Sopenharmony_ci   assert(clc.size % SPIRV_WORD_SIZE == 0);
340bf215546Sopenharmony_ci   nir_shader *nir = spirv_to_nir(clc.data, clc.size / SPIRV_WORD_SIZE,
341bf215546Sopenharmony_ci                                  NULL, 0, MESA_SHADER_KERNEL, NULL,
342bf215546Sopenharmony_ci                                  &spirv_lib_options, nir_options);
343bf215546Sopenharmony_ci   nir_validate_shader(nir, "after nir_load_clc_shader");
344bf215546Sopenharmony_ci
345bf215546Sopenharmony_ci   /* nir_inline_libclc will assume that the functions in this shader are
346bf215546Sopenharmony_ci    * already ready to lower.  This means we need to inline any function_temp
347bf215546Sopenharmony_ci    * initializers and lower any early returns.
348bf215546Sopenharmony_ci    */
349bf215546Sopenharmony_ci   nir->info.internal = true;
350bf215546Sopenharmony_ci   NIR_PASS_V(nir, nir_lower_variable_initializers, nir_var_function_temp);
351bf215546Sopenharmony_ci   NIR_PASS_V(nir, nir_lower_returns);
352bf215546Sopenharmony_ci
353bf215546Sopenharmony_ci   NIR_PASS_V(nir, libclc_add_generic_variants);
354bf215546Sopenharmony_ci
355bf215546Sopenharmony_ci   /* TODO: One day, we may want to run some optimizations on the libclc
356bf215546Sopenharmony_ci    * shader once and cache them to save time in each shader call.
357bf215546Sopenharmony_ci    */
358bf215546Sopenharmony_ci
359bf215546Sopenharmony_ci#ifdef ENABLE_SHADER_CACHE
360bf215546Sopenharmony_ci   if (disk_cache) {
361bf215546Sopenharmony_ci      struct blob blob;
362bf215546Sopenharmony_ci      blob_init(&blob);
363bf215546Sopenharmony_ci      nir_serialize(&blob, nir, false);
364bf215546Sopenharmony_ci      disk_cache_put(disk_cache, cache_key, blob.data, blob.size, NULL);
365bf215546Sopenharmony_ci   }
366bf215546Sopenharmony_ci#endif
367bf215546Sopenharmony_ci
368bf215546Sopenharmony_ci   close_clc_data(&clc);
369bf215546Sopenharmony_ci   return nir;
370bf215546Sopenharmony_ci}
371