From: Nicolai Hähnle <nicolai.haeh...@amd.com> Transfer commands can have associated GPU operations.
Enabled by passing GALLIUM_DDEBUG=transfers. Reviewed-by: Marek Olšák <marek.ol...@amd.com> --- src/gallium/drivers/ddebug/dd_context.c | 65 --------- src/gallium/drivers/ddebug/dd_draw.c | 234 ++++++++++++++++++++++++++++++++ src/gallium/drivers/ddebug/dd_pipe.h | 46 +++++++ src/gallium/drivers/ddebug/dd_screen.c | 9 +- 4 files changed, 288 insertions(+), 66 deletions(-) diff --git a/src/gallium/drivers/ddebug/dd_context.c b/src/gallium/drivers/ddebug/dd_context.c index 558708df58d..dd7b3e086cd 100644 --- a/src/gallium/drivers/ddebug/dd_context.c +++ b/src/gallium/drivers/ddebug/dd_context.c @@ -601,80 +601,20 @@ dd_context_destroy(struct pipe_context *_pipe) } } u_log_context_destroy(&dctx->log); pipe->destroy(pipe); FREE(dctx); } /******************************************************************** - * 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 */ static void dd_context_texture_barrier(struct pipe_context *_pipe, unsigned flags) { struct pipe_context *pipe = dd_context(_pipe)->pipe; pipe->texture_barrier(pipe, flags); } @@ -884,25 +824,20 @@ dd_context_create(struct dd_screen *dscreen, struct pipe_context *pipe) CTX_INIT(set_shader_buffers); CTX_INIT(set_shader_images); CTX_INIT(set_vertex_buffers); CTX_INIT(create_stream_output_target); CTX_INIT(stream_output_target_destroy); CTX_INIT(set_stream_output_targets); CTX_INIT(create_sampler_view); 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); /* create_video_codec */ /* create_video_buffer */ /* set_compute_resources */ /* set_global_binding */ CTX_INIT(get_sample_position); CTX_INIT(invalidate_resource); CTX_INIT(get_device_reset_status); diff --git a/src/gallium/drivers/ddebug/dd_draw.c b/src/gallium/drivers/ddebug/dd_draw.c index 182d6f297a1..a25017114d8 100644 --- a/src/gallium/drivers/ddebug/dd_draw.c +++ b/src/gallium/drivers/ddebug/dd_draw.c @@ -461,20 +461,70 @@ dd_dump_clear_buffer(struct dd_draw_state *dstate, struct call_clear_buffer *inf DUMP_M(uint, info, size); DUMP_M(uint, info, clear_value_size); fprintf(f, " clear_value:"); for (i = 0; i < info->clear_value_size; i++) fprintf(f, " %02x", value[i]); 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) { fprintf(f, "%s:\n", __func__+8); /* TODO */ } static void dd_dump_clear_render_target(struct dd_draw_state *dstate, FILE *f) { fprintf(f, "%s:\n", __func__+8); @@ -533,20 +583,35 @@ dd_dump_call(FILE *f, struct dd_draw_state *state, struct dd_call *call) break; case CALL_CLEAR_DEPTH_STENCIL: dd_dump_clear_depth_stencil(state, f); break; case CALL_GENERATE_MIPMAP: dd_dump_generate_mipmap(state, f); break; 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; } } static void dd_kill_process(void) { sync(); fprintf(stderr, "dd: Aborting the process...\n"); fflush(stdout); fflush(stderr); @@ -591,20 +656,35 @@ dd_unreference_copy_of_call(struct dd_call *dst) case CALL_CLEAR_RENDER_TARGET: break; case CALL_CLEAR_DEPTH_STENCIL: break; case CALL_GENERATE_MIPMAP: pipe_resource_reference(&dst->info.generate_mipmap.res, NULL); break; 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; } } static void dd_init_copy_of_draw_state(struct dd_draw_state_copy *state) { unsigned i,j; /* Just clear pointers to gallium objects. Don't clear the whole structure, * because it would kill performance with its size of 130 KB. @@ -1385,27 +1465,181 @@ dd_context_clear_texture(struct pipe_context *_pipe, struct pipe_context *pipe = dctx->pipe; struct dd_draw_record *record = dd_create_record(dctx); record->call.type = CALL_CLEAR_TEXTURE; dd_before_draw(dctx, record); pipe->clear_texture(pipe, res, level, box, data); 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) { CTX_INIT(flush); CTX_INIT(draw_vbo); CTX_INIT(launch_grid); CTX_INIT(resource_copy_region); CTX_INIT(blit); CTX_INIT(clear); CTX_INIT(clear_render_target); CTX_INIT(clear_depth_stencil); CTX_INIT(clear_buffer); CTX_INIT(clear_texture); 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); } diff --git a/src/gallium/drivers/ddebug/dd_pipe.h b/src/gallium/drivers/ddebug/dd_pipe.h index 607ebbb2b96..07c4d55017f 100644 --- a/src/gallium/drivers/ddebug/dd_pipe.h +++ b/src/gallium/drivers/ddebug/dd_pipe.h @@ -45,39 +45,45 @@ enum dd_dump_mode { DD_DUMP_APITRACE_CALL, }; struct dd_screen { struct pipe_screen base; struct pipe_screen *screen; unsigned timeout_ms; enum dd_dump_mode dump_mode; bool flush_always; + bool transfers; bool verbose; unsigned skip_count; unsigned apitrace_dump_call; }; enum call_type { CALL_DRAW_VBO, CALL_LAUNCH_GRID, CALL_RESOURCE_COPY_REGION, CALL_BLIT, CALL_FLUSH_RESOURCE, CALL_CLEAR, CALL_CLEAR_BUFFER, CALL_CLEAR_TEXTURE, CALL_CLEAR_RENDER_TARGET, 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 { struct pipe_resource *dst; unsigned dst_level; unsigned dstx, dsty, dstz; struct pipe_resource *src; unsigned src_level; struct pipe_box src_box; @@ -117,34 +123,74 @@ struct call_draw_info { struct call_get_query_result_resource { struct pipe_query *query; enum pipe_query_type query_type; boolean wait; enum pipe_query_value_type result_type; int index; struct pipe_resource *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; union { struct call_draw_info draw_vbo; struct pipe_grid_info launch_grid; struct call_resource_copy_region resource_copy_region; struct pipe_blit_info blit; struct pipe_resource *flush_resource; struct call_clear clear; 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; }; struct dd_query { unsigned type; struct pipe_query *query; }; struct dd_state diff --git a/src/gallium/drivers/ddebug/dd_screen.c b/src/gallium/drivers/ddebug/dd_screen.c index 11d1d8c1e9c..5b2be28a969 100644 --- a/src/gallium/drivers/ddebug/dd_screen.c +++ b/src/gallium/drivers/ddebug/dd_screen.c @@ -421,47 +421,51 @@ match_uint(const char **cur, unsigned *value) return true; } struct pipe_screen * ddebug_screen_create(struct pipe_screen *screen) { struct dd_screen *dscreen; 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; option = debug_get_option("GALLIUM_DDEBUG", NULL); if (!option) return screen; if (!strcmp(option, "help")) { puts("Gallium driver debugger"); 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"); puts("$HOME/"DD_DIR"/. By default, watch for GPU hangs and only dump information"); puts("about draw calls related to the hang."); puts(""); puts("<timeout in ms>"); puts(" Change the default timeout for GPU hang detection (default=1000ms)."); puts(" Setting this to 0 will disable GPU hang detection entirely."); puts(""); 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."); puts(""); puts("flush"); puts(" Flush after every draw call."); puts(""); puts("verbose"); puts(" Write additional information to stderr."); puts(""); @@ -478,20 +482,22 @@ ddebug_screen_create(struct pipe_screen *screen) if (match_word(&option, "always")) { if (mode == DD_DUMP_APITRACE_CALL) { printf("ddebug: both 'always' and 'apitrace' specified\n"); exit(1); } 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")) { if (mode != DD_DUMP_ONLY_HANGS) { printf("ddebug: 'apitrace' can only appear once and not mixed with 'always'\n"); exit(1); } if (!match_uint(&option, &apitrace_dump_call)) { printf("ddebug: expected call number after 'apitrace'\n"); @@ -549,20 +555,21 @@ ddebug_screen_create(struct pipe_screen *screen) SCR_INIT(get_compiler_options); SCR_INIT(get_driver_uuid); SCR_INIT(get_device_uuid); #undef SCR_INIT dscreen->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; switch (dscreen->dump_mode) { case DD_DUMP_ALL_CALLS: fprintf(stderr, "Gallium debugger active. Logging all calls.\n"); break; case DD_DUMP_APITRACE_CALL: fprintf(stderr, "Gallium debugger active. Going to dump an apitrace call.\n"); break; -- 2.11.0 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev