Path: blob/21.2-virgl/src/gallium/auxiliary/driver_ddebug/dd_draw.c
4561 views
/**************************************************************************1*2* Copyright 2015 Advanced Micro Devices, Inc.3* Copyright 2008 VMware, Inc.4* All Rights Reserved.5*6* Permission is hereby granted, free of charge, to any person obtaining a7* copy of this software and associated documentation files (the "Software"),8* to deal in the Software without restriction, including without limitation9* on the rights to use, copy, modify, merge, publish, distribute, sub10* license, and/or sell copies of the Software, and to permit persons to whom11* the Software is furnished to do so, subject to the following conditions:12*13* The above copyright notice and this permission notice (including the next14* paragraph) shall be included in all copies or substantial portions of the15* Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR18* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,19* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL20* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,21* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR22* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE23* USE OR OTHER DEALINGS IN THE SOFTWARE.24*25**************************************************************************/2627#include "dd_pipe.h"2829#include "util/u_dump.h"30#include "util/format/u_format.h"31#include "util/u_framebuffer.h"32#include "util/u_helpers.h"33#include "util/u_inlines.h"34#include "util/u_memory.h"35#include "util/u_process.h"36#include "tgsi/tgsi_parse.h"37#include "tgsi/tgsi_scan.h"38#include "util/os_time.h"39#include <inttypes.h>40#include "pipe/p_config.h"4142void43dd_get_debug_filename_and_mkdir(char *buf, size_t buflen, bool verbose)44{45static unsigned index;46char proc_name[128], dir[256];4748if (!os_get_process_name(proc_name, sizeof(proc_name))) {49fprintf(stderr, "dd: can't get the process name\n");50strcpy(proc_name, "unknown");51}5253snprintf(dir, sizeof(dir), "%s/"DD_DIR, debug_get_option("HOME", "."));5455if (mkdir(dir, 0774) && errno != EEXIST)56fprintf(stderr, "dd: can't create a directory (%i)\n", errno);5758snprintf(buf, buflen, "%s/%s_%u_%08u", dir, proc_name, (unsigned int)getpid(),59(unsigned int)p_atomic_inc_return(&index) - 1);6061if (verbose)62fprintf(stderr, "dd: dumping to file %s\n", buf);63}6465FILE *66dd_get_debug_file(bool verbose)67{68char name[512];69FILE *f;7071dd_get_debug_filename_and_mkdir(name, sizeof(name), verbose);72f = fopen(name, "w");73if (!f) {74fprintf(stderr, "dd: can't open file %s\n", name);75return NULL;76}7778return f;79}8081void82dd_parse_apitrace_marker(const char *string, int len, unsigned *call_number)83{84unsigned num;85char *s;8687if (len <= 0)88return;8990/* Make it zero-terminated. */91s = alloca(len + 1);92memcpy(s, string, len);93s[len] = 0;9495/* Parse the number. */96errno = 0;97num = strtol(s, NULL, 10);98if (errno)99return;100101*call_number = num;102}103104void105dd_write_header(FILE *f, struct pipe_screen *screen, unsigned apitrace_call_number)106{107char cmd_line[4096];108if (os_get_command_line(cmd_line, sizeof(cmd_line)))109fprintf(f, "Command: %s\n", cmd_line);110fprintf(f, "Driver vendor: %s\n", screen->get_vendor(screen));111fprintf(f, "Device vendor: %s\n", screen->get_device_vendor(screen));112fprintf(f, "Device name: %s\n\n", screen->get_name(screen));113114if (apitrace_call_number)115fprintf(f, "Last apitrace call: %u\n\n", apitrace_call_number);116}117118FILE *119dd_get_file_stream(struct dd_screen *dscreen, unsigned apitrace_call_number)120{121struct pipe_screen *screen = dscreen->screen;122123FILE *f = dd_get_debug_file(dscreen->verbose);124if (!f)125return NULL;126127dd_write_header(f, screen, apitrace_call_number);128return f;129}130131static void132dd_dump_dmesg(FILE *f)133{134#ifdef PIPE_OS_LINUX135char line[2000];136FILE *p = popen("dmesg | tail -n60", "r");137138if (!p)139return;140141fprintf(f, "\nLast 60 lines of dmesg:\n\n");142while (fgets(line, sizeof(line), p))143fputs(line, f);144145pclose(p);146#endif147}148149static unsigned150dd_num_active_viewports(struct dd_draw_state *dstate)151{152struct tgsi_shader_info info;153const struct tgsi_token *tokens;154155if (dstate->shaders[PIPE_SHADER_GEOMETRY])156tokens = dstate->shaders[PIPE_SHADER_GEOMETRY]->state.shader.tokens;157else if (dstate->shaders[PIPE_SHADER_TESS_EVAL])158tokens = dstate->shaders[PIPE_SHADER_TESS_EVAL]->state.shader.tokens;159else if (dstate->shaders[PIPE_SHADER_VERTEX])160tokens = dstate->shaders[PIPE_SHADER_VERTEX]->state.shader.tokens;161else162return 1;163164if (tokens) {165tgsi_scan_shader(tokens, &info);166if (info.writes_viewport_index)167return PIPE_MAX_VIEWPORTS;168}169170return 1;171}172173#define COLOR_RESET "\033[0m"174#define COLOR_SHADER "\033[1;32m"175#define COLOR_STATE "\033[1;33m"176177#define DUMP(name, var) do { \178fprintf(f, COLOR_STATE #name ": " COLOR_RESET); \179util_dump_##name(f, var); \180fprintf(f, "\n"); \181} while(0)182183#define DUMP_I(name, var, i) do { \184fprintf(f, COLOR_STATE #name " %i: " COLOR_RESET, i); \185util_dump_##name(f, var); \186fprintf(f, "\n"); \187} while(0)188189#define DUMP_M(name, var, member) do { \190fprintf(f, " " #member ": "); \191util_dump_##name(f, (var)->member); \192fprintf(f, "\n"); \193} while(0)194195#define DUMP_M_ADDR(name, var, member) do { \196fprintf(f, " " #member ": "); \197util_dump_##name(f, &(var)->member); \198fprintf(f, "\n"); \199} while(0)200201#define PRINT_NAMED(type, name, value) \202do { \203fprintf(f, COLOR_STATE "%s" COLOR_RESET " = ", name); \204util_dump_##type(f, value); \205fprintf(f, "\n"); \206} while (0)207208static void209util_dump_uint(FILE *f, unsigned i)210{211fprintf(f, "%u", i);212}213214static void215util_dump_int(FILE *f, int i)216{217fprintf(f, "%d", i);218}219220static void221util_dump_hex(FILE *f, unsigned i)222{223fprintf(f, "0x%x", i);224}225226static void227util_dump_double(FILE *f, double d)228{229fprintf(f, "%f", d);230}231232static void233util_dump_format(FILE *f, enum pipe_format format)234{235fprintf(f, "%s", util_format_name(format));236}237238static void239util_dump_color_union(FILE *f, const union pipe_color_union *color)240{241fprintf(f, "{f = {%f, %f, %f, %f}, ui = {%u, %u, %u, %u}",242color->f[0], color->f[1], color->f[2], color->f[3],243color->ui[0], color->ui[1], color->ui[2], color->ui[3]);244}245246static void247dd_dump_render_condition(struct dd_draw_state *dstate, FILE *f)248{249if (dstate->render_cond.query) {250fprintf(f, "render condition:\n");251DUMP_M(query_type, &dstate->render_cond, query->type);252DUMP_M(uint, &dstate->render_cond, condition);253DUMP_M(uint, &dstate->render_cond, mode);254fprintf(f, "\n");255}256}257258static void259dd_dump_shader(struct dd_draw_state *dstate, enum pipe_shader_type sh, FILE *f)260{261int i;262const char *shader_str[PIPE_SHADER_TYPES];263264shader_str[PIPE_SHADER_VERTEX] = "VERTEX";265shader_str[PIPE_SHADER_TESS_CTRL] = "TESS_CTRL";266shader_str[PIPE_SHADER_TESS_EVAL] = "TESS_EVAL";267shader_str[PIPE_SHADER_GEOMETRY] = "GEOMETRY";268shader_str[PIPE_SHADER_FRAGMENT] = "FRAGMENT";269shader_str[PIPE_SHADER_COMPUTE] = "COMPUTE";270271if (sh == PIPE_SHADER_TESS_CTRL &&272!dstate->shaders[PIPE_SHADER_TESS_CTRL] &&273dstate->shaders[PIPE_SHADER_TESS_EVAL])274fprintf(f, "tess_state: {default_outer_level = {%f, %f, %f, %f}, "275"default_inner_level = {%f, %f}}\n",276dstate->tess_default_levels[0],277dstate->tess_default_levels[1],278dstate->tess_default_levels[2],279dstate->tess_default_levels[3],280dstate->tess_default_levels[4],281dstate->tess_default_levels[5]);282283if (sh == PIPE_SHADER_FRAGMENT)284if (dstate->rs) {285unsigned num_viewports = dd_num_active_viewports(dstate);286287if (dstate->rs->state.rs.clip_plane_enable)288DUMP(clip_state, &dstate->clip_state);289290for (i = 0; i < num_viewports; i++)291DUMP_I(viewport_state, &dstate->viewports[i], i);292293if (dstate->rs->state.rs.scissor)294for (i = 0; i < num_viewports; i++)295DUMP_I(scissor_state, &dstate->scissors[i], i);296297DUMP(rasterizer_state, &dstate->rs->state.rs);298299if (dstate->rs->state.rs.poly_stipple_enable)300DUMP(poly_stipple, &dstate->polygon_stipple);301fprintf(f, "\n");302}303304if (!dstate->shaders[sh])305return;306307fprintf(f, COLOR_SHADER "begin shader: %s" COLOR_RESET "\n", shader_str[sh]);308DUMP(shader_state, &dstate->shaders[sh]->state.shader);309310for (i = 0; i < PIPE_MAX_CONSTANT_BUFFERS; i++)311if (dstate->constant_buffers[sh][i].buffer ||312dstate->constant_buffers[sh][i].user_buffer) {313DUMP_I(constant_buffer, &dstate->constant_buffers[sh][i], i);314if (dstate->constant_buffers[sh][i].buffer)315DUMP_M(resource, &dstate->constant_buffers[sh][i], buffer);316}317318for (i = 0; i < PIPE_MAX_SAMPLERS; i++)319if (dstate->sampler_states[sh][i])320DUMP_I(sampler_state, &dstate->sampler_states[sh][i]->state.sampler, i);321322for (i = 0; i < PIPE_MAX_SAMPLERS; i++)323if (dstate->sampler_views[sh][i]) {324DUMP_I(sampler_view, dstate->sampler_views[sh][i], i);325DUMP_M(resource, dstate->sampler_views[sh][i], texture);326}327328for (i = 0; i < PIPE_MAX_SHADER_IMAGES; i++)329if (dstate->shader_images[sh][i].resource) {330DUMP_I(image_view, &dstate->shader_images[sh][i], i);331if (dstate->shader_images[sh][i].resource)332DUMP_M(resource, &dstate->shader_images[sh][i], resource);333}334335for (i = 0; i < PIPE_MAX_SHADER_BUFFERS; i++)336if (dstate->shader_buffers[sh][i].buffer) {337DUMP_I(shader_buffer, &dstate->shader_buffers[sh][i], i);338if (dstate->shader_buffers[sh][i].buffer)339DUMP_M(resource, &dstate->shader_buffers[sh][i], buffer);340}341342fprintf(f, COLOR_SHADER "end shader: %s" COLOR_RESET "\n\n", shader_str[sh]);343}344345static void346dd_dump_flush(struct dd_draw_state *dstate, struct call_flush *info, FILE *f)347{348fprintf(f, "%s:\n", __func__+8);349DUMP_M(hex, info, flags);350}351352static void353dd_dump_draw_vbo(struct dd_draw_state *dstate, struct pipe_draw_info *info,354unsigned drawid_offset,355const struct pipe_draw_indirect_info *indirect,356const struct pipe_draw_start_count_bias *draw, FILE *f)357{358int sh, i;359360DUMP(draw_info, info);361PRINT_NAMED(int, "drawid offset", drawid_offset);362DUMP(draw_start_count_bias, draw);363if (indirect) {364if (indirect->buffer)365DUMP_M(resource, indirect, buffer);366if (indirect->indirect_draw_count)367DUMP_M(resource, indirect, indirect_draw_count);368if (indirect->count_from_stream_output)369DUMP_M(stream_output_target, indirect, count_from_stream_output);370}371372fprintf(f, "\n");373374/* TODO: dump active queries */375376dd_dump_render_condition(dstate, f);377378for (i = 0; i < PIPE_MAX_ATTRIBS; i++)379if (dstate->vertex_buffers[i].buffer.resource) {380DUMP_I(vertex_buffer, &dstate->vertex_buffers[i], i);381if (!dstate->vertex_buffers[i].is_user_buffer)382DUMP_M(resource, &dstate->vertex_buffers[i], buffer.resource);383}384385if (dstate->velems) {386PRINT_NAMED(uint, "num vertex elements",387dstate->velems->state.velems.count);388for (i = 0; i < dstate->velems->state.velems.count; i++) {389fprintf(f, " ");390DUMP_I(vertex_element, &dstate->velems->state.velems.velems[i], i);391}392}393394PRINT_NAMED(uint, "num stream output targets", dstate->num_so_targets);395for (i = 0; i < dstate->num_so_targets; i++)396if (dstate->so_targets[i]) {397DUMP_I(stream_output_target, dstate->so_targets[i], i);398DUMP_M(resource, dstate->so_targets[i], buffer);399fprintf(f, " offset = %i\n", dstate->so_offsets[i]);400}401402fprintf(f, "\n");403for (sh = 0; sh < PIPE_SHADER_TYPES; sh++) {404if (sh == PIPE_SHADER_COMPUTE)405continue;406407dd_dump_shader(dstate, sh, f);408}409410if (dstate->dsa)411DUMP(depth_stencil_alpha_state, &dstate->dsa->state.dsa);412DUMP(stencil_ref, &dstate->stencil_ref);413414if (dstate->blend)415DUMP(blend_state, &dstate->blend->state.blend);416DUMP(blend_color, &dstate->blend_color);417418PRINT_NAMED(uint, "min_samples", dstate->min_samples);419PRINT_NAMED(hex, "sample_mask", dstate->sample_mask);420fprintf(f, "\n");421422DUMP(framebuffer_state, &dstate->framebuffer_state);423for (i = 0; i < dstate->framebuffer_state.nr_cbufs; i++)424if (dstate->framebuffer_state.cbufs[i]) {425fprintf(f, " " COLOR_STATE "cbufs[%i]:" COLOR_RESET "\n ", i);426DUMP(surface, dstate->framebuffer_state.cbufs[i]);427fprintf(f, " ");428DUMP(resource, dstate->framebuffer_state.cbufs[i]->texture);429}430if (dstate->framebuffer_state.zsbuf) {431fprintf(f, " " COLOR_STATE "zsbuf:" COLOR_RESET "\n ");432DUMP(surface, dstate->framebuffer_state.zsbuf);433fprintf(f, " ");434DUMP(resource, dstate->framebuffer_state.zsbuf->texture);435}436fprintf(f, "\n");437}438439static void440dd_dump_launch_grid(struct dd_draw_state *dstate, struct pipe_grid_info *info, FILE *f)441{442fprintf(f, "%s:\n", __func__+8);443DUMP(grid_info, info);444fprintf(f, "\n");445446dd_dump_shader(dstate, PIPE_SHADER_COMPUTE, f);447fprintf(f, "\n");448}449450static void451dd_dump_resource_copy_region(struct dd_draw_state *dstate,452struct call_resource_copy_region *info,453FILE *f)454{455fprintf(f, "%s:\n", __func__+8);456DUMP_M(resource, info, dst);457DUMP_M(uint, info, dst_level);458DUMP_M(uint, info, dstx);459DUMP_M(uint, info, dsty);460DUMP_M(uint, info, dstz);461DUMP_M(resource, info, src);462DUMP_M(uint, info, src_level);463DUMP_M_ADDR(box, info, src_box);464}465466static void467dd_dump_blit(struct dd_draw_state *dstate, struct pipe_blit_info *info, FILE *f)468{469fprintf(f, "%s:\n", __func__+8);470DUMP_M(resource, info, dst.resource);471DUMP_M(uint, info, dst.level);472DUMP_M_ADDR(box, info, dst.box);473DUMP_M(format, info, dst.format);474475DUMP_M(resource, info, src.resource);476DUMP_M(uint, info, src.level);477DUMP_M_ADDR(box, info, src.box);478DUMP_M(format, info, src.format);479480DUMP_M(hex, info, mask);481DUMP_M(uint, info, filter);482DUMP_M(uint, info, scissor_enable);483DUMP_M_ADDR(scissor_state, info, scissor);484DUMP_M(uint, info, render_condition_enable);485486if (info->render_condition_enable)487dd_dump_render_condition(dstate, f);488}489490static void491dd_dump_generate_mipmap(struct dd_draw_state *dstate, FILE *f)492{493fprintf(f, "%s:\n", __func__+8);494/* TODO */495}496497static void498dd_dump_get_query_result_resource(struct call_get_query_result_resource *info, FILE *f)499{500fprintf(f, "%s:\n", __func__ + 8);501DUMP_M(query_type, info, query_type);502DUMP_M(uint, info, wait);503DUMP_M(query_value_type, info, result_type);504DUMP_M(int, info, index);505DUMP_M(resource, info, resource);506DUMP_M(uint, info, offset);507}508509static void510dd_dump_flush_resource(struct dd_draw_state *dstate, struct pipe_resource *res,511FILE *f)512{513fprintf(f, "%s:\n", __func__+8);514DUMP(resource, res);515}516517static void518dd_dump_clear(struct dd_draw_state *dstate, struct call_clear *info, FILE *f)519{520fprintf(f, "%s:\n", __func__+8);521DUMP_M(uint, info, buffers);522fprintf(f, " scissor_state: %d,%d %d,%d\n",523info->scissor_state.minx, info->scissor_state.miny,524info->scissor_state.maxx, info->scissor_state.maxy);525DUMP_M_ADDR(color_union, info, color);526DUMP_M(double, info, depth);527DUMP_M(hex, info, stencil);528}529530static void531dd_dump_clear_buffer(struct dd_draw_state *dstate, struct call_clear_buffer *info,532FILE *f)533{534int i;535const char *value = (const char*)info->clear_value;536537fprintf(f, "%s:\n", __func__+8);538DUMP_M(resource, info, res);539DUMP_M(uint, info, offset);540DUMP_M(uint, info, size);541DUMP_M(uint, info, clear_value_size);542543fprintf(f, " clear_value:");544for (i = 0; i < info->clear_value_size; i++)545fprintf(f, " %02x", value[i]);546fprintf(f, "\n");547}548549static void550dd_dump_transfer_map(struct call_transfer_map *info, FILE *f)551{552fprintf(f, "%s:\n", __func__+8);553DUMP_M_ADDR(transfer, info, transfer);554DUMP_M(ptr, info, transfer_ptr);555DUMP_M(ptr, info, ptr);556}557558static void559dd_dump_transfer_flush_region(struct call_transfer_flush_region *info, FILE *f)560{561fprintf(f, "%s:\n", __func__+8);562DUMP_M_ADDR(transfer, info, transfer);563DUMP_M(ptr, info, transfer_ptr);564DUMP_M_ADDR(box, info, box);565}566567static void568dd_dump_transfer_unmap(struct call_transfer_unmap *info, FILE *f)569{570fprintf(f, "%s:\n", __func__+8);571DUMP_M_ADDR(transfer, info, transfer);572DUMP_M(ptr, info, transfer_ptr);573}574575static void576dd_dump_buffer_subdata(struct call_buffer_subdata *info, FILE *f)577{578fprintf(f, "%s:\n", __func__+8);579DUMP_M(resource, info, resource);580DUMP_M(transfer_usage, info, usage);581DUMP_M(uint, info, offset);582DUMP_M(uint, info, size);583DUMP_M(ptr, info, data);584}585586static void587dd_dump_texture_subdata(struct call_texture_subdata *info, FILE *f)588{589fprintf(f, "%s:\n", __func__+8);590DUMP_M(resource, info, resource);591DUMP_M(uint, info, level);592DUMP_M(transfer_usage, info, usage);593DUMP_M_ADDR(box, info, box);594DUMP_M(ptr, info, data);595DUMP_M(uint, info, stride);596DUMP_M(uint, info, layer_stride);597}598599static void600dd_dump_clear_texture(struct dd_draw_state *dstate, FILE *f)601{602fprintf(f, "%s:\n", __func__+8);603/* TODO */604}605606static void607dd_dump_clear_render_target(struct dd_draw_state *dstate, FILE *f)608{609fprintf(f, "%s:\n", __func__+8);610/* TODO */611}612613static void614dd_dump_clear_depth_stencil(struct dd_draw_state *dstate, FILE *f)615{616fprintf(f, "%s:\n", __func__+8);617/* TODO */618}619620static void621dd_dump_driver_state(struct dd_context *dctx, FILE *f, unsigned flags)622{623if (dctx->pipe->dump_debug_state) {624fprintf(f,"\n\n**************************************************"625"***************************\n");626fprintf(f, "Driver-specific state:\n\n");627dctx->pipe->dump_debug_state(dctx->pipe, f, flags);628}629}630631static void632dd_dump_call(FILE *f, struct dd_draw_state *state, struct dd_call *call)633{634switch (call->type) {635case CALL_FLUSH:636dd_dump_flush(state, &call->info.flush, f);637break;638case CALL_DRAW_VBO:639dd_dump_draw_vbo(state, &call->info.draw_vbo.info,640call->info.draw_vbo.drawid_offset,641&call->info.draw_vbo.indirect,642&call->info.draw_vbo.draw, f);643break;644case CALL_LAUNCH_GRID:645dd_dump_launch_grid(state, &call->info.launch_grid, f);646break;647case CALL_RESOURCE_COPY_REGION:648dd_dump_resource_copy_region(state,649&call->info.resource_copy_region, f);650break;651case CALL_BLIT:652dd_dump_blit(state, &call->info.blit, f);653break;654case CALL_FLUSH_RESOURCE:655dd_dump_flush_resource(state, call->info.flush_resource, f);656break;657case CALL_CLEAR:658dd_dump_clear(state, &call->info.clear, f);659break;660case CALL_CLEAR_BUFFER:661dd_dump_clear_buffer(state, &call->info.clear_buffer, f);662break;663case CALL_CLEAR_TEXTURE:664dd_dump_clear_texture(state, f);665break;666case CALL_CLEAR_RENDER_TARGET:667dd_dump_clear_render_target(state, f);668break;669case CALL_CLEAR_DEPTH_STENCIL:670dd_dump_clear_depth_stencil(state, f);671break;672case CALL_GENERATE_MIPMAP:673dd_dump_generate_mipmap(state, f);674break;675case CALL_GET_QUERY_RESULT_RESOURCE:676dd_dump_get_query_result_resource(&call->info.get_query_result_resource, f);677break;678case CALL_TRANSFER_MAP:679dd_dump_transfer_map(&call->info.transfer_map, f);680break;681case CALL_TRANSFER_FLUSH_REGION:682dd_dump_transfer_flush_region(&call->info.transfer_flush_region, f);683break;684case CALL_TRANSFER_UNMAP:685dd_dump_transfer_unmap(&call->info.transfer_unmap, f);686break;687case CALL_BUFFER_SUBDATA:688dd_dump_buffer_subdata(&call->info.buffer_subdata, f);689break;690case CALL_TEXTURE_SUBDATA:691dd_dump_texture_subdata(&call->info.texture_subdata, f);692break;693}694}695696static void697dd_kill_process(void)698{699#ifdef PIPE_OS_UNIX700sync();701#endif702fprintf(stderr, "dd: Aborting the process...\n");703fflush(stdout);704fflush(stderr);705exit(1);706}707708static void709dd_unreference_copy_of_call(struct dd_call *dst)710{711switch (dst->type) {712case CALL_FLUSH:713break;714case CALL_DRAW_VBO:715pipe_so_target_reference(&dst->info.draw_vbo.indirect.count_from_stream_output, NULL);716pipe_resource_reference(&dst->info.draw_vbo.indirect.buffer, NULL);717pipe_resource_reference(&dst->info.draw_vbo.indirect.indirect_draw_count, NULL);718if (dst->info.draw_vbo.info.index_size &&719!dst->info.draw_vbo.info.has_user_indices)720pipe_resource_reference(&dst->info.draw_vbo.info.index.resource, NULL);721else722dst->info.draw_vbo.info.index.user = NULL;723break;724case CALL_LAUNCH_GRID:725pipe_resource_reference(&dst->info.launch_grid.indirect, NULL);726break;727case CALL_RESOURCE_COPY_REGION:728pipe_resource_reference(&dst->info.resource_copy_region.dst, NULL);729pipe_resource_reference(&dst->info.resource_copy_region.src, NULL);730break;731case CALL_BLIT:732pipe_resource_reference(&dst->info.blit.dst.resource, NULL);733pipe_resource_reference(&dst->info.blit.src.resource, NULL);734break;735case CALL_FLUSH_RESOURCE:736pipe_resource_reference(&dst->info.flush_resource, NULL);737break;738case CALL_CLEAR:739break;740case CALL_CLEAR_BUFFER:741pipe_resource_reference(&dst->info.clear_buffer.res, NULL);742break;743case CALL_CLEAR_TEXTURE:744break;745case CALL_CLEAR_RENDER_TARGET:746break;747case CALL_CLEAR_DEPTH_STENCIL:748break;749case CALL_GENERATE_MIPMAP:750pipe_resource_reference(&dst->info.generate_mipmap.res, NULL);751break;752case CALL_GET_QUERY_RESULT_RESOURCE:753pipe_resource_reference(&dst->info.get_query_result_resource.resource, NULL);754break;755case CALL_TRANSFER_MAP:756pipe_resource_reference(&dst->info.transfer_map.transfer.resource, NULL);757break;758case CALL_TRANSFER_FLUSH_REGION:759pipe_resource_reference(&dst->info.transfer_flush_region.transfer.resource, NULL);760break;761case CALL_TRANSFER_UNMAP:762pipe_resource_reference(&dst->info.transfer_unmap.transfer.resource, NULL);763break;764case CALL_BUFFER_SUBDATA:765pipe_resource_reference(&dst->info.buffer_subdata.resource, NULL);766break;767case CALL_TEXTURE_SUBDATA:768pipe_resource_reference(&dst->info.texture_subdata.resource, NULL);769break;770}771}772773static void774dd_init_copy_of_draw_state(struct dd_draw_state_copy *state)775{776unsigned i,j;777778/* Just clear pointers to gallium objects. Don't clear the whole structure,779* because it would kill performance with its size of 130 KB.780*/781memset(state->base.vertex_buffers, 0,782sizeof(state->base.vertex_buffers));783memset(state->base.so_targets, 0,784sizeof(state->base.so_targets));785memset(state->base.constant_buffers, 0,786sizeof(state->base.constant_buffers));787memset(state->base.sampler_views, 0,788sizeof(state->base.sampler_views));789memset(state->base.shader_images, 0,790sizeof(state->base.shader_images));791memset(state->base.shader_buffers, 0,792sizeof(state->base.shader_buffers));793memset(&state->base.framebuffer_state, 0,794sizeof(state->base.framebuffer_state));795796memset(state->shaders, 0, sizeof(state->shaders));797798state->base.render_cond.query = &state->render_cond;799800for (i = 0; i < PIPE_SHADER_TYPES; i++) {801state->base.shaders[i] = &state->shaders[i];802for (j = 0; j < PIPE_MAX_SAMPLERS; j++)803state->base.sampler_states[i][j] = &state->sampler_states[i][j];804}805806state->base.velems = &state->velems;807state->base.rs = &state->rs;808state->base.dsa = &state->dsa;809state->base.blend = &state->blend;810}811812static void813dd_unreference_copy_of_draw_state(struct dd_draw_state_copy *state)814{815struct dd_draw_state *dst = &state->base;816unsigned i,j;817818for (i = 0; i < ARRAY_SIZE(dst->vertex_buffers); i++)819pipe_vertex_buffer_unreference(&dst->vertex_buffers[i]);820for (i = 0; i < ARRAY_SIZE(dst->so_targets); i++)821pipe_so_target_reference(&dst->so_targets[i], NULL);822823for (i = 0; i < PIPE_SHADER_TYPES; i++) {824if (dst->shaders[i])825tgsi_free_tokens(dst->shaders[i]->state.shader.tokens);826827for (j = 0; j < PIPE_MAX_CONSTANT_BUFFERS; j++)828pipe_resource_reference(&dst->constant_buffers[i][j].buffer, NULL);829for (j = 0; j < PIPE_MAX_SAMPLERS; j++)830pipe_sampler_view_reference(&dst->sampler_views[i][j], NULL);831for (j = 0; j < PIPE_MAX_SHADER_IMAGES; j++)832pipe_resource_reference(&dst->shader_images[i][j].resource, NULL);833for (j = 0; j < PIPE_MAX_SHADER_BUFFERS; j++)834pipe_resource_reference(&dst->shader_buffers[i][j].buffer, NULL);835}836837util_unreference_framebuffer_state(&dst->framebuffer_state);838}839840static void841dd_copy_draw_state(struct dd_draw_state *dst, struct dd_draw_state *src)842{843unsigned i,j;844845if (src->render_cond.query) {846*dst->render_cond.query = *src->render_cond.query;847dst->render_cond.condition = src->render_cond.condition;848dst->render_cond.mode = src->render_cond.mode;849} else {850dst->render_cond.query = NULL;851}852853for (i = 0; i < ARRAY_SIZE(src->vertex_buffers); i++) {854pipe_vertex_buffer_reference(&dst->vertex_buffers[i],855&src->vertex_buffers[i]);856}857858dst->num_so_targets = src->num_so_targets;859for (i = 0; i < src->num_so_targets; i++)860pipe_so_target_reference(&dst->so_targets[i], src->so_targets[i]);861memcpy(dst->so_offsets, src->so_offsets, sizeof(src->so_offsets));862863for (i = 0; i < PIPE_SHADER_TYPES; i++) {864if (!src->shaders[i]) {865dst->shaders[i] = NULL;866continue;867}868869if (src->shaders[i]) {870dst->shaders[i]->state.shader = src->shaders[i]->state.shader;871if (src->shaders[i]->state.shader.tokens) {872dst->shaders[i]->state.shader.tokens =873tgsi_dup_tokens(src->shaders[i]->state.shader.tokens);874} else {875dst->shaders[i]->state.shader.ir.nir = NULL;876}877} else {878dst->shaders[i] = NULL;879}880881for (j = 0; j < PIPE_MAX_CONSTANT_BUFFERS; j++) {882pipe_resource_reference(&dst->constant_buffers[i][j].buffer,883src->constant_buffers[i][j].buffer);884memcpy(&dst->constant_buffers[i][j], &src->constant_buffers[i][j],885sizeof(src->constant_buffers[i][j]));886}887888for (j = 0; j < PIPE_MAX_SAMPLERS; j++) {889pipe_sampler_view_reference(&dst->sampler_views[i][j],890src->sampler_views[i][j]);891if (src->sampler_states[i][j])892dst->sampler_states[i][j]->state.sampler =893src->sampler_states[i][j]->state.sampler;894else895dst->sampler_states[i][j] = NULL;896}897898for (j = 0; j < PIPE_MAX_SHADER_IMAGES; j++) {899pipe_resource_reference(&dst->shader_images[i][j].resource,900src->shader_images[i][j].resource);901memcpy(&dst->shader_images[i][j], &src->shader_images[i][j],902sizeof(src->shader_images[i][j]));903}904905for (j = 0; j < PIPE_MAX_SHADER_BUFFERS; j++) {906pipe_resource_reference(&dst->shader_buffers[i][j].buffer,907src->shader_buffers[i][j].buffer);908memcpy(&dst->shader_buffers[i][j], &src->shader_buffers[i][j],909sizeof(src->shader_buffers[i][j]));910}911}912913if (src->velems)914dst->velems->state.velems = src->velems->state.velems;915else916dst->velems = NULL;917918if (src->rs)919dst->rs->state.rs = src->rs->state.rs;920else921dst->rs = NULL;922923if (src->dsa)924dst->dsa->state.dsa = src->dsa->state.dsa;925else926dst->dsa = NULL;927928if (src->blend)929dst->blend->state.blend = src->blend->state.blend;930else931dst->blend = NULL;932933dst->blend_color = src->blend_color;934dst->stencil_ref = src->stencil_ref;935dst->sample_mask = src->sample_mask;936dst->min_samples = src->min_samples;937dst->clip_state = src->clip_state;938util_copy_framebuffer_state(&dst->framebuffer_state, &src->framebuffer_state);939memcpy(dst->scissors, src->scissors, sizeof(src->scissors));940memcpy(dst->viewports, src->viewports, sizeof(src->viewports));941memcpy(dst->tess_default_levels, src->tess_default_levels,942sizeof(src->tess_default_levels));943dst->apitrace_call_number = src->apitrace_call_number;944}945946static void947dd_free_record(struct pipe_screen *screen, struct dd_draw_record *record)948{949u_log_page_destroy(record->log_page);950dd_unreference_copy_of_call(&record->call);951dd_unreference_copy_of_draw_state(&record->draw_state);952screen->fence_reference(screen, &record->prev_bottom_of_pipe, NULL);953screen->fence_reference(screen, &record->top_of_pipe, NULL);954screen->fence_reference(screen, &record->bottom_of_pipe, NULL);955util_queue_fence_destroy(&record->driver_finished);956FREE(record);957}958959static void960dd_write_record(FILE *f, struct dd_draw_record *record)961{962PRINT_NAMED(ptr, "pipe", record->dctx->pipe);963PRINT_NAMED(ns, "time before (API call)", record->time_before);964PRINT_NAMED(ns, "time after (driver done)", record->time_after);965fprintf(f, "\n");966967dd_dump_call(f, &record->draw_state.base, &record->call);968969if (record->log_page) {970fprintf(f,"\n\n**************************************************"971"***************************\n");972fprintf(f, "Context Log:\n\n");973u_log_page_print(record->log_page, f);974}975}976977static void978dd_maybe_dump_record(struct dd_screen *dscreen, struct dd_draw_record *record)979{980if (dscreen->dump_mode == DD_DUMP_ONLY_HANGS ||981(dscreen->dump_mode == DD_DUMP_APITRACE_CALL &&982dscreen->apitrace_dump_call != record->draw_state.base.apitrace_call_number))983return;984985char name[512];986dd_get_debug_filename_and_mkdir(name, sizeof(name), dscreen->verbose);987FILE *f = fopen(name, "w");988if (!f) {989fprintf(stderr, "dd: failed to open %s\n", name);990return;991}992993dd_write_header(f, dscreen->screen, record->draw_state.base.apitrace_call_number);994dd_write_record(f, record);995996fclose(f);997}998999static const char *1000dd_fence_state(struct pipe_screen *screen, struct pipe_fence_handle *fence,1001bool *not_reached)1002{1003if (!fence)1004return "---";10051006bool ok = screen->fence_finish(screen, NULL, fence, 0);10071008if (not_reached && !ok)1009*not_reached = true;10101011return ok ? "YES" : "NO ";1012}10131014static void1015dd_report_hang(struct dd_context *dctx)1016{1017struct dd_screen *dscreen = dd_screen(dctx->base.screen);1018struct pipe_screen *screen = dscreen->screen;1019bool encountered_hang = false;1020bool stop_output = false;1021unsigned num_later = 0;10221023fprintf(stderr, "GPU hang detected, collecting information...\n\n");10241025fprintf(stderr, "Draw # driver prev BOP TOP BOP dump file\n"1026"-------------------------------------------------------------\n");10271028list_for_each_entry(struct dd_draw_record, record, &dctx->records, list) {1029if (!encountered_hang &&1030screen->fence_finish(screen, NULL, record->bottom_of_pipe, 0)) {1031dd_maybe_dump_record(dscreen, record);1032continue;1033}10341035if (stop_output) {1036dd_maybe_dump_record(dscreen, record);1037num_later++;1038continue;1039}10401041bool driver = util_queue_fence_is_signalled(&record->driver_finished);1042bool top_not_reached = false;1043const char *prev_bop = dd_fence_state(screen, record->prev_bottom_of_pipe, NULL);1044const char *top = dd_fence_state(screen, record->top_of_pipe, &top_not_reached);1045const char *bop = dd_fence_state(screen, record->bottom_of_pipe, NULL);10461047fprintf(stderr, "%-9u %s %s %s %s ",1048record->draw_call, driver ? "YES" : "NO ", prev_bop, top, bop);10491050char name[512];1051dd_get_debug_filename_and_mkdir(name, sizeof(name), false);10521053FILE *f = fopen(name, "w");1054if (!f) {1055fprintf(stderr, "fopen failed\n");1056} else {1057fprintf(stderr, "%s\n", name);10581059dd_write_header(f, dscreen->screen, record->draw_state.base.apitrace_call_number);1060dd_write_record(f, record);10611062fclose(f);1063}10641065if (top_not_reached)1066stop_output = true;1067encountered_hang = true;1068}10691070if (num_later)1071fprintf(stderr, "... and %u additional draws.\n", num_later);10721073char name[512];1074dd_get_debug_filename_and_mkdir(name, sizeof(name), false);1075FILE *f = fopen(name, "w");1076if (!f) {1077fprintf(stderr, "fopen failed\n");1078} else {1079dd_write_header(f, dscreen->screen, 0);1080dd_dump_driver_state(dctx, f, PIPE_DUMP_DEVICE_STATUS_REGISTERS);1081dd_dump_dmesg(f);1082fclose(f);1083}10841085fprintf(stderr, "\nDone.\n");1086dd_kill_process();1087}10881089int1090dd_thread_main(void *input)1091{1092struct dd_context *dctx = (struct dd_context *)input;1093struct dd_screen *dscreen = dd_screen(dctx->base.screen);1094struct pipe_screen *screen = dscreen->screen;10951096const char *process_name = util_get_process_name();1097if (process_name) {1098char threadname[16];1099snprintf(threadname, sizeof(threadname), "%.*s:ddbg",1100(int)MIN2(strlen(process_name), sizeof(threadname) - 6),1101process_name);1102u_thread_setname(threadname);1103}11041105mtx_lock(&dctx->mutex);11061107for (;;) {1108struct list_head records;1109list_replace(&dctx->records, &records);1110list_inithead(&dctx->records);1111dctx->num_records = 0;11121113if (dctx->api_stalled)1114cnd_signal(&dctx->cond);11151116if (list_is_empty(&records)) {1117if (dctx->kill_thread)1118break;11191120cnd_wait(&dctx->cond, &dctx->mutex);1121continue;1122}11231124mtx_unlock(&dctx->mutex);11251126/* Wait for the youngest draw. This means hangs can take a bit longer1127* to detect, but it's more efficient this way. */1128struct dd_draw_record *youngest =1129list_last_entry(&records, struct dd_draw_record, list);11301131if (dscreen->timeout_ms > 0) {1132uint64_t abs_timeout = os_time_get_absolute_timeout(1133(uint64_t)dscreen->timeout_ms * 1000*1000);11341135if (!util_queue_fence_wait_timeout(&youngest->driver_finished, abs_timeout) ||1136!screen->fence_finish(screen, NULL, youngest->bottom_of_pipe,1137(uint64_t)dscreen->timeout_ms * 1000*1000)) {1138mtx_lock(&dctx->mutex);1139list_splice(&records, &dctx->records);1140dd_report_hang(dctx);1141/* we won't actually get here */1142mtx_unlock(&dctx->mutex);1143}1144} else {1145util_queue_fence_wait(&youngest->driver_finished);1146}11471148list_for_each_entry_safe(struct dd_draw_record, record, &records, list) {1149dd_maybe_dump_record(dscreen, record);1150list_del(&record->list);1151dd_free_record(screen, record);1152}11531154mtx_lock(&dctx->mutex);1155}1156mtx_unlock(&dctx->mutex);1157return 0;1158}11591160static struct dd_draw_record *1161dd_create_record(struct dd_context *dctx)1162{1163struct dd_draw_record *record;11641165record = MALLOC_STRUCT(dd_draw_record);1166if (!record)1167return NULL;11681169record->dctx = dctx;1170record->draw_call = dctx->num_draw_calls;11711172record->prev_bottom_of_pipe = NULL;1173record->top_of_pipe = NULL;1174record->bottom_of_pipe = NULL;1175record->log_page = NULL;1176util_queue_fence_init(&record->driver_finished);1177util_queue_fence_reset(&record->driver_finished);11781179dd_init_copy_of_draw_state(&record->draw_state);1180dd_copy_draw_state(&record->draw_state.base, &dctx->draw_state);11811182return record;1183}11841185static void1186dd_add_record(struct dd_context *dctx, struct dd_draw_record *record)1187{1188mtx_lock(&dctx->mutex);1189if (unlikely(dctx->num_records > 10000)) {1190dctx->api_stalled = true;1191/* Since this is only a heuristic to prevent the API thread from getting1192* too far ahead, we don't need a loop here. */1193cnd_wait(&dctx->cond, &dctx->mutex);1194dctx->api_stalled = false;1195}11961197if (list_is_empty(&dctx->records))1198cnd_signal(&dctx->cond);11991200list_addtail(&record->list, &dctx->records);1201dctx->num_records++;1202mtx_unlock(&dctx->mutex);1203}12041205static void1206dd_before_draw(struct dd_context *dctx, struct dd_draw_record *record)1207{1208struct dd_screen *dscreen = dd_screen(dctx->base.screen);1209struct pipe_context *pipe = dctx->pipe;1210struct pipe_screen *screen = dscreen->screen;12111212record->time_before = os_time_get_nano();12131214if (dscreen->timeout_ms > 0) {1215if (dscreen->flush_always && dctx->num_draw_calls >= dscreen->skip_count) {1216pipe->flush(pipe, &record->prev_bottom_of_pipe, 0);1217screen->fence_reference(screen, &record->top_of_pipe, record->prev_bottom_of_pipe);1218} else {1219pipe->flush(pipe, &record->prev_bottom_of_pipe,1220PIPE_FLUSH_DEFERRED | PIPE_FLUSH_BOTTOM_OF_PIPE);1221pipe->flush(pipe, &record->top_of_pipe,1222PIPE_FLUSH_DEFERRED | PIPE_FLUSH_TOP_OF_PIPE);1223}1224} else if (dscreen->flush_always && dctx->num_draw_calls >= dscreen->skip_count) {1225pipe->flush(pipe, NULL, 0);1226}12271228dd_add_record(dctx, record);1229}12301231static void1232dd_after_draw_async(void *data)1233{1234struct dd_draw_record *record = (struct dd_draw_record *)data;1235struct dd_context *dctx = record->dctx;1236struct dd_screen *dscreen = dd_screen(dctx->base.screen);12371238record->log_page = u_log_new_page(&dctx->log);1239record->time_after = os_time_get_nano();12401241util_queue_fence_signal(&record->driver_finished);12421243if (dscreen->dump_mode == DD_DUMP_APITRACE_CALL &&1244dscreen->apitrace_dump_call > dctx->draw_state.apitrace_call_number) {1245dd_thread_join(dctx);1246/* No need to continue. */1247exit(0);1248}1249}12501251static void1252dd_after_draw(struct dd_context *dctx, struct dd_draw_record *record)1253{1254struct dd_screen *dscreen = dd_screen(dctx->base.screen);1255struct pipe_context *pipe = dctx->pipe;12561257if (dscreen->timeout_ms > 0) {1258unsigned flush_flags;1259if (dscreen->flush_always && dctx->num_draw_calls >= dscreen->skip_count)1260flush_flags = 0;1261else1262flush_flags = PIPE_FLUSH_DEFERRED | PIPE_FLUSH_BOTTOM_OF_PIPE;1263pipe->flush(pipe, &record->bottom_of_pipe, flush_flags);1264}12651266if (pipe->callback) {1267pipe->callback(pipe, dd_after_draw_async, record, true);1268} else {1269dd_after_draw_async(record);1270}12711272++dctx->num_draw_calls;1273if (dscreen->skip_count && dctx->num_draw_calls % 10000 == 0)1274fprintf(stderr, "Gallium debugger reached %u draw calls.\n",1275dctx->num_draw_calls);1276}12771278static void1279dd_context_flush(struct pipe_context *_pipe,1280struct pipe_fence_handle **fence, unsigned flags)1281{1282struct dd_context *dctx = dd_context(_pipe);1283struct pipe_context *pipe = dctx->pipe;1284struct pipe_screen *screen = pipe->screen;1285struct dd_draw_record *record = dd_create_record(dctx);12861287record->call.type = CALL_FLUSH;1288record->call.info.flush.flags = flags;12891290record->time_before = os_time_get_nano();12911292dd_add_record(dctx, record);12931294pipe->flush(pipe, &record->bottom_of_pipe, flags);1295if (fence)1296screen->fence_reference(screen, fence, record->bottom_of_pipe);12971298if (pipe->callback) {1299pipe->callback(pipe, dd_after_draw_async, record, true);1300} else {1301dd_after_draw_async(record);1302}1303}13041305static void1306dd_context_draw_vbo(struct pipe_context *_pipe,1307const struct pipe_draw_info *info,1308unsigned drawid_offset,1309const struct pipe_draw_indirect_info *indirect,1310const struct pipe_draw_start_count_bias *draws,1311unsigned num_draws)1312{1313struct dd_context *dctx = dd_context(_pipe);1314struct pipe_context *pipe = dctx->pipe;1315struct dd_draw_record *record = dd_create_record(dctx);13161317record->call.type = CALL_DRAW_VBO;1318record->call.info.draw_vbo.info = *info;1319record->call.info.draw_vbo.drawid_offset = drawid_offset;1320record->call.info.draw_vbo.draw = draws[0];1321if (info->index_size && !info->has_user_indices) {1322record->call.info.draw_vbo.info.index.resource = NULL;1323pipe_resource_reference(&record->call.info.draw_vbo.info.index.resource,1324info->index.resource);1325}13261327if (indirect) {1328record->call.info.draw_vbo.indirect = *indirect;1329record->call.info.draw_vbo.indirect.buffer = NULL;1330pipe_resource_reference(&record->call.info.draw_vbo.indirect.buffer,1331indirect->buffer);1332record->call.info.draw_vbo.indirect.indirect_draw_count = NULL;1333pipe_resource_reference(&record->call.info.draw_vbo.indirect.indirect_draw_count,1334indirect->indirect_draw_count);1335record->call.info.draw_vbo.indirect.count_from_stream_output = NULL;1336pipe_so_target_reference(&record->call.info.draw_vbo.indirect.count_from_stream_output,1337indirect->count_from_stream_output);1338} else {1339memset(&record->call.info.draw_vbo.indirect, 0, sizeof(*indirect));1340}13411342dd_before_draw(dctx, record);1343pipe->draw_vbo(pipe, info, drawid_offset, indirect, draws, num_draws);1344dd_after_draw(dctx, record);1345}13461347static void1348dd_context_launch_grid(struct pipe_context *_pipe,1349const struct pipe_grid_info *info)1350{1351struct dd_context *dctx = dd_context(_pipe);1352struct pipe_context *pipe = dctx->pipe;1353struct dd_draw_record *record = dd_create_record(dctx);13541355record->call.type = CALL_LAUNCH_GRID;1356record->call.info.launch_grid = *info;1357record->call.info.launch_grid.indirect = NULL;1358pipe_resource_reference(&record->call.info.launch_grid.indirect, info->indirect);13591360dd_before_draw(dctx, record);1361pipe->launch_grid(pipe, info);1362dd_after_draw(dctx, record);1363}13641365static void1366dd_context_resource_copy_region(struct pipe_context *_pipe,1367struct pipe_resource *dst, unsigned dst_level,1368unsigned dstx, unsigned dsty, unsigned dstz,1369struct pipe_resource *src, unsigned src_level,1370const struct pipe_box *src_box)1371{1372struct dd_context *dctx = dd_context(_pipe);1373struct pipe_context *pipe = dctx->pipe;1374struct dd_draw_record *record = dd_create_record(dctx);13751376record->call.type = CALL_RESOURCE_COPY_REGION;1377record->call.info.resource_copy_region.dst = NULL;1378pipe_resource_reference(&record->call.info.resource_copy_region.dst, dst);1379record->call.info.resource_copy_region.dst_level = dst_level;1380record->call.info.resource_copy_region.dstx = dstx;1381record->call.info.resource_copy_region.dsty = dsty;1382record->call.info.resource_copy_region.dstz = dstz;1383record->call.info.resource_copy_region.src = NULL;1384pipe_resource_reference(&record->call.info.resource_copy_region.src, src);1385record->call.info.resource_copy_region.src_level = src_level;1386record->call.info.resource_copy_region.src_box = *src_box;13871388dd_before_draw(dctx, record);1389pipe->resource_copy_region(pipe,1390dst, dst_level, dstx, dsty, dstz,1391src, src_level, src_box);1392dd_after_draw(dctx, record);1393}13941395static void1396dd_context_blit(struct pipe_context *_pipe, const struct pipe_blit_info *info)1397{1398struct dd_context *dctx = dd_context(_pipe);1399struct pipe_context *pipe = dctx->pipe;1400struct dd_draw_record *record = dd_create_record(dctx);14011402record->call.type = CALL_BLIT;1403record->call.info.blit = *info;1404record->call.info.blit.dst.resource = NULL;1405pipe_resource_reference(&record->call.info.blit.dst.resource, info->dst.resource);1406record->call.info.blit.src.resource = NULL;1407pipe_resource_reference(&record->call.info.blit.src.resource, info->src.resource);14081409dd_before_draw(dctx, record);1410pipe->blit(pipe, info);1411dd_after_draw(dctx, record);1412}14131414static bool1415dd_context_generate_mipmap(struct pipe_context *_pipe,1416struct pipe_resource *res,1417enum pipe_format format,1418unsigned base_level,1419unsigned last_level,1420unsigned first_layer,1421unsigned last_layer)1422{1423struct dd_context *dctx = dd_context(_pipe);1424struct pipe_context *pipe = dctx->pipe;1425struct dd_draw_record *record = dd_create_record(dctx);1426bool result;14271428record->call.type = CALL_GENERATE_MIPMAP;1429record->call.info.generate_mipmap.res = NULL;1430pipe_resource_reference(&record->call.info.generate_mipmap.res, res);1431record->call.info.generate_mipmap.format = format;1432record->call.info.generate_mipmap.base_level = base_level;1433record->call.info.generate_mipmap.last_level = last_level;1434record->call.info.generate_mipmap.first_layer = first_layer;1435record->call.info.generate_mipmap.last_layer = last_layer;14361437dd_before_draw(dctx, record);1438result = pipe->generate_mipmap(pipe, res, format, base_level, last_level,1439first_layer, last_layer);1440dd_after_draw(dctx, record);1441return result;1442}14431444static void1445dd_context_get_query_result_resource(struct pipe_context *_pipe,1446struct pipe_query *query,1447bool wait,1448enum pipe_query_value_type result_type,1449int index,1450struct pipe_resource *resource,1451unsigned offset)1452{1453struct dd_context *dctx = dd_context(_pipe);1454struct dd_query *dquery = dd_query(query);1455struct pipe_context *pipe = dctx->pipe;1456struct dd_draw_record *record = dd_create_record(dctx);14571458record->call.type = CALL_GET_QUERY_RESULT_RESOURCE;1459record->call.info.get_query_result_resource.query = query;1460record->call.info.get_query_result_resource.wait = wait;1461record->call.info.get_query_result_resource.result_type = result_type;1462record->call.info.get_query_result_resource.index = index;1463record->call.info.get_query_result_resource.resource = NULL;1464pipe_resource_reference(&record->call.info.get_query_result_resource.resource,1465resource);1466record->call.info.get_query_result_resource.offset = offset;14671468/* The query may be deleted by the time we need to print it. */1469record->call.info.get_query_result_resource.query_type = dquery->type;14701471dd_before_draw(dctx, record);1472pipe->get_query_result_resource(pipe, dquery->query, wait,1473result_type, index, resource, offset);1474dd_after_draw(dctx, record);1475}14761477static void1478dd_context_flush_resource(struct pipe_context *_pipe,1479struct pipe_resource *resource)1480{1481struct dd_context *dctx = dd_context(_pipe);1482struct pipe_context *pipe = dctx->pipe;1483struct dd_draw_record *record = dd_create_record(dctx);14841485record->call.type = CALL_FLUSH_RESOURCE;1486record->call.info.flush_resource = NULL;1487pipe_resource_reference(&record->call.info.flush_resource, resource);14881489dd_before_draw(dctx, record);1490pipe->flush_resource(pipe, resource);1491dd_after_draw(dctx, record);1492}14931494static void1495dd_context_clear(struct pipe_context *_pipe, unsigned buffers, const struct pipe_scissor_state *scissor_state,1496const union pipe_color_union *color, double depth,1497unsigned stencil)1498{1499struct dd_context *dctx = dd_context(_pipe);1500struct pipe_context *pipe = dctx->pipe;1501struct dd_draw_record *record = dd_create_record(dctx);15021503record->call.type = CALL_CLEAR;1504record->call.info.clear.buffers = buffers;1505if (scissor_state)1506record->call.info.clear.scissor_state = *scissor_state;1507record->call.info.clear.color = *color;1508record->call.info.clear.depth = depth;1509record->call.info.clear.stencil = stencil;15101511dd_before_draw(dctx, record);1512pipe->clear(pipe, buffers, scissor_state, color, depth, stencil);1513dd_after_draw(dctx, record);1514}15151516static void1517dd_context_clear_render_target(struct pipe_context *_pipe,1518struct pipe_surface *dst,1519const union pipe_color_union *color,1520unsigned dstx, unsigned dsty,1521unsigned width, unsigned height,1522bool render_condition_enabled)1523{1524struct dd_context *dctx = dd_context(_pipe);1525struct pipe_context *pipe = dctx->pipe;1526struct dd_draw_record *record = dd_create_record(dctx);15271528record->call.type = CALL_CLEAR_RENDER_TARGET;15291530dd_before_draw(dctx, record);1531pipe->clear_render_target(pipe, dst, color, dstx, dsty, width, height,1532render_condition_enabled);1533dd_after_draw(dctx, record);1534}15351536static void1537dd_context_clear_depth_stencil(struct pipe_context *_pipe,1538struct pipe_surface *dst, unsigned clear_flags,1539double depth, unsigned stencil, unsigned dstx,1540unsigned dsty, unsigned width, unsigned height,1541bool render_condition_enabled)1542{1543struct dd_context *dctx = dd_context(_pipe);1544struct pipe_context *pipe = dctx->pipe;1545struct dd_draw_record *record = dd_create_record(dctx);15461547record->call.type = CALL_CLEAR_DEPTH_STENCIL;15481549dd_before_draw(dctx, record);1550pipe->clear_depth_stencil(pipe, dst, clear_flags, depth, stencil,1551dstx, dsty, width, height,1552render_condition_enabled);1553dd_after_draw(dctx, record);1554}15551556static void1557dd_context_clear_buffer(struct pipe_context *_pipe, struct pipe_resource *res,1558unsigned offset, unsigned size,1559const void *clear_value, int clear_value_size)1560{1561struct dd_context *dctx = dd_context(_pipe);1562struct pipe_context *pipe = dctx->pipe;1563struct dd_draw_record *record = dd_create_record(dctx);15641565record->call.type = CALL_CLEAR_BUFFER;1566record->call.info.clear_buffer.res = NULL;1567pipe_resource_reference(&record->call.info.clear_buffer.res, res);1568record->call.info.clear_buffer.offset = offset;1569record->call.info.clear_buffer.size = size;1570record->call.info.clear_buffer.clear_value = clear_value;1571record->call.info.clear_buffer.clear_value_size = clear_value_size;15721573dd_before_draw(dctx, record);1574pipe->clear_buffer(pipe, res, offset, size, clear_value, clear_value_size);1575dd_after_draw(dctx, record);1576}15771578static void1579dd_context_clear_texture(struct pipe_context *_pipe,1580struct pipe_resource *res,1581unsigned level,1582const struct pipe_box *box,1583const void *data)1584{1585struct dd_context *dctx = dd_context(_pipe);1586struct pipe_context *pipe = dctx->pipe;1587struct dd_draw_record *record = dd_create_record(dctx);15881589record->call.type = CALL_CLEAR_TEXTURE;15901591dd_before_draw(dctx, record);1592pipe->clear_texture(pipe, res, level, box, data);1593dd_after_draw(dctx, record);1594}15951596/********************************************************************1597* transfer1598*/15991600static void *1601dd_context_buffer_map(struct pipe_context *_pipe,1602struct pipe_resource *resource, unsigned level,1603unsigned usage, const struct pipe_box *box,1604struct pipe_transfer **transfer)1605{1606struct dd_context *dctx = dd_context(_pipe);1607struct pipe_context *pipe = dctx->pipe;1608struct dd_draw_record *record =1609dd_screen(dctx->base.screen)->transfers ? dd_create_record(dctx) : NULL;16101611if (record) {1612record->call.type = CALL_TRANSFER_MAP;16131614dd_before_draw(dctx, record);1615}1616void *ptr = pipe->buffer_map(pipe, resource, level, usage, box, transfer);1617if (record) {1618record->call.info.transfer_map.transfer_ptr = *transfer;1619record->call.info.transfer_map.ptr = ptr;1620if (*transfer) {1621record->call.info.transfer_map.transfer = **transfer;1622record->call.info.transfer_map.transfer.resource = NULL;1623pipe_resource_reference(&record->call.info.transfer_map.transfer.resource,1624(*transfer)->resource);1625} else {1626memset(&record->call.info.transfer_map.transfer, 0, sizeof(struct pipe_transfer));1627}16281629dd_after_draw(dctx, record);1630}1631return ptr;1632}16331634static void *1635dd_context_texture_map(struct pipe_context *_pipe,1636struct pipe_resource *resource, unsigned level,1637unsigned usage, const struct pipe_box *box,1638struct pipe_transfer **transfer)1639{1640struct dd_context *dctx = dd_context(_pipe);1641struct pipe_context *pipe = dctx->pipe;1642struct dd_draw_record *record =1643dd_screen(dctx->base.screen)->transfers ? dd_create_record(dctx) : NULL;16441645if (record) {1646record->call.type = CALL_TRANSFER_MAP;16471648dd_before_draw(dctx, record);1649}1650void *ptr = pipe->texture_map(pipe, resource, level, usage, box, transfer);1651if (record) {1652record->call.info.transfer_map.transfer_ptr = *transfer;1653record->call.info.transfer_map.ptr = ptr;1654if (*transfer) {1655record->call.info.transfer_map.transfer = **transfer;1656record->call.info.transfer_map.transfer.resource = NULL;1657pipe_resource_reference(&record->call.info.transfer_map.transfer.resource,1658(*transfer)->resource);1659} else {1660memset(&record->call.info.transfer_map.transfer, 0, sizeof(struct pipe_transfer));1661}16621663dd_after_draw(dctx, record);1664}1665return ptr;1666}16671668static void1669dd_context_transfer_flush_region(struct pipe_context *_pipe,1670struct pipe_transfer *transfer,1671const struct pipe_box *box)1672{1673struct dd_context *dctx = dd_context(_pipe);1674struct pipe_context *pipe = dctx->pipe;1675struct dd_draw_record *record =1676dd_screen(dctx->base.screen)->transfers ? dd_create_record(dctx) : NULL;16771678if (record) {1679record->call.type = CALL_TRANSFER_FLUSH_REGION;1680record->call.info.transfer_flush_region.transfer_ptr = transfer;1681record->call.info.transfer_flush_region.box = *box;1682record->call.info.transfer_flush_region.transfer = *transfer;1683record->call.info.transfer_flush_region.transfer.resource = NULL;1684pipe_resource_reference(1685&record->call.info.transfer_flush_region.transfer.resource,1686transfer->resource);16871688dd_before_draw(dctx, record);1689}1690pipe->transfer_flush_region(pipe, transfer, box);1691if (record)1692dd_after_draw(dctx, record);1693}16941695static void1696dd_context_buffer_unmap(struct pipe_context *_pipe,1697struct pipe_transfer *transfer)1698{1699struct dd_context *dctx = dd_context(_pipe);1700struct pipe_context *pipe = dctx->pipe;1701struct dd_draw_record *record =1702dd_screen(dctx->base.screen)->transfers ? dd_create_record(dctx) : NULL;17031704if (record) {1705record->call.type = CALL_TRANSFER_UNMAP;1706record->call.info.transfer_unmap.transfer_ptr = transfer;1707record->call.info.transfer_unmap.transfer = *transfer;1708record->call.info.transfer_unmap.transfer.resource = NULL;1709pipe_resource_reference(1710&record->call.info.transfer_unmap.transfer.resource,1711transfer->resource);17121713dd_before_draw(dctx, record);1714}1715pipe->buffer_unmap(pipe, transfer);1716if (record)1717dd_after_draw(dctx, record);1718}17191720static void1721dd_context_texture_unmap(struct pipe_context *_pipe,1722struct pipe_transfer *transfer)1723{1724struct dd_context *dctx = dd_context(_pipe);1725struct pipe_context *pipe = dctx->pipe;1726struct dd_draw_record *record =1727dd_screen(dctx->base.screen)->transfers ? dd_create_record(dctx) : NULL;17281729if (record) {1730record->call.type = CALL_TRANSFER_UNMAP;1731record->call.info.transfer_unmap.transfer_ptr = transfer;1732record->call.info.transfer_unmap.transfer = *transfer;1733record->call.info.transfer_unmap.transfer.resource = NULL;1734pipe_resource_reference(1735&record->call.info.transfer_unmap.transfer.resource,1736transfer->resource);17371738dd_before_draw(dctx, record);1739}1740pipe->texture_unmap(pipe, transfer);1741if (record)1742dd_after_draw(dctx, record);1743}17441745static void1746dd_context_buffer_subdata(struct pipe_context *_pipe,1747struct pipe_resource *resource,1748unsigned usage, unsigned offset,1749unsigned size, const void *data)1750{1751struct dd_context *dctx = dd_context(_pipe);1752struct pipe_context *pipe = dctx->pipe;1753struct dd_draw_record *record =1754dd_screen(dctx->base.screen)->transfers ? dd_create_record(dctx) : NULL;17551756if (record) {1757record->call.type = CALL_BUFFER_SUBDATA;1758record->call.info.buffer_subdata.resource = NULL;1759pipe_resource_reference(&record->call.info.buffer_subdata.resource, resource);1760record->call.info.buffer_subdata.usage = usage;1761record->call.info.buffer_subdata.offset = offset;1762record->call.info.buffer_subdata.size = size;1763record->call.info.buffer_subdata.data = data;17641765dd_before_draw(dctx, record);1766}1767pipe->buffer_subdata(pipe, resource, usage, offset, size, data);1768if (record)1769dd_after_draw(dctx, record);1770}17711772static void1773dd_context_texture_subdata(struct pipe_context *_pipe,1774struct pipe_resource *resource,1775unsigned level, unsigned usage,1776const struct pipe_box *box,1777const void *data, unsigned stride,1778unsigned layer_stride)1779{1780struct dd_context *dctx = dd_context(_pipe);1781struct pipe_context *pipe = dctx->pipe;1782struct dd_draw_record *record =1783dd_screen(dctx->base.screen)->transfers ? dd_create_record(dctx) : NULL;17841785if (record) {1786record->call.type = CALL_TEXTURE_SUBDATA;1787record->call.info.texture_subdata.resource = NULL;1788pipe_resource_reference(&record->call.info.texture_subdata.resource, resource);1789record->call.info.texture_subdata.level = level;1790record->call.info.texture_subdata.usage = usage;1791record->call.info.texture_subdata.box = *box;1792record->call.info.texture_subdata.data = data;1793record->call.info.texture_subdata.stride = stride;1794record->call.info.texture_subdata.layer_stride = layer_stride;17951796dd_before_draw(dctx, record);1797}1798pipe->texture_subdata(pipe, resource, level, usage, box, data,1799stride, layer_stride);1800if (record)1801dd_after_draw(dctx, record);1802}18031804void1805dd_init_draw_functions(struct dd_context *dctx)1806{1807CTX_INIT(flush);1808CTX_INIT(draw_vbo);1809CTX_INIT(launch_grid);1810CTX_INIT(resource_copy_region);1811CTX_INIT(blit);1812CTX_INIT(clear);1813CTX_INIT(clear_render_target);1814CTX_INIT(clear_depth_stencil);1815CTX_INIT(clear_buffer);1816CTX_INIT(clear_texture);1817CTX_INIT(flush_resource);1818CTX_INIT(generate_mipmap);1819CTX_INIT(get_query_result_resource);1820CTX_INIT(buffer_map);1821CTX_INIT(texture_map);1822CTX_INIT(transfer_flush_region);1823CTX_INIT(buffer_unmap);1824CTX_INIT(texture_unmap);1825CTX_INIT(buffer_subdata);1826CTX_INIT(texture_subdata);1827}182818291830