diff options
author | Marek Olšák <[email protected]> | 2015-07-04 14:10:21 +0200 |
---|---|---|
committer | Marek Olšák <[email protected]> | 2015-08-26 19:25:18 +0200 |
commit | 525921ed51176255474c73adacfc6801a7bf2783 (patch) | |
tree | 2695524d4f9d915a8c5bce90590a2086aebc3d74 /src/gallium/drivers/ddebug/dd_draw.c | |
parent | 0fc21ecfc0891d239f20bf7724e51bc75503570c (diff) |
gallium/ddebug: new pipe for hang detection and driver state dumping (v2)
v2: lots of improvements
This is like identity or trace, but simpler. It doesn't wrap most states.
Run with:
GALLIUM_DDEBUG=1000 [executable]
where "executable" is the app and "1000" is in miliseconds, meaning that
the context will be considered hung if a fence fails to signal in 1000 ms.
If that happens, all shaders, context states, bound resources, draw
parameters, and driver debug information (if any) will be dumped into:
/home/$username/dd_dumps/$processname_$pid_$index.
Note that the context is flushed after every draw/clear/copy/blit operation
and then waited for to find the exact call that hangs.
You can also do:
GALLIUM_DDEBUG=always
to do the dumping after every draw/clear/copy/blit operation without
flushing and waiting.
Examples of driver states that can be dumped are:
- Hardware status registers saying which hw block is busy (hung).
- Disassembled shaders in a human-readable form.
- The last submitted command buffer in a human-readable form.
v2: drop pipe-loader changes, drop SConscript
rename dd.h -> dd_pipe.h
Acked-by: Christian König <[email protected]>
Acked-by: Alex Deucher <[email protected]>
Diffstat (limited to 'src/gallium/drivers/ddebug/dd_draw.c')
-rw-r--r-- | src/gallium/drivers/ddebug/dd_draw.c | 807 |
1 files changed, 807 insertions, 0 deletions
diff --git a/src/gallium/drivers/ddebug/dd_draw.c b/src/gallium/drivers/ddebug/dd_draw.c new file mode 100644 index 00000000000..1c986238708 --- /dev/null +++ b/src/gallium/drivers/ddebug/dd_draw.c @@ -0,0 +1,807 @@ +/************************************************************************** + * + * Copyright 2015 Advanced Micro Devices, Inc. + * Copyright 2008 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "dd_pipe.h" + +#include "util/u_dump.h" +#include "util/u_format.h" +#include "tgsi/tgsi_scan.h" +#include "os/os_process.h" +#include <errno.h> +#include <sys/stat.h> + + +enum call_type +{ + CALL_DRAW_VBO, + CALL_RESOURCE_COPY_REGION, + CALL_BLIT, + CALL_FLUSH_RESOURCE, + CALL_CLEAR, + CALL_CLEAR_BUFFER, + CALL_CLEAR_RENDER_TARGET, + CALL_CLEAR_DEPTH_STENCIL, +}; + +struct call_resource_copy_region +{ + struct pipe_resource *dst; + unsigned dst_level; + unsigned dstx, dsty, dstz; + struct pipe_resource *src; + unsigned src_level; + const struct pipe_box *src_box; +}; + +struct call_clear +{ + unsigned buffers; + const union pipe_color_union *color; + double depth; + unsigned stencil; +}; + +struct call_clear_buffer +{ + struct pipe_resource *res; + unsigned offset; + unsigned size; + const void *clear_value; + int clear_value_size; +}; + +struct dd_call +{ + enum call_type type; + + union { + struct pipe_draw_info draw_vbo; + 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; + } info; +}; + + +static FILE * +dd_get_file_stream(struct dd_context *dctx) +{ + struct pipe_screen *screen = dctx->pipe->screen; + static unsigned index; + char proc_name[128], dir[256], name[512]; + FILE *f; + + if (!os_get_process_name(proc_name, sizeof(proc_name))) { + fprintf(stderr, "dd: can't get the process name\n"); + return NULL; + } + + snprintf(dir, sizeof(dir), "%s/"DD_DIR, debug_get_option("HOME", ".")); + + if (mkdir(dir, 0774) && errno != EEXIST) { + fprintf(stderr, "dd: can't create a directory (%i)\n", errno); + return NULL; + } + + snprintf(name, sizeof(name), "%s/%s_%u_%08u", dir, proc_name, getpid(), index++); + f = fopen(name, "w"); + if (!f) { + fprintf(stderr, "dd: can't open file %s\n", name); + return NULL; + } + + fprintf(f, "Driver vendor: %s\n", screen->get_vendor(screen)); + fprintf(f, "Device vendor: %s\n", screen->get_device_vendor(screen)); + fprintf(f, "Device name: %s\n\n", screen->get_name(screen)); + return f; +} + +static void +dd_close_file_stream(FILE *f) +{ + fclose(f); +} + +static unsigned +dd_num_active_viewports(struct dd_context *dctx) +{ + struct tgsi_shader_info info; + const struct tgsi_token *tokens; + + if (dctx->shaders[PIPE_SHADER_GEOMETRY]) + tokens = dctx->shaders[PIPE_SHADER_GEOMETRY]->state.shader.tokens; + else if (dctx->shaders[PIPE_SHADER_TESS_EVAL]) + tokens = dctx->shaders[PIPE_SHADER_TESS_EVAL]->state.shader.tokens; + else if (dctx->shaders[PIPE_SHADER_VERTEX]) + tokens = dctx->shaders[PIPE_SHADER_VERTEX]->state.shader.tokens; + else + return 1; + + tgsi_scan_shader(tokens, &info); + return info.writes_viewport_index ? PIPE_MAX_VIEWPORTS : 1; +} + +#define COLOR_RESET "\033[0m" +#define COLOR_SHADER "\033[1;32m" +#define COLOR_STATE "\033[1;33m" + +#define DUMP(name, var) do { \ + fprintf(f, COLOR_STATE #name ": " COLOR_RESET); \ + util_dump_##name(f, var); \ + fprintf(f, "\n"); \ +} while(0) + +#define DUMP_I(name, var, i) do { \ + fprintf(f, COLOR_STATE #name " %i: " COLOR_RESET, i); \ + util_dump_##name(f, var); \ + fprintf(f, "\n"); \ +} while(0) + +#define DUMP_M(name, var, member) do { \ + fprintf(f, " " #member ": "); \ + util_dump_##name(f, (var)->member); \ + fprintf(f, "\n"); \ +} while(0) + +#define DUMP_M_ADDR(name, var, member) do { \ + fprintf(f, " " #member ": "); \ + util_dump_##name(f, &(var)->member); \ + fprintf(f, "\n"); \ +} while(0) + +static void +print_named_value(FILE *f, const char *name, int value) +{ + fprintf(f, COLOR_STATE "%s" COLOR_RESET " = %i\n", name, value); +} + +static void +print_named_xvalue(FILE *f, const char *name, int value) +{ + fprintf(f, COLOR_STATE "%s" COLOR_RESET " = 0x%08x\n", name, value); +} + +static void +util_dump_uint(FILE *f, unsigned i) +{ + fprintf(f, "%u", i); +} + +static void +util_dump_hex(FILE *f, unsigned i) +{ + fprintf(f, "0x%x", i); +} + +static void +util_dump_double(FILE *f, double d) +{ + fprintf(f, "%f", d); +} + +static void +util_dump_format(FILE *f, enum pipe_format format) +{ + fprintf(f, "%s", util_format_name(format)); +} + +static void +util_dump_color_union(FILE *f, const union pipe_color_union *color) +{ + fprintf(f, "{f = {%f, %f, %f, %f}, ui = {%u, %u, %u, %u}", + color->f[0], color->f[1], color->f[2], color->f[3], + color->ui[0], color->ui[1], color->ui[2], color->ui[3]); +} + +static void +util_dump_query(FILE *f, struct dd_query *query) +{ + if (query->type >= PIPE_QUERY_DRIVER_SPECIFIC) + fprintf(f, "PIPE_QUERY_DRIVER_SPECIFIC + %i", + query->type - PIPE_QUERY_DRIVER_SPECIFIC); + else + fprintf(f, "%s", util_dump_query_type(query->type, false)); +} + +static void +dd_dump_render_condition(struct dd_context *dctx, FILE *f) +{ + if (dctx->render_cond.query) { + fprintf(f, "render condition:\n"); + DUMP_M(query, &dctx->render_cond, query); + DUMP_M(uint, &dctx->render_cond, condition); + DUMP_M(uint, &dctx->render_cond, mode); + fprintf(f, "\n"); + } +} + +static void +dd_dump_draw_vbo(struct dd_context *dctx, struct pipe_draw_info *info, FILE *f) +{ + int sh, i; + const char *shader_str[PIPE_SHADER_TYPES]; + + shader_str[PIPE_SHADER_VERTEX] = "VERTEX"; + shader_str[PIPE_SHADER_TESS_CTRL] = "TESS_CTRL"; + shader_str[PIPE_SHADER_TESS_EVAL] = "TESS_EVAL"; + shader_str[PIPE_SHADER_GEOMETRY] = "GEOMETRY"; + shader_str[PIPE_SHADER_FRAGMENT] = "FRAGMENT"; + shader_str[PIPE_SHADER_COMPUTE] = "COMPUTE"; + + DUMP(draw_info, info); + if (info->indexed) { + DUMP(index_buffer, &dctx->index_buffer); + if (dctx->index_buffer.buffer) + DUMP_M(resource, &dctx->index_buffer, buffer); + } + if (info->count_from_stream_output) + DUMP_M(stream_output_target, info, + count_from_stream_output); + if (info->indirect) + DUMP_M(resource, info, indirect); + fprintf(f, "\n"); + + /* TODO: dump active queries */ + + dd_dump_render_condition(dctx, f); + + for (i = 0; i < PIPE_MAX_ATTRIBS; i++) + if (dctx->vertex_buffers[i].buffer || + dctx->vertex_buffers[i].user_buffer) { + DUMP_I(vertex_buffer, &dctx->vertex_buffers[i], i); + if (dctx->vertex_buffers[i].buffer) + DUMP_M(resource, &dctx->vertex_buffers[i], buffer); + } + + if (dctx->velems) { + print_named_value(f, "num vertex elements", + dctx->velems->state.velems.count); + for (i = 0; i < dctx->velems->state.velems.count; i++) { + fprintf(f, " "); + DUMP_I(vertex_element, &dctx->velems->state.velems.velems[i], i); + } + } + + print_named_value(f, "num stream output targets", dctx->num_so_targets); + for (i = 0; i < dctx->num_so_targets; i++) + if (dctx->so_targets[i]) { + DUMP_I(stream_output_target, dctx->so_targets[i], i); + DUMP_M(resource, dctx->so_targets[i], buffer); + fprintf(f, " offset = %i\n", dctx->so_offsets[i]); + } + + fprintf(f, "\n"); + for (sh = 0; sh < PIPE_SHADER_TYPES; sh++) { + if (sh == PIPE_SHADER_COMPUTE) + continue; + + if (sh == PIPE_SHADER_TESS_CTRL && + !dctx->shaders[PIPE_SHADER_TESS_CTRL] && + dctx->shaders[PIPE_SHADER_TESS_EVAL]) + fprintf(f, "tess_state: {default_outer_level = {%f, %f, %f, %f}, " + "default_inner_level = {%f, %f}}\n", + dctx->tess_default_levels[0], + dctx->tess_default_levels[1], + dctx->tess_default_levels[2], + dctx->tess_default_levels[3], + dctx->tess_default_levels[4], + dctx->tess_default_levels[5]); + + if (sh == PIPE_SHADER_FRAGMENT) + if (dctx->rs) { + unsigned num_viewports = dd_num_active_viewports(dctx); + + if (dctx->rs->state.rs.clip_plane_enable) + DUMP(clip_state, &dctx->clip_state); + + for (i = 0; i < num_viewports; i++) + DUMP_I(viewport_state, &dctx->viewports[i], i); + + if (dctx->rs->state.rs.scissor) + for (i = 0; i < num_viewports; i++) + DUMP_I(scissor_state, &dctx->scissors[i], i); + + DUMP(rasterizer_state, &dctx->rs->state.rs); + + if (dctx->rs->state.rs.poly_stipple_enable) + DUMP(poly_stipple, &dctx->polygon_stipple); + fprintf(f, "\n"); + } + + if (!dctx->shaders[sh]) + continue; + + fprintf(f, COLOR_SHADER "begin shader: %s" COLOR_RESET "\n", shader_str[sh]); + DUMP(shader_state, &dctx->shaders[sh]->state.shader); + + for (i = 0; i < PIPE_MAX_CONSTANT_BUFFERS; i++) + if (dctx->constant_buffers[sh][i].buffer || + dctx->constant_buffers[sh][i].user_buffer) { + DUMP_I(constant_buffer, &dctx->constant_buffers[sh][i], i); + if (dctx->constant_buffers[sh][i].buffer) + DUMP_M(resource, &dctx->constant_buffers[sh][i], buffer); + } + + for (i = 0; i < PIPE_MAX_SAMPLERS; i++) + if (dctx->sampler_states[sh][i]) + DUMP_I(sampler_state, &dctx->sampler_states[sh][i]->state.sampler, i); + + for (i = 0; i < PIPE_MAX_SAMPLERS; i++) + if (dctx->sampler_views[sh][i]) { + DUMP_I(sampler_view, dctx->sampler_views[sh][i], i); + DUMP_M(resource, dctx->sampler_views[sh][i], texture); + } + + /* TODO: print shader images */ + /* TODO: print shader buffers */ + + fprintf(f, COLOR_SHADER "end shader: %s" COLOR_RESET "\n\n", shader_str[sh]); + } + + if (dctx->dsa) + DUMP(depth_stencil_alpha_state, &dctx->dsa->state.dsa); + DUMP(stencil_ref, &dctx->stencil_ref); + + if (dctx->blend) + DUMP(blend_state, &dctx->blend->state.blend); + DUMP(blend_color, &dctx->blend_color); + + print_named_value(f, "min_samples", dctx->min_samples); + print_named_xvalue(f, "sample_mask", dctx->sample_mask); + fprintf(f, "\n"); + + DUMP(framebuffer_state, &dctx->framebuffer_state); + for (i = 0; i < dctx->framebuffer_state.nr_cbufs; i++) + if (dctx->framebuffer_state.cbufs[i]) { + fprintf(f, " " COLOR_STATE "cbufs[%i]:" COLOR_RESET "\n ", i); + DUMP(surface, dctx->framebuffer_state.cbufs[i]); + fprintf(f, " "); + DUMP(resource, dctx->framebuffer_state.cbufs[i]->texture); + } + if (dctx->framebuffer_state.zsbuf) { + fprintf(f, " " COLOR_STATE "zsbuf:" COLOR_RESET "\n "); + DUMP(surface, dctx->framebuffer_state.zsbuf); + fprintf(f, " "); + DUMP(resource, dctx->framebuffer_state.zsbuf->texture); + } + fprintf(f, "\n"); +} + +static void +dd_dump_resource_copy_region(struct dd_context *dctx, + struct call_resource_copy_region *info, + FILE *f) +{ + fprintf(f, "%s:\n", __func__+8); + DUMP_M(resource, info, dst); + DUMP_M(uint, info, dst_level); + DUMP_M(uint, info, dstx); + DUMP_M(uint, info, dsty); + DUMP_M(uint, info, dstz); + DUMP_M(resource, info, src); + DUMP_M(uint, info, src_level); + DUMP_M(box, info, src_box); +} + +static void +dd_dump_blit(struct dd_context *dctx, struct pipe_blit_info *info, FILE *f) +{ + fprintf(f, "%s:\n", __func__+8); + DUMP_M(resource, info, dst.resource); + DUMP_M(uint, info, dst.level); + DUMP_M_ADDR(box, info, dst.box); + DUMP_M(format, info, dst.format); + + DUMP_M(resource, info, src.resource); + DUMP_M(uint, info, src.level); + DUMP_M_ADDR(box, info, src.box); + DUMP_M(format, info, src.format); + + DUMP_M(hex, info, mask); + DUMP_M(uint, info, filter); + DUMP_M(uint, info, scissor_enable); + DUMP_M_ADDR(scissor_state, info, scissor); + DUMP_M(uint, info, render_condition_enable); + + if (info->render_condition_enable) + dd_dump_render_condition(dctx, f); +} + +static void +dd_dump_flush_resource(struct dd_context *dctx, struct pipe_resource *res, + FILE *f) +{ + fprintf(f, "%s:\n", __func__+8); + DUMP(resource, res); +} + +static void +dd_dump_clear(struct dd_context *dctx, struct call_clear *info, FILE *f) +{ + fprintf(f, "%s:\n", __func__+8); + DUMP_M(uint, info, buffers); + DUMP_M(color_union, info, color); + DUMP_M(double, info, depth); + DUMP_M(hex, info, stencil); +} + +static void +dd_dump_clear_buffer(struct dd_context *dctx, struct call_clear_buffer *info, + FILE *f) +{ + int i; + const char *value = (const char*)info->clear_value; + + fprintf(f, "%s:\n", __func__+8); + DUMP_M(resource, info, res); + DUMP_M(uint, info, offset); + 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_clear_render_target(struct dd_context *dctx, FILE *f) +{ + fprintf(f, "%s:\n", __func__+8); + /* TODO */ +} + +static void +dd_dump_clear_depth_stencil(struct dd_context *dctx, FILE *f) +{ + fprintf(f, "%s:\n", __func__+8); + /* TODO */ +} + +static void +dd_dump_driver_state(struct dd_context *dctx, FILE *f, unsigned flags) +{ + if (dctx->pipe->dump_debug_state) { + fprintf(f,"\n\n**************************************************" + "***************************\n"); + fprintf(f, "Driver-specific state:\n\n"); + dctx->pipe->dump_debug_state(dctx->pipe, f, flags); + } +} + +static void +dd_dump_call(struct dd_context *dctx, struct dd_call *call, unsigned flags) +{ + FILE *f = dd_get_file_stream(dctx); + + if (!f) + return; + + switch (call->type) { + case CALL_DRAW_VBO: + dd_dump_draw_vbo(dctx, &call->info.draw_vbo, f); + break; + case CALL_RESOURCE_COPY_REGION: + dd_dump_resource_copy_region(dctx, &call->info.resource_copy_region, f); + break; + case CALL_BLIT: + dd_dump_blit(dctx, &call->info.blit, f); + break; + case CALL_FLUSH_RESOURCE: + dd_dump_flush_resource(dctx, call->info.flush_resource, f); + break; + case CALL_CLEAR: + dd_dump_clear(dctx, &call->info.clear, f); + break; + case CALL_CLEAR_BUFFER: + dd_dump_clear_buffer(dctx, &call->info.clear_buffer, f); + break; + case CALL_CLEAR_RENDER_TARGET: + dd_dump_clear_render_target(dctx, f); + break; + case CALL_CLEAR_DEPTH_STENCIL: + dd_dump_clear_depth_stencil(dctx, f); + } + + dd_dump_driver_state(dctx, f, flags); + dd_close_file_stream(f); +} + +static void +dd_kill_process(void) +{ + sync(); + fprintf(stderr, "dd: Aborting the process...\n"); + fflush(stdout); + fflush(stderr); + abort(); +} + +static bool +dd_flush_and_check_hang(struct dd_context *dctx, + struct pipe_fence_handle **flush_fence, + unsigned flush_flags) +{ + struct pipe_fence_handle *fence = NULL; + struct pipe_context *pipe = dctx->pipe; + struct pipe_screen *screen = pipe->screen; + uint64_t timeout_ms = dd_screen(dctx->base.screen)->timeout_ms; + bool idle; + + assert(timeout_ms > 0); + + pipe->flush(pipe, &fence, flush_flags); + if (flush_fence) + screen->fence_reference(screen, flush_fence, fence); + if (!fence) + return false; + + idle = screen->fence_finish(screen, fence, timeout_ms * 1000000); + screen->fence_reference(screen, &fence, NULL); + if (!idle) + fprintf(stderr, "dd: GPU hang detected!\n"); + return !idle; +} + +static void +dd_flush_and_handle_hang(struct dd_context *dctx, + struct pipe_fence_handle **fence, unsigned flags, + const char *cause) +{ + if (dd_flush_and_check_hang(dctx, fence, flags)) { + FILE *f = dd_get_file_stream(dctx); + + if (f) { + fprintf(f, "dd: %s.\n", cause); + dd_dump_driver_state(dctx, f, PIPE_DEBUG_DEVICE_IS_HUNG); + dd_close_file_stream(f); + } + + /* Terminate the process to prevent future hangs. */ + dd_kill_process(); + } +} + +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; + + switch (dd_screen(dctx->base.screen)->mode) { + case DD_DETECT_HANGS: + dd_flush_and_handle_hang(dctx, fence, flags, + "GPU hang detected in pipe->flush()"); + break; + case DD_DUMP_ALL_CALLS: + pipe->flush(pipe, fence, flags); + break; + default: + assert(0); + } +} + +static void +dd_before_draw(struct dd_context *dctx) +{ + if (dd_screen(dctx->base.screen)->mode == DD_DETECT_HANGS && + !dd_screen(dctx->base.screen)->no_flush) + dd_flush_and_handle_hang(dctx, NULL, 0, + "GPU hang most likely caused by internal " + "driver commands"); +} + +static void +dd_after_draw(struct dd_context *dctx, struct dd_call *call) +{ + switch (dd_screen(dctx->base.screen)->mode) { + case DD_DETECT_HANGS: + if (!dd_screen(dctx->base.screen)->no_flush && + dd_flush_and_check_hang(dctx, NULL, 0)) { + dd_dump_call(dctx, call, PIPE_DEBUG_DEVICE_IS_HUNG); + + /* Terminate the process to prevent future hangs. */ + dd_kill_process(); + } + break; + case DD_DUMP_ALL_CALLS: + dd_dump_call(dctx, call, 0); + break; + default: + assert(0); + } +} + +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_call call; + + call.type = CALL_DRAW_VBO; + call.info.draw_vbo = *info; + + dd_before_draw(dctx); + pipe->draw_vbo(pipe, info); + dd_after_draw(dctx, &call); +} + +static void +dd_context_resource_copy_region(struct pipe_context *_pipe, + struct pipe_resource *dst, unsigned dst_level, + unsigned dstx, unsigned dsty, unsigned dstz, + struct pipe_resource *src, unsigned src_level, + const struct pipe_box *src_box) +{ + struct dd_context *dctx = dd_context(_pipe); + struct pipe_context *pipe = dctx->pipe; + struct dd_call call; + + call.type = CALL_RESOURCE_COPY_REGION; + call.info.resource_copy_region.dst = dst; + call.info.resource_copy_region.dst_level = dst_level; + call.info.resource_copy_region.dstx = dstx; + call.info.resource_copy_region.dsty = dsty; + call.info.resource_copy_region.dstz = dstz; + call.info.resource_copy_region.src = src; + call.info.resource_copy_region.src_level = src_level; + call.info.resource_copy_region.src_box = src_box; + + dd_before_draw(dctx); + pipe->resource_copy_region(pipe, + dst, dst_level, dstx, dsty, dstz, + src, src_level, src_box); + dd_after_draw(dctx, &call); +} + +static void +dd_context_blit(struct pipe_context *_pipe, const struct pipe_blit_info *info) +{ + struct dd_context *dctx = dd_context(_pipe); + struct pipe_context *pipe = dctx->pipe; + struct dd_call call; + + call.type = CALL_BLIT; + call.info.blit = *info; + + dd_before_draw(dctx); + pipe->blit(pipe, info); + dd_after_draw(dctx, &call); +} + +static void +dd_context_flush_resource(struct pipe_context *_pipe, + struct pipe_resource *resource) +{ + struct dd_context *dctx = dd_context(_pipe); + struct pipe_context *pipe = dctx->pipe; + struct dd_call call; + + call.type = CALL_FLUSH_RESOURCE; + call.info.flush_resource = resource; + + dd_before_draw(dctx); + pipe->flush_resource(pipe, resource); + dd_after_draw(dctx, &call); +} + +static void +dd_context_clear(struct pipe_context *_pipe, unsigned buffers, + const union pipe_color_union *color, double depth, + unsigned stencil) +{ + struct dd_context *dctx = dd_context(_pipe); + struct pipe_context *pipe = dctx->pipe; + struct dd_call call; + + call.type = CALL_CLEAR; + call.info.clear.buffers = buffers; + call.info.clear.color = color; + call.info.clear.depth = depth; + call.info.clear.stencil = stencil; + + dd_before_draw(dctx); + pipe->clear(pipe, buffers, color, depth, stencil); + dd_after_draw(dctx, &call); +} + +static void +dd_context_clear_render_target(struct pipe_context *_pipe, + struct pipe_surface *dst, + const union pipe_color_union *color, + unsigned dstx, unsigned dsty, + unsigned width, unsigned height) +{ + struct dd_context *dctx = dd_context(_pipe); + struct pipe_context *pipe = dctx->pipe; + struct dd_call call; + + call.type = CALL_CLEAR_RENDER_TARGET; + + dd_before_draw(dctx); + pipe->clear_render_target(pipe, dst, color, dstx, dsty, width, height); + dd_after_draw(dctx, &call); +} + +static void +dd_context_clear_depth_stencil(struct pipe_context *_pipe, + struct pipe_surface *dst, unsigned clear_flags, + double depth, unsigned stencil, unsigned dstx, + unsigned dsty, unsigned width, unsigned height) +{ + struct dd_context *dctx = dd_context(_pipe); + struct pipe_context *pipe = dctx->pipe; + struct dd_call call; + + call.type = CALL_CLEAR_DEPTH_STENCIL; + + dd_before_draw(dctx); + pipe->clear_depth_stencil(pipe, dst, clear_flags, depth, stencil, + dstx, dsty, width, height); + dd_after_draw(dctx, &call); +} + +static void +dd_context_clear_buffer(struct pipe_context *_pipe, struct pipe_resource *res, + unsigned offset, unsigned size, + const void *clear_value, int clear_value_size) +{ + struct dd_context *dctx = dd_context(_pipe); + struct pipe_context *pipe = dctx->pipe; + struct dd_call call; + + call.type = CALL_CLEAR_BUFFER; + call.info.clear_buffer.res = res; + call.info.clear_buffer.offset = offset; + call.info.clear_buffer.size = size; + call.info.clear_buffer.clear_value = clear_value; + call.info.clear_buffer.clear_value_size = clear_value_size; + + dd_before_draw(dctx); + pipe->clear_buffer(pipe, res, offset, size, clear_value, clear_value_size); + dd_after_draw(dctx, &call); +} + +void +dd_init_draw_functions(struct dd_context *dctx) +{ + CTX_INIT(flush); + CTX_INIT(draw_vbo); + 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(flush_resource); + /* launch_grid */ +} |