| /* |
| * Copyright (c) 2022 Amazon.com, Inc. or its affiliates. |
| * Copyright © 2018 Intel Corporation |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included |
| * in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| * DEALINGS IN THE SOFTWARE. |
| */ |
| |
| #include <stdio.h> |
| #include <stdint.h> |
| #include <assert.h> |
| #include <string.h> |
| |
| #include "compiler/nir/nir.h" |
| #include "util/blob.h" |
| #include "util/build_id.h" |
| #include "util/disk_cache.h" |
| #include "util/mesa-sha1.h" |
| |
| #include "pan_context.h" |
| |
| static bool debug = false; |
| |
| extern int midgard_debug; |
| extern int bifrost_debug; |
| |
| /** |
| * Compute a disk cache key for the given uncompiled shader and shader key. |
| */ |
| 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) |
| { |
| uint8_t data[sizeof(uncompiled->nir_sha1) + sizeof(*shader_key)]; |
| |
| memcpy(data, uncompiled->nir_sha1, sizeof(uncompiled->nir_sha1)); |
| memcpy(data + sizeof(uncompiled->nir_sha1), shader_key, sizeof(*shader_key)); |
| |
| disk_cache_compute_key(cache, data, sizeof(data), cache_key); |
| } |
| |
| /** |
| * Store the given compiled shader in the disk cache. |
| * |
| * This should only be called on newly compiled shaders. No checking is |
| * done to prevent repeated stores of the same shader. |
| */ |
| 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) |
| { |
| #ifdef ENABLE_SHADER_CACHE |
| if (!cache) |
| return; |
| |
| cache_key cache_key; |
| panfrost_disk_cache_compute_key(cache, uncompiled, key, cache_key); |
| |
| if (debug) { |
| char sha1[41]; |
| _mesa_sha1_format(sha1, cache_key); |
| fprintf(stderr, "[mesa disk cache] storing %s\n", sha1); |
| } |
| |
| struct blob blob; |
| blob_init(&blob); |
| |
| /* We write the following data to the cache blob: |
| * |
| * 1. Size of program binary |
| * 2. Program binary |
| * 3. Shader info |
| */ |
| blob_write_uint32(&blob, binary->binary.size); |
| blob_write_bytes(&blob, binary->binary.data, binary->binary.size); |
| blob_write_bytes(&blob, &binary->info, sizeof(binary->info)); |
| |
| disk_cache_put(cache, cache_key, blob.data, blob.size, NULL); |
| blob_finish(&blob); |
| #endif |
| } |
| |
| /** |
| * Search for a compiled shader in the disk cache. |
| */ |
| 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) |
| { |
| #ifdef ENABLE_SHADER_CACHE |
| if (!cache) |
| return false; |
| |
| cache_key cache_key; |
| panfrost_disk_cache_compute_key(cache, uncompiled, key, cache_key); |
| |
| if (debug) { |
| char sha1[41]; |
| _mesa_sha1_format(sha1, cache_key); |
| fprintf(stderr, "[mesa disk cache] retrieving %s: ", sha1); |
| } |
| |
| size_t size; |
| void *buffer = disk_cache_get(cache, cache_key, &size); |
| |
| if (debug) |
| fprintf(stderr, "%s\n", buffer ? "found" : "missing"); |
| |
| if (!buffer) |
| return false; |
| |
| struct blob_reader blob; |
| blob_reader_init(&blob, buffer, size); |
| |
| util_dynarray_init(&binary->binary, NULL); |
| |
| uint32_t binary_size = blob_read_uint32(&blob); |
| void *ptr = util_dynarray_resize_bytes(&binary->binary, binary_size, 1); |
| |
| blob_copy_bytes(&blob, ptr, binary_size); |
| blob_copy_bytes(&blob, &binary->info, sizeof(binary->info)); |
| |
| return true; |
| #else |
| return false; |
| #endif |
| } |
| |
| /** |
| * Initialize the on-disk shader cache. |
| */ |
| void |
| panfrost_disk_cache_init(struct panfrost_screen *screen) |
| { |
| #ifdef ENABLE_SHADER_CACHE |
| const char *renderer = screen->base.get_name(&screen->base); |
| |
| const struct build_id_note *note = |
| build_id_find_nhdr_for_addr(panfrost_disk_cache_init); |
| assert(note && build_id_length(note) == 20); /* sha1 */ |
| |
| const uint8_t *id_sha1 = build_id_data(note); |
| assert(id_sha1); |
| |
| char timestamp[41]; |
| _mesa_sha1_format(timestamp, id_sha1); |
| |
| /* Consider any flags affecting the compile when caching */ |
| uint64_t driver_flags = screen->dev.debug; |
| driver_flags |= ((uint64_t) (midgard_debug | bifrost_debug) << 32); |
| |
| screen->disk_cache = disk_cache_create(renderer, timestamp, driver_flags); |
| #endif |
| } |