Module: Mesa
Branch: main
Commit: 80a319c0b444293761eb7e07cc4e97ad65d56cd5
URL:    
http://cgit.freedesktop.org/mesa/mesa/commit/?id=80a319c0b444293761eb7e07cc4e97ad65d56cd5

Author: Mark Collins <[email protected]>
Date:   Fri Dec  1 13:27:15 2023 +0000

freedreno/rddecompiler: Add ability to read GPU buffer into file

While running tests, it is be useful to have non-sequenced dumps of
certain buffers to see their contents from changes in the decompiled
CS. This introduces a function gpu_read_into_file(...) for specifying
a file to read a specific GPU buffer into after replaying the CS.

Signed-off-by: Mark Collins <[email protected]>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26465>

---

 src/freedreno/common/redump.h           |  1 +
 src/freedreno/decode/rdcompiler-utils.h | 41 ++++++++++++++++++++++++
 src/freedreno/decode/replay.c           | 56 +++++++++++++++++++++++++++++++++
 3 files changed, 98 insertions(+)

diff --git a/src/freedreno/common/redump.h b/src/freedreno/common/redump.h
index 980e57488d1..7b97e1a8078 100644
--- a/src/freedreno/common/redump.h
+++ b/src/freedreno/common/redump.h
@@ -44,6 +44,7 @@ enum rd_sect_type {
    RD_CHIP_ID,
    RD_SHADER_LOG_BUFFER, /* Specifies buffer which has logs from shaders */
    RD_CP_LOG_BUFFER, /* Specifies buffer which has logs from CP */
+   RD_WRBUFFER,     /* Specifies buffer which has data that needs to be 
written out to a file */
 };
 
 /* RD_PARAM types: */
diff --git a/src/freedreno/decode/rdcompiler-utils.h 
b/src/freedreno/decode/rdcompiler-utils.h
index 45c4cc05c30..feef4a86ddd 100644
--- a/src/freedreno/decode/rdcompiler-utils.h
+++ b/src/freedreno/decode/rdcompiler-utils.h
@@ -45,6 +45,14 @@ cs_get_cur_iova(struct cmdstream *cs)
    return cs->iova + cs->cur * sizeof(uint32_t);
 }
 
+struct wrbuf {
+   struct list_head link;
+
+   uint64_t iova;
+   uint64_t size;
+   const char *name;
+};
+
 struct replay_context {
    void *mem_ctx;
 
@@ -59,6 +67,8 @@ struct replay_context {
 
    struct list_head cs_list;
 
+   struct list_head wrbuf_list;
+
    struct ir3_compiler *compiler;
 
    struct hash_table_u64 *compiled_shaders;
@@ -165,6 +175,18 @@ rd_write_cs_submit(FILE *out, struct cmdstream *cs)
    fwrite(packet, sizeof(packet), 1, out);
 }
 
+static void
+rd_write_wrbuffer(FILE *out, struct wrbuf *wrbuf)
+{
+   uint32_t name_len = strlen(wrbuf->name) + 1;
+   struct rd_section section = {.type = RD_WRBUFFER,
+                                .size = (uint32_t)(sizeof(uint32_t) * 2) + 
name_len};
+   fwrite(&section, sizeof(section), 1, out);
+   fwrite(&wrbuf->iova, sizeof(uint64_t), 1, out);
+   fwrite(&wrbuf->size, sizeof(uint64_t), 1, out);
+   fwrite(wrbuf->name, sizeof(char), name_len, out);
+}
+
 static void
 print_usage(const char *name)
 {
@@ -225,6 +247,7 @@ replay_context_init(struct replay_context *ctx, struct 
fd_dev_id *dev_id,
 
    ctx->mem_ctx = ralloc_context(NULL);
    list_inithead(&ctx->cs_list);
+   list_inithead(&ctx->wrbuf_list);
 
    util_vma_heap_init(&ctx->vma, va_start, ROUND_DOWN_TO(va_size, 4096));
 
@@ -270,6 +293,10 @@ replay_context_finish(struct replay_context *ctx)
    }
    rd_write_cs_submit(out, ctx->submit_cs);
 
+   list_for_each_entry (struct wrbuf, wrbuf, &ctx->wrbuf_list, link) {
+      rd_write_wrbuffer(out, wrbuf);
+   }
+
    fclose(out);
 }
 
@@ -379,3 +406,17 @@ gpu_print(struct replay_context *ctx, struct cmdstream 
*_cs, uint64_t iova,
 
    end_ib();
 }
+
+static void
+gpu_read_into_file(struct replay_context *ctx, struct cmdstream *_cs,
+                    uint64_t iova, uint64_t size, const char *name)
+{
+   struct wrbuf *wrbuf = (struct wrbuf *) calloc(1, sizeof(struct wrbuf));
+   wrbuf->iova = iova;
+   wrbuf->size = size;
+   wrbuf->name = strdup(name);
+
+   assert(wrbuf->iova != 0);
+
+   list_addtail(&wrbuf->link, &ctx->wrbuf_list);
+}
\ No newline at end of file
diff --git a/src/freedreno/decode/replay.c b/src/freedreno/decode/replay.c
index 5d22f994a06..6081640c711 100644
--- a/src/freedreno/decode/replay.c
+++ b/src/freedreno/decode/replay.c
@@ -170,6 +170,12 @@ struct cmdstream {
    uint64_t size;
 };
 
+struct wrbuf {
+   uint64_t iova;
+   uint64_t size;
+   char* name;
+};
+
 struct device {
    int fd;
 
@@ -190,6 +196,8 @@ struct device {
 #ifdef FD_REPLAY_KGSL
    uint32_t context_id;
 #endif
+
+   struct u_vector wrbufs;
 };
 
 void buffer_mem_free(struct device *dev, struct buffer *buf);
@@ -325,6 +333,40 @@ device_print_cp_log(struct device *dev)
    }
 }
 
+static void
+device_dump_wrbuf(struct device *dev)
+{
+   if (!u_vector_length(&dev->wrbufs))
+      return;
+
+   char buffer_dir[256];
+   snprintf(buffer_dir, sizeof(buffer_dir), "%s/buffers", exename);
+   rmdir(buffer_dir);
+   mkdir(buffer_dir, 0777);
+
+   struct wrbuf *wrbuf;
+   u_vector_foreach(wrbuf, &dev->wrbufs) {
+      char buffer_path[256];
+      snprintf(buffer_path, sizeof(buffer_path), "%s/%s", buffer_dir, 
wrbuf->name);
+      FILE *f = fopen(buffer_path, "wb");
+      if (!f) {
+         fprintf(stderr, "Error opening %s\n", buffer_path);
+         goto end_it;
+      }
+
+      struct buffer *buf = device_get_buffer(dev, wrbuf->iova);
+      if (!buf) {
+         fprintf(stderr, "Error getting buffer for %s\n", buffer_path);
+         goto end_it;
+      }
+      const void *buffer = buf->map + (wrbuf->iova - buf->iova);
+      fwrite(buffer, wrbuf->size, 1, f);
+
+      end_it:
+      fclose(f);
+   }
+}
+
 #if !FD_REPLAY_KGSL
 static inline void
 get_abs_timeout(struct drm_msm_timespec *tv, uint64_t ns)
@@ -401,6 +443,7 @@ device_create()
    rb_tree_init(&dev->buffers);
    util_vma_heap_init(&dev->vma, va_start, ROUND_DOWN_TO(va_size, 4096));
    u_vector_init(&dev->cmdstreams, 8, sizeof(struct cmdstream));
+   u_vector_init(&dev->wrbufs, 8, sizeof(struct wrbuf));
 
    return dev;
 }
@@ -521,6 +564,8 @@ device_submit_cmdstreams(struct device *dev)
 
    device_print_shader_log(dev);
    device_print_cp_log(dev);
+
+   device_dump_wrbuf(dev);
 }
 
 static void
@@ -714,6 +759,8 @@ device_submit_cmdstreams(struct device *dev)
 
    device_print_shader_log(dev);
    device_print_cp_log(dev);
+
+   device_dump_wrbuf(dev);
 }
 
 static void
@@ -834,6 +881,15 @@ override_cmdstream(struct device *dev, struct cmdstream 
*cs,
          parse_addr(ps.buf, ps.sz, &sizedwords, &dev->cp_log_iova);
          break;
       }
+      case RD_WRBUFFER: {
+         struct wrbuf *wrbuf = u_vector_add(&dev->wrbufs);
+         uint64_t *p = (uint64_t *)ps.buf;
+         wrbuf->iova = p[0];
+         wrbuf->size = p[1];
+         wrbuf->name = calloc(1, p[2]);
+         memcpy(wrbuf->name, (char *)ps.buf + 3 * sizeof(uint64_t), p[2]);
+         break;
+      }
       default:
          break;
       }

Reply via email to