[Mesa-dev] [PATCH 4/8] ddebug: log calls to pipe->flush
Nicolai Hähnle
nhaehnle at gmail.com
Wed Apr 24 13:14:32 UTC 2019
From: Nicolai Hähnle <nicolai.haehnle at amd.com>
This can be useful when internal draws lead to a hang.
---
src/gallium/auxiliary/driver_ddebug/dd_draw.c | 75 ++++++++++++++-----
src/gallium/auxiliary/driver_ddebug/dd_pipe.h | 6 ++
2 files changed, 61 insertions(+), 20 deletions(-)
diff --git a/src/gallium/auxiliary/driver_ddebug/dd_draw.c b/src/gallium/auxiliary/driver_ddebug/dd_draw.c
index 4eb0dd096f4..bda1891c49b 100644
--- a/src/gallium/auxiliary/driver_ddebug/dd_draw.c
+++ b/src/gallium/auxiliary/driver_ddebug/dd_draw.c
@@ -275,20 +275,27 @@ dd_dump_shader(struct dd_draw_state *dstate, enum pipe_shader_type sh, FILE *f)
for (i = 0; i < PIPE_MAX_SHADER_BUFFERS; i++)
if (dstate->shader_buffers[sh][i].buffer) {
DUMP_I(shader_buffer, &dstate->shader_buffers[sh][i], i);
if (dstate->shader_buffers[sh][i].buffer)
DUMP_M(resource, &dstate->shader_buffers[sh][i], buffer);
}
fprintf(f, COLOR_SHADER "end shader: %s" COLOR_RESET "\n\n", shader_str[sh]);
}
+static void
+dd_dump_flush(struct dd_draw_state *dstate, struct call_flush *info, FILE *f)
+{
+ fprintf(f, "%s:\n", __func__+8);
+ DUMP_M(hex, info, flags);
+}
+
static void
dd_dump_draw_vbo(struct dd_draw_state *dstate, struct pipe_draw_info *info, FILE *f)
{
int sh, i;
DUMP(draw_info, info);
if (info->count_from_stream_output)
DUMP_M(stream_output_target, info,
count_from_stream_output);
if (info->indirect) {
@@ -550,20 +557,23 @@ dd_dump_driver_state(struct dd_context *dctx, FILE *f, unsigned flags)
"***************************\n");
fprintf(f, "Driver-specific state:\n\n");
dctx->pipe->dump_debug_state(dctx->pipe, f, flags);
}
}
static void
dd_dump_call(FILE *f, struct dd_draw_state *state, struct dd_call *call)
{
switch (call->type) {
+ case CALL_FLUSH:
+ dd_dump_flush(state, &call->info.flush, f);
+ break;
case CALL_DRAW_VBO:
dd_dump_draw_vbo(state, &call->info.draw_vbo.draw, f);
break;
case CALL_LAUNCH_GRID:
dd_dump_launch_grid(state, &call->info.launch_grid, f);
break;
case CALL_RESOURCE_COPY_REGION:
dd_dump_resource_copy_region(state,
&call->info.resource_copy_region, f);
break;
@@ -621,20 +631,22 @@ dd_kill_process(void)
fprintf(stderr, "dd: Aborting the process...\n");
fflush(stdout);
fflush(stderr);
exit(1);
}
static void
dd_unreference_copy_of_call(struct dd_call *dst)
{
switch (dst->type) {
+ case CALL_FLUSH:
+ break;
case CALL_DRAW_VBO:
pipe_so_target_reference(&dst->info.draw_vbo.draw.count_from_stream_output, NULL);
pipe_resource_reference(&dst->info.draw_vbo.indirect.buffer, NULL);
pipe_resource_reference(&dst->info.draw_vbo.indirect.indirect_draw_count, NULL);
if (dst->info.draw_vbo.draw.index_size &&
!dst->info.draw_vbo.draw.has_user_indices)
pipe_resource_reference(&dst->info.draw_vbo.draw.index.resource, NULL);
else
dst->info.draw_vbo.draw.index.user = NULL;
break;
@@ -1086,27 +1098,37 @@ dd_create_record(struct dd_context *dctx)
util_queue_fence_init(&record->driver_finished);
util_queue_fence_reset(&record->driver_finished);
dd_init_copy_of_draw_state(&record->draw_state);
dd_copy_draw_state(&record->draw_state.base, &dctx->draw_state);
return record;
}
static void
-dd_context_flush(struct pipe_context *_pipe,
- struct pipe_fence_handle **fence, unsigned flags)
+dd_add_record(struct dd_context *dctx, struct dd_draw_record *record)
{
- struct dd_context *dctx = dd_context(_pipe);
- struct pipe_context *pipe = dctx->pipe;
+ mtx_lock(&dctx->mutex);
+ if (unlikely(dctx->num_records > 10000)) {
+ dctx->api_stalled = true;
+ /* Since this is only a heuristic to prevent the API thread from getting
+ * too far ahead, we don't need a loop here. */
+ cnd_wait(&dctx->cond, &dctx->mutex);
+ dctx->api_stalled = false;
+ }
- pipe->flush(pipe, fence, flags);
+ if (list_empty(&dctx->records))
+ cnd_signal(&dctx->cond);
+
+ list_addtail(&record->list, &dctx->records);
+ dctx->num_records++;
+ mtx_unlock(&dctx->mutex);
}
static void
dd_before_draw(struct dd_context *dctx, struct dd_draw_record *record)
{
struct dd_screen *dscreen = dd_screen(dctx->base.screen);
struct pipe_context *pipe = dctx->pipe;
struct pipe_screen *screen = dscreen->screen;
record->time_before = os_time_get_nano();
@@ -1118,35 +1140,21 @@ dd_before_draw(struct dd_context *dctx, struct dd_draw_record *record)
} else {
pipe->flush(pipe, &record->prev_bottom_of_pipe,
PIPE_FLUSH_DEFERRED | PIPE_FLUSH_BOTTOM_OF_PIPE);
pipe->flush(pipe, &record->top_of_pipe,
PIPE_FLUSH_DEFERRED | PIPE_FLUSH_TOP_OF_PIPE);
}
} else if (dscreen->flush_always && dctx->num_draw_calls >= dscreen->skip_count) {
pipe->flush(pipe, NULL, 0);
}
- mtx_lock(&dctx->mutex);
- if (unlikely(dctx->num_records > 10000)) {
- dctx->api_stalled = true;
- /* Since this is only a heuristic to prevent the API thread from getting
- * too far ahead, we don't need a loop here. */
- cnd_wait(&dctx->cond, &dctx->mutex);
- dctx->api_stalled = false;
- }
-
- if (list_empty(&dctx->records))
- cnd_signal(&dctx->cond);
-
- list_addtail(&record->list, &dctx->records);
- dctx->num_records++;
- mtx_unlock(&dctx->mutex);
+ dd_add_record(dctx, record);
}
static void
dd_after_draw_async(void *data)
{
struct dd_draw_record *record = (struct dd_draw_record *)data;
struct dd_context *dctx = record->dctx;
struct dd_screen *dscreen = dd_screen(dctx->base.screen);
record->log_page = u_log_new_page(&dctx->log);
@@ -1182,20 +1190,47 @@ dd_after_draw(struct dd_context *dctx, struct dd_draw_record *record)
} else {
dd_after_draw_async(record);
}
++dctx->num_draw_calls;
if (dscreen->skip_count && dctx->num_draw_calls % 10000 == 0)
fprintf(stderr, "Gallium debugger reached %u draw calls.\n",
dctx->num_draw_calls);
}
+static void
+dd_context_flush(struct pipe_context *_pipe,
+ struct pipe_fence_handle **fence, unsigned flags)
+{
+ struct dd_context *dctx = dd_context(_pipe);
+ struct pipe_context *pipe = dctx->pipe;
+ struct pipe_screen *screen = pipe->screen;
+ struct dd_draw_record *record = dd_create_record(dctx);
+
+ record->call.type = CALL_FLUSH;
+ record->call.info.flush.flags = flags;
+
+ record->time_before = os_time_get_nano();
+
+ dd_add_record(dctx, record);
+
+ pipe->flush(pipe, &record->bottom_of_pipe, flags);
+ if (fence)
+ screen->fence_reference(screen, fence, record->bottom_of_pipe);
+
+ if (pipe->callback) {
+ pipe->callback(pipe, dd_after_draw_async, record, true);
+ } else {
+ dd_after_draw_async(record);
+ }
+}
+
static void
dd_context_draw_vbo(struct pipe_context *_pipe,
const struct pipe_draw_info *info)
{
struct dd_context *dctx = dd_context(_pipe);
struct pipe_context *pipe = dctx->pipe;
struct dd_draw_record *record = dd_create_record(dctx);
record->call.type = CALL_DRAW_VBO;
record->call.info.draw_vbo.draw = *info;
diff --git a/src/gallium/auxiliary/driver_ddebug/dd_pipe.h b/src/gallium/auxiliary/driver_ddebug/dd_pipe.h
index 12da8280aa6..708b2463e2b 100644
--- a/src/gallium/auxiliary/driver_ddebug/dd_pipe.h
+++ b/src/gallium/auxiliary/driver_ddebug/dd_pipe.h
@@ -53,20 +53,21 @@ struct dd_screen
enum dd_dump_mode dump_mode;
bool flush_always;
bool transfers;
bool verbose;
unsigned skip_count;
unsigned apitrace_dump_call;
};
enum call_type
{
+ CALL_FLUSH,
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,
@@ -108,20 +109,24 @@ struct call_clear_buffer
struct call_generate_mipmap {
struct pipe_resource *res;
enum pipe_format format;
unsigned base_level;
unsigned last_level;
unsigned first_layer;
unsigned last_layer;
};
+struct call_flush {
+ unsigned flags;
+};
+
struct call_draw_info {
struct pipe_draw_info draw;
struct pipe_draw_indirect_info indirect;
};
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;
@@ -163,20 +168,21 @@ struct call_texture_subdata {
const void *data;
unsigned stride;
unsigned layer_stride;
};
struct dd_call
{
enum call_type type;
union {
+ struct call_flush flush;
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;
--
2.20.1
More information about the mesa-dev
mailing list