mirror of https://gitlab.freedesktop.org/mesa/mesa
etnaviv: add disk cache
Adds a shader disk-cache for shader variants. Note that builds with `-Dshader-cache=false` have no-op stubs with `disk_cache_create()` that returns NULL. This shader disk-cache gets used when using NIR only. Helps to save about 1-2 minutes for a deqp run on gc2000. Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6669>
This commit is contained in:
parent
6a0d7f6316
commit
77af1ca690
|
@ -28,6 +28,8 @@ C_SOURCES := \
|
|||
etnaviv_debug.h \
|
||||
etnaviv_disasm.c \
|
||||
etnaviv_disasm.h \
|
||||
etnaviv_disk_cache.c \
|
||||
etnaviv_disk_cache.h \
|
||||
etnaviv_emit.c \
|
||||
etnaviv_emit.h \
|
||||
etnaviv_etc2.c \
|
||||
|
|
|
@ -27,10 +27,11 @@
|
|||
#include "etnaviv_compiler.h"
|
||||
#include "etnaviv_compiler_nir.h"
|
||||
#include "etnaviv_debug.h"
|
||||
#include "etnaviv_disk_cache.h"
|
||||
#include "util/ralloc.h"
|
||||
|
||||
struct etna_compiler *
|
||||
etna_compiler_create(void)
|
||||
etna_compiler_create(const char *renderer)
|
||||
{
|
||||
struct etna_compiler *compiler = rzalloc(NULL, struct etna_compiler);
|
||||
|
||||
|
@ -43,6 +44,8 @@ etna_compiler_create(void)
|
|||
compiler = NULL;
|
||||
}
|
||||
|
||||
etna_disk_cache_init(compiler, renderer);
|
||||
|
||||
return compiler;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "pipe/p_compiler.h"
|
||||
#include "pipe/p_shader_tokens.h"
|
||||
#include "compiler/shader_enums.h"
|
||||
#include "util/disk_cache.h"
|
||||
|
||||
/* XXX some of these are pretty arbitrary limits, may be better to switch
|
||||
* to dynamic allocation at some point.
|
||||
|
@ -51,6 +52,8 @@
|
|||
struct etna_compiler {
|
||||
uint32_t shader_count;
|
||||
struct ra_regs *regs;
|
||||
|
||||
struct disk_cache *disk_cache;
|
||||
};
|
||||
|
||||
/* compiler output per input/output */
|
||||
|
@ -84,14 +87,27 @@ struct etna_shader_variant {
|
|||
|
||||
struct etna_bo *bo; /* cached code memory bo handle (for icache) */
|
||||
|
||||
/*
|
||||
* Below here is serialized when written to disk cache:
|
||||
*/
|
||||
uint32_t *code;
|
||||
struct etna_shader_uniform_info uniforms;
|
||||
|
||||
/*
|
||||
* The following macros are used by the shader disk cache save/
|
||||
* restore paths to serialize/deserialize the variant. Any
|
||||
* pointers that require special handling in store_variant()
|
||||
* and retrieve_variant() should go above here.
|
||||
*/
|
||||
#define VARIANT_CACHE_START offsetof(struct etna_shader_variant, stage)
|
||||
#define VARIANT_CACHE_PTR(v) (((char *)v) + VARIANT_CACHE_START)
|
||||
#define VARIANT_CACHE_SIZE (sizeof(struct etna_shader_variant) - VARIANT_CACHE_START)
|
||||
|
||||
gl_shader_stage stage;
|
||||
uint32_t code_size; /* code size in uint32 words */
|
||||
uint32_t *code;
|
||||
unsigned num_loops;
|
||||
unsigned num_temps;
|
||||
|
||||
struct etna_shader_uniform_info uniforms;
|
||||
|
||||
/* ETNA_DIRTY_* flags that, when set in context dirty, mean that the
|
||||
* uniforms have to get (partial) reloaded. */
|
||||
uint32_t uniforms_dirty_bits;
|
||||
|
@ -134,7 +150,7 @@ struct etna_shader_link_info {
|
|||
};
|
||||
|
||||
struct etna_compiler *
|
||||
etna_compiler_create(void);
|
||||
etna_compiler_create(const char *renderer);
|
||||
|
||||
void
|
||||
etna_compiler_destroy(const struct etna_compiler *compiler);
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#define ETNA_DBG_NO_SINGLEBUF 0x1000000 /* disable single buffer feature */
|
||||
#define ETNA_DBG_NIR 0x2000000 /* use new NIR compiler */
|
||||
#define ETNA_DBG_DEQP 0x4000000 /* Hacks to run dEQP GLES3 tests */
|
||||
#define ETNA_DBG_NOCACHE 0x8000000 /* Disable shader cache */
|
||||
|
||||
extern int etna_mesa_debug; /* set in etna_screen.c from ETNA_DEBUG */
|
||||
|
||||
|
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* Copyright © 2020 Google, Inc.
|
||||
* Copyright (c) 2020 Etnaviv Project
|
||||
*
|
||||
* 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, sub license,
|
||||
* 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 (including the
|
||||
* next paragraph) 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 NON-INFRINGEMENT. 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.
|
||||
*
|
||||
* Authors:
|
||||
* Christian Gmeiner <christian.gmeiner@gmail.com>
|
||||
*/
|
||||
|
||||
#include "etnaviv_debug.h"
|
||||
#include "etnaviv_disk_cache.h"
|
||||
#include "nir_serialize.h"
|
||||
|
||||
#define debug 0
|
||||
|
||||
void
|
||||
etna_disk_cache_init(struct etna_compiler *compiler, const char *renderer)
|
||||
{
|
||||
if (!(etna_mesa_debug & ETNA_DBG_NIR))
|
||||
return;
|
||||
|
||||
if (etna_mesa_debug & ETNA_DBG_NOCACHE)
|
||||
return;
|
||||
|
||||
const struct build_id_note *note =
|
||||
build_id_find_nhdr_for_addr(etna_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);
|
||||
|
||||
compiler->disk_cache = disk_cache_create(renderer, timestamp, etna_mesa_debug);
|
||||
}
|
||||
|
||||
void
|
||||
etna_disk_cache_init_shader_key(struct etna_compiler *compiler, struct etna_shader *shader)
|
||||
{
|
||||
if (!compiler->disk_cache)
|
||||
return;
|
||||
|
||||
struct mesa_sha1 ctx;
|
||||
|
||||
_mesa_sha1_init(&ctx);
|
||||
|
||||
/* Serialize the NIR to a binary blob that we can hash for the disk
|
||||
* cache. Drop unnecessary information (like variable names)
|
||||
* so the serialized NIR is smaller, and also to let us detect more
|
||||
* isomorphic shaders when hashing, increasing cache hits.
|
||||
*/
|
||||
struct blob blob;
|
||||
|
||||
blob_init(&blob);
|
||||
nir_serialize(&blob, shader->nir, true);
|
||||
_mesa_sha1_update(&ctx, blob.data, blob.size);
|
||||
blob_finish(&blob);
|
||||
|
||||
_mesa_sha1_final(&ctx, shader->cache_key);
|
||||
}
|
||||
|
||||
static void
|
||||
compute_variant_key(struct etna_compiler *compiler, struct etna_shader_variant *v,
|
||||
cache_key cache_key)
|
||||
{
|
||||
struct blob blob;
|
||||
|
||||
blob_init(&blob);
|
||||
|
||||
blob_write_bytes(&blob, &v->shader->cache_key, sizeof(v->shader->cache_key));
|
||||
blob_write_bytes(&blob, &v->key, sizeof(v->key));
|
||||
|
||||
disk_cache_compute_key(compiler->disk_cache, blob.data, blob.size, cache_key);
|
||||
|
||||
blob_finish(&blob);
|
||||
}
|
||||
|
||||
static void
|
||||
retrieve_variant(struct blob_reader *blob, struct etna_shader_variant *v)
|
||||
{
|
||||
blob_copy_bytes(blob, VARIANT_CACHE_PTR(v), VARIANT_CACHE_SIZE);
|
||||
|
||||
v->code = malloc(4 * v->code_size);
|
||||
blob_copy_bytes(blob, v->code, 4 * v->code_size);
|
||||
|
||||
blob_copy_bytes(blob, &v->uniforms.imm_count, sizeof(v->uniforms.imm_count));
|
||||
v->uniforms.imm_contents = malloc(v->uniforms.imm_count * sizeof(v->uniforms.imm_contents));
|
||||
v->uniforms.imm_data = malloc(v->uniforms.imm_count * sizeof(v->uniforms.imm_data));
|
||||
|
||||
blob_copy_bytes(blob, v->uniforms.imm_contents, v->uniforms.imm_count * sizeof(v->uniforms.imm_contents));
|
||||
blob_copy_bytes(blob, v->uniforms.imm_data, v->uniforms.imm_count * sizeof(v->uniforms.imm_data));
|
||||
}
|
||||
|
||||
static void
|
||||
store_variant(struct blob *blob, const struct etna_shader_variant *v)
|
||||
{
|
||||
const uint32_t imm_count = v->uniforms.imm_count;
|
||||
|
||||
blob_write_bytes(blob, VARIANT_CACHE_PTR(v), VARIANT_CACHE_SIZE);
|
||||
blob_write_bytes(blob, v->code, 4 * v->code_size);
|
||||
|
||||
blob_write_bytes(blob, &v->uniforms.imm_count, sizeof(v->uniforms.imm_count));
|
||||
blob_write_bytes(blob, v->uniforms.imm_contents, imm_count * sizeof(v->uniforms.imm_contents));
|
||||
blob_write_bytes(blob, v->uniforms.imm_data, imm_count * sizeof(v->uniforms.imm_data));
|
||||
}
|
||||
|
||||
bool
|
||||
etna_disk_cache_retrieve(struct etna_compiler *compiler, struct etna_shader_variant *v)
|
||||
{
|
||||
if (!compiler->disk_cache)
|
||||
return false;
|
||||
|
||||
cache_key cache_key;
|
||||
|
||||
compute_variant_key(compiler, v, cache_key);
|
||||
|
||||
if (debug) {
|
||||
char sha1[41];
|
||||
|
||||
_mesa_sha1_format(sha1, cache_key);
|
||||
fprintf(stderr, "[mesa disk cache] retrieving variant %s: ", sha1);
|
||||
}
|
||||
|
||||
size_t size;
|
||||
void *buffer = disk_cache_get(compiler->disk_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);
|
||||
|
||||
retrieve_variant(&blob, v);
|
||||
|
||||
free(buffer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
etna_disk_cache_store(struct etna_compiler *compiler, struct etna_shader_variant *v)
|
||||
{
|
||||
if (!compiler->disk_cache)
|
||||
return;
|
||||
|
||||
cache_key cache_key;
|
||||
|
||||
compute_variant_key(compiler, v, cache_key);
|
||||
|
||||
if (debug) {
|
||||
char sha1[41];
|
||||
|
||||
_mesa_sha1_format(sha1, cache_key);
|
||||
fprintf(stderr, "[mesa disk cache] storing variant %s\n", sha1);
|
||||
}
|
||||
|
||||
struct blob blob;
|
||||
blob_init(&blob);
|
||||
|
||||
store_variant(&blob, v);
|
||||
|
||||
disk_cache_put(compiler->disk_cache, cache_key, blob.data, blob.size, NULL);
|
||||
blob_finish(&blob);
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright © 2020 Google, Inc.
|
||||
* Copyright (c) 2020 Etnaviv Project
|
||||
*
|
||||
* 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, sub license,
|
||||
* 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 (including the
|
||||
* next paragraph) 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 NON-INFRINGEMENT. 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.
|
||||
*
|
||||
* Authors:
|
||||
* Christian Gmeiner <christian.gmeiner@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef H_ETNAVIV_DISK_CACHE
|
||||
#define H_ETNAVIV_DISK_CACHE
|
||||
|
||||
#include "etnaviv_compiler.h"
|
||||
|
||||
void
|
||||
etna_disk_cache_init(struct etna_compiler *compiler, const char *renderer);
|
||||
|
||||
void
|
||||
etna_disk_cache_init_shader_key(struct etna_compiler *compiler, struct etna_shader *shader);
|
||||
|
||||
bool
|
||||
etna_disk_cache_retrieve(struct etna_compiler *compiler, struct etna_shader_variant *v);
|
||||
|
||||
void
|
||||
etna_disk_cache_store(struct etna_compiler *compiler, struct etna_shader_variant *v);
|
||||
|
||||
#endif
|
|
@ -74,6 +74,7 @@ static const struct debug_named_value debug_options[] = {
|
|||
{"no_singlebuffer",ETNA_DBG_NO_SINGLEBUF, "Disable single buffer feature"},
|
||||
{"nir", ETNA_DBG_NIR, "use new NIR compiler"},
|
||||
{"deqp", ETNA_DBG_DEQP, "Hacks to run dEQP GLES3 tests"}, /* needs MESA_GLES_VERSION_OVERRIDE=3.0 */
|
||||
{"nocache", ETNA_DBG_NOCACHE, "Disable shader cache"},
|
||||
DEBUG_NAMED_VALUE_END
|
||||
};
|
||||
|
||||
|
@ -883,6 +884,15 @@ etna_get_compiler_options(struct pipe_screen *pscreen,
|
|||
return &etna_screen(pscreen)->options;
|
||||
}
|
||||
|
||||
static struct disk_cache *
|
||||
etna_get_disk_shader_cache(struct pipe_screen *pscreen)
|
||||
{
|
||||
struct etna_screen *screen = etna_screen(pscreen);
|
||||
struct etna_compiler *compiler = screen->compiler;
|
||||
|
||||
return compiler->disk_cache;
|
||||
}
|
||||
|
||||
struct pipe_screen *
|
||||
etna_screen_create(struct etna_device *dev, struct etna_gpu *gpu,
|
||||
struct renderonly *ro)
|
||||
|
@ -1027,6 +1037,7 @@ etna_screen_create(struct etna_device *dev, struct etna_gpu *gpu,
|
|||
pscreen->get_paramf = etna_screen_get_paramf;
|
||||
pscreen->get_shader_param = etna_screen_get_shader_param;
|
||||
pscreen->get_compiler_options = etna_get_compiler_options;
|
||||
pscreen->get_disk_shader_cache = etna_get_disk_shader_cache;
|
||||
|
||||
pscreen->get_name = etna_screen_get_name;
|
||||
pscreen->get_vendor = etna_screen_get_vendor;
|
||||
|
@ -1037,7 +1048,7 @@ etna_screen_create(struct etna_device *dev, struct etna_gpu *gpu,
|
|||
pscreen->is_format_supported = etna_screen_is_format_supported;
|
||||
pscreen->query_dmabuf_modifiers = etna_screen_query_dmabuf_modifiers;
|
||||
|
||||
screen->compiler = etna_compiler_create();
|
||||
screen->compiler = etna_compiler_create(etna_screen_get_name(pscreen));
|
||||
if (!screen->compiler)
|
||||
goto fail;
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "etnaviv_compiler.h"
|
||||
#include "etnaviv_context.h"
|
||||
#include "etnaviv_debug.h"
|
||||
#include "etnaviv_disk_cache.h"
|
||||
#include "etnaviv_screen.h"
|
||||
#include "etnaviv_util.h"
|
||||
|
||||
|
@ -353,6 +354,10 @@ create_variant(struct etna_shader *shader, struct etna_shader_key key)
|
|||
|
||||
v->shader = shader;
|
||||
v->key = key;
|
||||
v->id = ++shader->variant_count;
|
||||
|
||||
if (etna_disk_cache_retrieve(shader->compiler, v))
|
||||
return v;
|
||||
|
||||
ret = etna_compile_shader(v);
|
||||
if (!ret) {
|
||||
|
@ -360,7 +365,7 @@ create_variant(struct etna_shader *shader, struct etna_shader_key key)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
v->id = ++shader->variant_count;
|
||||
etna_disk_cache_store(shader->compiler, v);
|
||||
|
||||
return v;
|
||||
|
||||
|
@ -412,7 +417,7 @@ etna_create_shader_state(struct pipe_context *pctx,
|
|||
else
|
||||
shader->tokens = tgsi_dup_tokens(pss->tokens);
|
||||
|
||||
|
||||
etna_disk_cache_init_shader_key(compiler, shader);
|
||||
|
||||
if (etna_mesa_debug & ETNA_DBG_SHADERDB) {
|
||||
/* if shader-db run, create a standard variant immediately
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#define H_ETNAVIV_SHADER
|
||||
|
||||
#include "pipe/p_state.h"
|
||||
#include "util/disk_cache.h"
|
||||
|
||||
struct etna_context;
|
||||
struct etna_shader_variant;
|
||||
|
@ -69,6 +70,8 @@ struct etna_shader {
|
|||
struct etna_compiler *compiler;
|
||||
|
||||
struct etna_shader_variant *variants;
|
||||
|
||||
cache_key cache_key; /* shader disk-cache key */
|
||||
};
|
||||
|
||||
bool
|
||||
|
|
|
@ -47,6 +47,8 @@ files_etnaviv = files(
|
|||
'etnaviv_debug.h',
|
||||
'etnaviv_disasm.c',
|
||||
'etnaviv_disasm.h',
|
||||
'etnaviv_disk_cache.c',
|
||||
'etnaviv_disk_cache.h',
|
||||
'etnaviv_emit.c',
|
||||
'etnaviv_emit.h',
|
||||
'etnaviv_etc2.c',
|
||||
|
|
Loading…
Reference in New Issue