From: Nicolai Hähnle <nicolai.haeh...@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 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev