summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Gmeiner <christian.gmeiner@gmail.com>2020-08-08 17:44:15 +0200
committerMarge Bot <eric+marge@anholt.net>2020-09-18 07:45:11 +0000
commit77af1ca690f4f49e305c095d97b9af798bfea307 (patch)
tree28960c279b397815dabde68b878b60dfe227f47a
parent6a0d7f6316c60b480f4439ecef50de422a9175a6 (diff)
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>
-rw-r--r--src/gallium/drivers/etnaviv/Makefile.sources2
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_compiler.c5
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_compiler.h24
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_debug.h1
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_disk_cache.c186
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_disk_cache.h45
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_screen.c13
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_shader.c9
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_shader.h3
-rw-r--r--src/gallium/drivers/etnaviv/meson.build2
10 files changed, 282 insertions, 8 deletions
diff --git a/src/gallium/drivers/etnaviv/Makefile.sources b/src/gallium/drivers/etnaviv/Makefile.sources
index 32fcd799ac1..3fc86072c6f 100644
--- a/src/gallium/drivers/etnaviv/Makefile.sources
+++ b/src/gallium/drivers/etnaviv/Makefile.sources
@@ -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 \
diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler.c b/src/gallium/drivers/etnaviv/etnaviv_compiler.c
index 0cb07c03cd7..119a0e21e41 100644
--- a/src/gallium/drivers/etnaviv/etnaviv_compiler.c
+++ b/src/gallium/drivers/etnaviv/etnaviv_compiler.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;
}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler.h b/src/gallium/drivers/etnaviv/etnaviv_compiler.h
index 8aaebab9f9f..734d5b1ee1b 100644
--- a/src/gallium/drivers/etnaviv/etnaviv_compiler.h
+++ b/src/gallium/drivers/etnaviv/etnaviv_compiler.h
@@ -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);
diff --git a/src/gallium/drivers/etnaviv/etnaviv_debug.h b/src/gallium/drivers/etnaviv/etnaviv_debug.h
index 79e6ebaedd8..6070f2ca189 100644
--- a/src/gallium/drivers/etnaviv/etnaviv_debug.h
+++ b/src/gallium/drivers/etnaviv/etnaviv_debug.h
@@ -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 */
diff --git a/src/gallium/drivers/etnaviv/etnaviv_disk_cache.c b/src/gallium/drivers/etnaviv/etnaviv_disk_cache.c
new file mode 100644
index 00000000000..5b1844d8ebc
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_disk_cache.c
@@ -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);
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_disk_cache.h b/src/gallium/drivers/etnaviv/etnaviv_disk_cache.h
new file mode 100644
index 00000000000..61fa302fffa
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_disk_cache.h
@@ -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
diff --git a/src/gallium/drivers/etnaviv/etnaviv_screen.c b/src/gallium/drivers/etnaviv/etnaviv_screen.c
index 269089868ed..1637eaa3f5f 100644
--- a/src/gallium/drivers/etnaviv/etnaviv_screen.c
+++ b/src/gallium/drivers/etnaviv/etnaviv_screen.c
@@ -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;
diff --git a/src/gallium/drivers/etnaviv/etnaviv_shader.c b/src/gallium/drivers/etnaviv/etnaviv_shader.c
index b44354483ae..47becee5eb5 100644
--- a/src/gallium/drivers/etnaviv/etnaviv_shader.c
+++ b/src/gallium/drivers/etnaviv/etnaviv_shader.c
@@ -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
diff --git a/src/gallium/drivers/etnaviv/etnaviv_shader.h b/src/gallium/drivers/etnaviv/etnaviv_shader.h
index c1ea785a135..ccba5c858db 100644
--- a/src/gallium/drivers/etnaviv/etnaviv_shader.h
+++ b/src/gallium/drivers/etnaviv/etnaviv_shader.h
@@ -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
diff --git a/src/gallium/drivers/etnaviv/meson.build b/src/gallium/drivers/etnaviv/meson.build
index 7b7ce26056e..8805fcc7ef2 100644
--- a/src/gallium/drivers/etnaviv/meson.build
+++ b/src/gallium/drivers/etnaviv/meson.build
@@ -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',