ddebug: optionally handle transfer commands like draws
authorNicolai Hähnle <nicolai.haehnle@amd.com>
Sun, 22 Oct 2017 15:39:01 +0000 (17:39 +0200)
committerNicolai Hähnle <nicolai.haehnle@amd.com>
Thu, 9 Nov 2017 13:01:03 +0000 (14:01 +0100)
Transfer commands can have associated GPU operations.

Enabled by passing GALLIUM_DDEBUG=transfers.

Reviewed-by: Marek Olšák <marek.olsak@amd.com>
src/gallium/drivers/ddebug/dd_context.c
src/gallium/drivers/ddebug/dd_draw.c
src/gallium/drivers/ddebug/dd_pipe.h
src/gallium/drivers/ddebug/dd_screen.c

index 558708df58d7411ae0ec28ce87d39df07c7a8182..dd7b3e086cd78240915bce3c1d37b2273cfb73b8 100644 (file)
@@ -607,66 +607,6 @@ dd_context_destroy(struct pipe_context *_pipe)
 }
 
 
-/********************************************************************
- * transfer
- */
-
-static void *
-dd_context_transfer_map(struct pipe_context *_pipe,
-                        struct pipe_resource *resource, unsigned level,
-                        unsigned usage, const struct pipe_box *box,
-                        struct pipe_transfer **transfer)
-{
-   struct pipe_context *pipe = dd_context(_pipe)->pipe;
-
-   return pipe->transfer_map(pipe, resource, level, usage, box, transfer);
-}
-
-static void
-dd_context_transfer_flush_region(struct pipe_context *_pipe,
-                                 struct pipe_transfer *transfer,
-                                 const struct pipe_box *box)
-{
-   struct pipe_context *pipe = dd_context(_pipe)->pipe;
-
-   pipe->transfer_flush_region(pipe, transfer, box);
-}
-
-static void
-dd_context_transfer_unmap(struct pipe_context *_pipe,
-                          struct pipe_transfer *transfer)
-{
-   struct pipe_context *pipe = dd_context(_pipe)->pipe;
-
-   pipe->transfer_unmap(pipe, transfer);
-}
-
-static void
-dd_context_buffer_subdata(struct pipe_context *_pipe,
-                          struct pipe_resource *resource,
-                          unsigned usage, unsigned offset,
-                          unsigned size, const void *data)
-{
-   struct pipe_context *pipe = dd_context(_pipe)->pipe;
-
-   pipe->buffer_subdata(pipe, resource, usage, offset, size, data);
-}
-
-static void
-dd_context_texture_subdata(struct pipe_context *_pipe,
-                           struct pipe_resource *resource,
-                           unsigned level, unsigned usage,
-                           const struct pipe_box *box,
-                           const void *data, unsigned stride,
-                           unsigned layer_stride)
-{
-   struct pipe_context *pipe = dd_context(_pipe)->pipe;
-
-   pipe->texture_subdata(pipe, resource, level, usage, box, data,
-                         stride, layer_stride);
-}
-
-
 /********************************************************************
  * miscellaneous
  */
@@ -891,11 +831,6 @@ dd_context_create(struct dd_screen *dscreen, struct pipe_context *pipe)
    CTX_INIT(sampler_view_destroy);
    CTX_INIT(create_surface);
    CTX_INIT(surface_destroy);
-   CTX_INIT(transfer_map);
-   CTX_INIT(transfer_flush_region);
-   CTX_INIT(transfer_unmap);
-   CTX_INIT(buffer_subdata);
-   CTX_INIT(texture_subdata);
    CTX_INIT(texture_barrier);
    CTX_INIT(memory_barrier);
    CTX_INIT(resource_commit);
index 182d6f297a1822b9cc9c040b2fbcf69a711a725d..a25017114d8ac4e1c0beeb54b81e755c2c8f5a18 100644 (file)
@@ -467,6 +467,56 @@ dd_dump_clear_buffer(struct dd_draw_state *dstate, struct call_clear_buffer *inf
    fprintf(f, "\n");
 }
 
+static void
+dd_dump_transfer_map(struct call_transfer_map *info, FILE *f)
+{
+   fprintf(f, "%s:\n", __func__+8);
+   DUMP_M_ADDR(transfer, info, transfer);
+   DUMP_M(ptr, info, transfer_ptr);
+   DUMP_M(ptr, info, ptr);
+}
+
+static void
+dd_dump_transfer_flush_region(struct call_transfer_flush_region *info, FILE *f)
+{
+   fprintf(f, "%s:\n", __func__+8);
+   DUMP_M_ADDR(transfer, info, transfer);
+   DUMP_M(ptr, info, transfer_ptr);
+   DUMP_M_ADDR(box, info, box);
+}
+
+static void
+dd_dump_transfer_unmap(struct call_transfer_unmap *info, FILE *f)
+{
+   fprintf(f, "%s:\n", __func__+8);
+   DUMP_M_ADDR(transfer, info, transfer);
+   DUMP_M(ptr, info, transfer_ptr);
+}
+
+static void
+dd_dump_buffer_subdata(struct call_buffer_subdata *info, FILE *f)
+{
+   fprintf(f, "%s:\n", __func__+8);
+   DUMP_M(resource, info, resource);
+   DUMP_M(transfer_usage, info, usage);
+   DUMP_M(uint, info, offset);
+   DUMP_M(uint, info, size);
+   DUMP_M(ptr, info, data);
+}
+
+static void
+dd_dump_texture_subdata(struct call_texture_subdata *info, FILE *f)
+{
+   fprintf(f, "%s:\n", __func__+8);
+   DUMP_M(resource, info, resource);
+   DUMP_M(uint, info, level);
+   DUMP_M(transfer_usage, info, usage);
+   DUMP_M_ADDR(box, info, box);
+   DUMP_M(ptr, info, data);
+   DUMP_M(uint, info, stride);
+   DUMP_M(uint, info, layer_stride);
+}
+
 static void
 dd_dump_clear_texture(struct dd_draw_state *dstate, FILE *f)
 {
@@ -540,6 +590,21 @@ dd_dump_call(FILE *f, struct dd_draw_state *state, struct dd_call *call)
    case CALL_GET_QUERY_RESULT_RESOURCE:
       dd_dump_get_query_result_resource(&call->info.get_query_result_resource, f);
       break;
+   case CALL_TRANSFER_MAP:
+      dd_dump_transfer_map(&call->info.transfer_map, f);
+      break;
+   case CALL_TRANSFER_FLUSH_REGION:
+      dd_dump_transfer_flush_region(&call->info.transfer_flush_region, f);
+      break;
+   case CALL_TRANSFER_UNMAP:
+      dd_dump_transfer_unmap(&call->info.transfer_unmap, f);
+      break;
+   case CALL_BUFFER_SUBDATA:
+      dd_dump_buffer_subdata(&call->info.buffer_subdata, f);
+      break;
+   case CALL_TEXTURE_SUBDATA:
+      dd_dump_texture_subdata(&call->info.texture_subdata, f);
+      break;
    }
 }
 
@@ -598,6 +663,21 @@ dd_unreference_copy_of_call(struct dd_call *dst)
    case CALL_GET_QUERY_RESULT_RESOURCE:
       pipe_resource_reference(&dst->info.get_query_result_resource.resource, NULL);
       break;
+   case CALL_TRANSFER_MAP:
+      pipe_resource_reference(&dst->info.transfer_map.transfer.resource, NULL);
+      break;
+   case CALL_TRANSFER_FLUSH_REGION:
+      pipe_resource_reference(&dst->info.transfer_flush_region.transfer.resource, NULL);
+      break;
+   case CALL_TRANSFER_UNMAP:
+      pipe_resource_reference(&dst->info.transfer_unmap.transfer.resource, NULL);
+      break;
+   case CALL_BUFFER_SUBDATA:
+      pipe_resource_reference(&dst->info.buffer_subdata.resource, NULL);
+      break;
+   case CALL_TEXTURE_SUBDATA:
+      pipe_resource_reference(&dst->info.texture_subdata.resource, NULL);
+      break;
    }
 }
 
@@ -1392,6 +1472,155 @@ dd_context_clear_texture(struct pipe_context *_pipe,
    dd_after_draw(dctx, record);
 }
 
+/********************************************************************
+ * transfer
+ */
+
+static void *
+dd_context_transfer_map(struct pipe_context *_pipe,
+                        struct pipe_resource *resource, unsigned level,
+                        unsigned usage, const struct pipe_box *box,
+                        struct pipe_transfer **transfer)
+{
+   struct dd_context *dctx = dd_context(_pipe);
+   struct pipe_context *pipe = dctx->pipe;
+   struct dd_draw_record *record =
+      dd_screen(dctx->base.screen)->transfers ? dd_create_record(dctx) : NULL;
+
+   if (record) {
+      record->call.type = CALL_TRANSFER_MAP;
+
+      dd_before_draw(dctx, record);
+   }
+   void *ptr = pipe->transfer_map(pipe, resource, level, usage, box, transfer);
+   if (record) {
+      record->call.info.transfer_map.transfer_ptr = *transfer;
+      record->call.info.transfer_map.ptr = ptr;
+      if (*transfer) {
+         record->call.info.transfer_map.transfer = **transfer;
+         record->call.info.transfer_map.transfer.resource = NULL;
+         pipe_resource_reference(&record->call.info.transfer_map.transfer.resource,
+                                 (*transfer)->resource);
+      } else {
+         memset(&record->call.info.transfer_map.transfer, 0, sizeof(struct pipe_transfer));
+      }
+
+      dd_after_draw(dctx, record);
+   }
+   return ptr;
+}
+
+static void
+dd_context_transfer_flush_region(struct pipe_context *_pipe,
+                                 struct pipe_transfer *transfer,
+                                 const struct pipe_box *box)
+{
+   struct dd_context *dctx = dd_context(_pipe);
+   struct pipe_context *pipe = dctx->pipe;
+   struct dd_draw_record *record =
+      dd_screen(dctx->base.screen)->transfers ? dd_create_record(dctx) : NULL;
+
+   if (record) {
+      record->call.type = CALL_TRANSFER_FLUSH_REGION;
+      record->call.info.transfer_flush_region.transfer_ptr = transfer;
+      record->call.info.transfer_flush_region.box = *box;
+      record->call.info.transfer_flush_region.transfer = *transfer;
+      record->call.info.transfer_flush_region.transfer.resource = NULL;
+      pipe_resource_reference(
+            &record->call.info.transfer_flush_region.transfer.resource,
+            transfer->resource);
+
+      dd_before_draw(dctx, record);
+   }
+   pipe->transfer_flush_region(pipe, transfer, box);
+   if (record)
+      dd_after_draw(dctx, record);
+}
+
+static void
+dd_context_transfer_unmap(struct pipe_context *_pipe,
+                          struct pipe_transfer *transfer)
+{
+   struct dd_context *dctx = dd_context(_pipe);
+   struct pipe_context *pipe = dctx->pipe;
+   struct dd_draw_record *record =
+      dd_screen(dctx->base.screen)->transfers ? dd_create_record(dctx) : NULL;
+
+   if (record) {
+      record->call.type = CALL_TRANSFER_UNMAP;
+      record->call.info.transfer_unmap.transfer_ptr = transfer;
+      record->call.info.transfer_unmap.transfer = *transfer;
+      record->call.info.transfer_unmap.transfer.resource = NULL;
+      pipe_resource_reference(
+            &record->call.info.transfer_unmap.transfer.resource,
+            transfer->resource);
+
+      dd_before_draw(dctx, record);
+   }
+   pipe->transfer_unmap(pipe, transfer);
+   if (record)
+      dd_after_draw(dctx, record);
+}
+
+static void
+dd_context_buffer_subdata(struct pipe_context *_pipe,
+                          struct pipe_resource *resource,
+                          unsigned usage, unsigned offset,
+                          unsigned size, const void *data)
+{
+   struct dd_context *dctx = dd_context(_pipe);
+   struct pipe_context *pipe = dctx->pipe;
+   struct dd_draw_record *record =
+      dd_screen(dctx->base.screen)->transfers ? dd_create_record(dctx) : NULL;
+
+   if (record) {
+      record->call.type = CALL_BUFFER_SUBDATA;
+      record->call.info.buffer_subdata.resource = NULL;
+      pipe_resource_reference(&record->call.info.buffer_subdata.resource, resource);
+      record->call.info.buffer_subdata.usage = usage;
+      record->call.info.buffer_subdata.offset = offset;
+      record->call.info.buffer_subdata.size = size;
+      record->call.info.buffer_subdata.data = data;
+
+      dd_before_draw(dctx, record);
+   }
+   pipe->buffer_subdata(pipe, resource, usage, offset, size, data);
+   if (record)
+      dd_after_draw(dctx, record);
+}
+
+static void
+dd_context_texture_subdata(struct pipe_context *_pipe,
+                           struct pipe_resource *resource,
+                           unsigned level, unsigned usage,
+                           const struct pipe_box *box,
+                           const void *data, unsigned stride,
+                           unsigned layer_stride)
+{
+   struct dd_context *dctx = dd_context(_pipe);
+   struct pipe_context *pipe = dctx->pipe;
+   struct dd_draw_record *record =
+      dd_screen(dctx->base.screen)->transfers ? dd_create_record(dctx) : NULL;
+
+   if (record) {
+      record->call.type = CALL_TEXTURE_SUBDATA;
+      record->call.info.texture_subdata.resource = NULL;
+      pipe_resource_reference(&record->call.info.texture_subdata.resource, resource);
+      record->call.info.texture_subdata.level = level;
+      record->call.info.texture_subdata.usage = usage;
+      record->call.info.texture_subdata.box = *box;
+      record->call.info.texture_subdata.data = data;
+      record->call.info.texture_subdata.stride = stride;
+      record->call.info.texture_subdata.layer_stride = layer_stride;
+
+      dd_before_draw(dctx, record);
+   }
+   pipe->texture_subdata(pipe, resource, level, usage, box, data,
+                         stride, layer_stride);
+   if (record)
+      dd_after_draw(dctx, record);
+}
+
 void
 dd_init_draw_functions(struct dd_context *dctx)
 {
@@ -1408,4 +1637,9 @@ dd_init_draw_functions(struct dd_context *dctx)
    CTX_INIT(flush_resource);
    CTX_INIT(generate_mipmap);
    CTX_INIT(get_query_result_resource);
+   CTX_INIT(transfer_map);
+   CTX_INIT(transfer_flush_region);
+   CTX_INIT(transfer_unmap);
+   CTX_INIT(buffer_subdata);
+   CTX_INIT(texture_subdata);
 }
index 607ebbb2b96cce8099ccbb7b013c774c8a1a9a1b..07c4d55017f7316aed9424ffcd0e8844255f09d2 100644 (file)
@@ -52,6 +52,7 @@ struct dd_screen
    unsigned timeout_ms;
    enum dd_dump_mode dump_mode;
    bool flush_always;
+   bool transfers;
    bool verbose;
    unsigned skip_count;
    unsigned apitrace_dump_call;
@@ -71,6 +72,11 @@ enum call_type
    CALL_CLEAR_DEPTH_STENCIL,
    CALL_GENERATE_MIPMAP,
    CALL_GET_QUERY_RESULT_RESOURCE,
+   CALL_TRANSFER_MAP,
+   CALL_TRANSFER_FLUSH_REGION,
+   CALL_TRANSFER_UNMAP,
+   CALL_BUFFER_SUBDATA,
+   CALL_TEXTURE_SUBDATA,
 };
 
 struct call_resource_copy_region
@@ -124,6 +130,41 @@ struct call_get_query_result_resource {
    unsigned offset;
 };
 
+struct call_transfer_map {
+   struct pipe_transfer *transfer_ptr;
+   struct pipe_transfer transfer;
+   void *ptr;
+};
+
+struct call_transfer_flush_region {
+   struct pipe_transfer *transfer_ptr;
+   struct pipe_transfer transfer;
+   struct pipe_box box;
+};
+
+struct call_transfer_unmap {
+   struct pipe_transfer *transfer_ptr;
+   struct pipe_transfer transfer;
+};
+
+struct call_buffer_subdata {
+   struct pipe_resource *resource;
+   unsigned usage;
+   unsigned offset;
+   unsigned size;
+   const void *data;
+};
+
+struct call_texture_subdata {
+   struct pipe_resource *resource;
+   unsigned level;
+   unsigned usage;
+   struct pipe_box box;
+   const void *data;
+   unsigned stride;
+   unsigned layer_stride;
+};
+
 struct dd_call
 {
    enum call_type type;
@@ -138,6 +179,11 @@ struct dd_call
       struct call_clear_buffer clear_buffer;
       struct call_generate_mipmap generate_mipmap;
       struct call_get_query_result_resource get_query_result_resource;
+      struct call_transfer_map transfer_map;
+      struct call_transfer_flush_region transfer_flush_region;
+      struct call_transfer_unmap transfer_unmap;
+      struct call_buffer_subdata buffer_subdata;
+      struct call_texture_subdata texture_subdata;
    } info;
 };
 
index 11d1d8c1e9c010d12ca5f199b74395ded4f5efe5..5b2be28a96942b284db34430c46b146fb24eb2e6 100644 (file)
@@ -428,6 +428,7 @@ ddebug_screen_create(struct pipe_screen *screen)
    const char *option;
    bool flush = false;
    bool verbose = false;
+   bool transfers = false;
    unsigned timeout = 1000;
    unsigned apitrace_dump_call = 0;
    enum dd_dump_mode mode = DD_DUMP_ONLY_HANGS;
@@ -441,7 +442,7 @@ ddebug_screen_create(struct pipe_screen *screen)
       puts("");
       puts("Usage:");
       puts("");
-      puts("  GALLIUM_DDEBUG=\"[<timeout in ms>] [(always|apitrace <call#)] [flush] [verbose]\"");
+      puts("  GALLIUM_DDEBUG=\"[<timeout in ms>] [(always|apitrace <call#)] [flush] [transfers] [verbose]\"");
       puts("  GALLIUM_DDEBUG_SKIP=[count]");
       puts("");
       puts("Dump context and driver information of draw calls into");
@@ -455,6 +456,9 @@ ddebug_screen_create(struct pipe_screen *screen)
       puts("always");
       puts("  Dump information about all draw calls.");
       puts("");
+      puts("transfers");
+      puts("  Also dump and do hang detection on transfers.");
+      puts("");
       puts("apitrace <call#>");
       puts("  Dump information about the draw call corresponding to the given");
       puts("  apitrace call number and exit.");
@@ -485,6 +489,8 @@ ddebug_screen_create(struct pipe_screen *screen)
          mode = DD_DUMP_ALL_CALLS;
       } else if (match_word(&option, "flush")) {
          flush = true;
+      } else if (match_word(&option, "transfers")) {
+         transfers = true;
       } else if (match_word(&option, "verbose")) {
          verbose = true;
       } else if (match_word(&option, "apitrace")) {
@@ -556,6 +562,7 @@ ddebug_screen_create(struct pipe_screen *screen)
    dscreen->timeout_ms = timeout;
    dscreen->dump_mode = mode;
    dscreen->flush_always = flush;
+   dscreen->transfers = transfers;
    dscreen->verbose = verbose;
    dscreen->apitrace_dump_call = apitrace_dump_call;