From: Nicolai Hähnle <nicolai.haeh...@amd.com>

This option allows replacing a single shader by a pre-compiled ELF object
as generated by LLVM's llc, for example. This can be useful for debugging a
deterministically occuring error in shaders (and has in fact helped find
the causes of https://bugs.freedesktop.org/show_bug.cgi?id=93264).
---
 src/gallium/drivers/radeon/r600_pipe_common.h |  1 +
 src/gallium/drivers/radeonsi/si_debug.c       | 94 +++++++++++++++++++++++++++
 src/gallium/drivers/radeonsi/si_pipe.c        |  3 +
 src/gallium/drivers/radeonsi/si_pipe.h        |  1 +
 src/gallium/drivers/radeonsi/si_shader.c      | 18 +++--
 5 files changed, 112 insertions(+), 5 deletions(-)

diff --git a/src/gallium/drivers/radeon/r600_pipe_common.h 
b/src/gallium/drivers/radeon/r600_pipe_common.h
index c3933b1d..556c7cc 100644
--- a/src/gallium/drivers/radeon/r600_pipe_common.h
+++ b/src/gallium/drivers/radeon/r600_pipe_common.h
@@ -87,6 +87,7 @@
 #define DBG_NO_DCC             (1llu << 43)
 #define DBG_NO_DCC_CLEAR       (1llu << 44)
 #define DBG_NO_RB_PLUS         (1llu << 45)
+#define DBG_REPLACE_SHADERS    (1llu << 46)
 
 #define R600_MAP_BUFFER_ALIGNMENT 64
 
diff --git a/src/gallium/drivers/radeonsi/si_debug.c 
b/src/gallium/drivers/radeonsi/si_debug.c
index c45f8c0..f50d98c 100644
--- a/src/gallium/drivers/radeonsi/si_debug.c
+++ b/src/gallium/drivers/radeonsi/si_debug.c
@@ -28,7 +28,9 @@
 #include "si_shader.h"
 #include "sid.h"
 #include "sid_tables.h"
+#include "radeon/radeon_elf_util.h"
 #include "ddebug/dd_util.h"
+#include "util/u_memory.h"
 
 
 static void si_dump_shader(struct si_shader_ctx_state *state, const char *name,
@@ -42,6 +44,98 @@ static void si_dump_shader(struct si_shader_ctx_state 
*state, const char *name,
        fprintf(f, "%s\n\n", state->current->binary.disasm_string);
 }
 
+/**
+ * Shader compiles can be overridden with arbitrary ELF objects by setting
+ * the environment variable 
RADEON_REPLACE_SHADERS=num1:filename1[;num2:filename2]
+ */
+bool si_replace_shader(unsigned num, struct radeon_shader_binary *binary)
+{
+       const char *p = debug_get_option("RADEON_REPLACE_SHADERS", NULL);
+       const char *semicolon;
+       char *copy = NULL;
+       FILE *f;
+       long filesize, nread;
+       char *buf = NULL;
+       bool replaced = false;
+
+       if (!p)
+               return false;
+
+       while (*p) {
+               unsigned long i;
+               char *endp;
+               i = strtoul(p, &endp, 0);
+
+               p = endp;
+               if (*p != ':') {
+                       fprintf(stderr, "RADEON_REPLACE_SHADERS formatted 
badly.\n");
+                       exit(1);
+               }
+               ++p;
+
+               if (i == num)
+                       break;
+
+               p = strchr(p, ';');
+               if (!p)
+                       return false;
+               ++p;
+       }
+       if (!*p)
+               return false;
+
+       semicolon = strchr(p, ';');
+       if (semicolon) {
+               p = copy = strndup(p, semicolon - p);
+               if (!copy) {
+                       fprintf(stderr, "out of memory\n");
+                       return false;
+               }
+       }
+
+       fprintf(stderr, "radeonsi: replace shader %u by %s\n", num, p);
+
+       f = fopen(p, "r");
+       if (!f) {
+               perror("radeonsi: failed to open file");
+               goto out_free;
+       }
+
+       if (fseek(f, 0, SEEK_END) != 0)
+               goto file_error;
+
+       filesize = ftell(f);
+       if (filesize < 0)
+               goto file_error;
+
+       if (fseek(f, 0, SEEK_SET) != 0)
+               goto file_error;
+
+       buf = MALLOC(filesize);
+       if (!buf) {
+               fprintf(stderr, "out of memory\n");
+               goto out_close;
+       }
+
+       nread = fread(buf, 1, filesize, f);
+       if (nread != filesize)
+               goto file_error;
+
+       radeon_elf_read(buf, filesize, binary);
+       replaced = true;
+
+out_close:
+       fclose(f);
+out_free:
+       FREE(buf);
+       free(copy);
+       return replaced;
+
+file_error:
+       perror("radeonsi: reading shader");
+       goto out_close;
+}
+
 /* Parsed IBs are difficult to read without colors. Use "less -R file" to
  * read them, or use "aha -b -f file" to convert them to html.
  */
diff --git a/src/gallium/drivers/radeonsi/si_pipe.c 
b/src/gallium/drivers/radeonsi/si_pipe.c
index ac13407..6a1911f 100644
--- a/src/gallium/drivers/radeonsi/si_pipe.c
+++ b/src/gallium/drivers/radeonsi/si_pipe.c
@@ -639,6 +639,9 @@ struct pipe_screen *radeonsi_screen_create(struct 
radeon_winsys *ws)
        if (debug_get_bool_option("RADEON_DUMP_SHADERS", FALSE))
                sscreen->b.debug_flags |= DBG_FS | DBG_VS | DBG_GS | DBG_PS | 
DBG_CS;
 
+       if (debug_get_option("RADEON_REPLACE_SHADERS", NULL))
+               sscreen->b.debug_flags |= DBG_REPLACE_SHADERS;
+
        /* Create the auxiliary context. This must be done last. */
        sscreen->b.aux_context = sscreen->b.b.context_create(&sscreen->b.b, 
NULL, 0);
 
diff --git a/src/gallium/drivers/radeonsi/si_pipe.h 
b/src/gallium/drivers/radeonsi/si_pipe.h
index 65c7e19..f83cb02 100644
--- a/src/gallium/drivers/radeonsi/si_pipe.h
+++ b/src/gallium/drivers/radeonsi/si_pipe.h
@@ -329,6 +329,7 @@ void si_init_cp_dma_functions(struct si_context *sctx);
 /* si_debug.c */
 void si_init_debug_functions(struct si_context *sctx);
 void si_check_vm_faults(struct si_context *sctx);
+bool si_replace_shader(unsigned num, struct radeon_shader_binary *binary);
 
 /* si_dma.c */
 void si_dma_copy(struct pipe_context *ctx,
diff --git a/src/gallium/drivers/radeonsi/si_shader.c 
b/src/gallium/drivers/radeonsi/si_shader.c
index 511ed88..3b19713 100644
--- a/src/gallium/drivers/radeonsi/si_shader.c
+++ b/src/gallium/drivers/radeonsi/si_shader.c
@@ -3884,13 +3884,21 @@ int si_compile_llvm(struct si_screen *sscreen, struct 
si_shader *shader,
        bool dump_asm = r600_can_dump_shader(&sscreen->b,
                                shader->selector ? shader->selector->tokens : 
NULL);
        bool dump_ir = dump_asm && !(sscreen->b.debug_flags & DBG_NO_IR);
+       bool replaced = false;
+       unsigned count = p_atomic_inc_return(&sscreen->b.num_compilations);
 
-       p_atomic_inc(&sscreen->b.num_compilations);
+       if (dump_ir || dump_asm)
+               fprintf(stderr, "radeonsi: Compiling shader %d\n", count);
 
-       r = radeon_llvm_compile(mod, &shader->binary,
-               r600_get_llvm_processor_name(sscreen->b.family), dump_ir, 
dump_asm, tm);
-       if (r)
-               return r;
+       if (sscreen->b.debug_flags & DBG_REPLACE_SHADERS)
+               replaced = si_replace_shader(count, &shader->binary);
+
+       if (!replaced) {
+               r = radeon_llvm_compile(mod, &shader->binary,
+                       r600_get_llvm_processor_name(sscreen->b.family), 
dump_ir, dump_asm, tm);
+               if (r)
+                       return r;
+       }
 
        r = si_shader_binary_read(sscreen, shader);
 
-- 
2.5.0

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to