mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-05 05:18:08 +02:00
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 <christian.koenig@amd.com>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
0fc21ecfc0
commit
525921ed51
11 changed files with 2135 additions and 0 deletions
|
|
@ -2317,6 +2317,7 @@ AC_CONFIG_FILES([Makefile
|
|||
src/gallium/auxiliary/Makefile
|
||||
src/gallium/auxiliary/pipe-loader/Makefile
|
||||
src/gallium/drivers/freedreno/Makefile
|
||||
src/gallium/drivers/ddebug/Makefile
|
||||
src/gallium/drivers/i915/Makefile
|
||||
src/gallium/drivers/ilo/Makefile
|
||||
src/gallium/drivers/llvmpipe/Makefile
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ SUBDIRS += auxiliary
|
|||
##
|
||||
|
||||
SUBDIRS += \
|
||||
drivers/ddebug \
|
||||
drivers/noop \
|
||||
drivers/trace \
|
||||
drivers/rbug
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@
|
|||
* one or more debug driver: rbug, trace.
|
||||
*/
|
||||
|
||||
#ifdef GALLIUM_DDEBUG
|
||||
#include "ddebug/dd_public.h"
|
||||
#endif
|
||||
|
||||
#ifdef GALLIUM_TRACE
|
||||
#include "trace/tr_public.h"
|
||||
#endif
|
||||
|
|
@ -30,6 +34,10 @@
|
|||
static inline struct pipe_screen *
|
||||
debug_screen_wrap(struct pipe_screen *screen)
|
||||
{
|
||||
#if defined(GALLIUM_DDEBUG)
|
||||
screen = ddebug_screen_create(screen);
|
||||
#endif
|
||||
|
||||
#if defined(GALLIUM_RBUG)
|
||||
screen = rbug_screen_create(screen);
|
||||
#endif
|
||||
|
|
|
|||
9
src/gallium/drivers/ddebug/Makefile.am
Normal file
9
src/gallium/drivers/ddebug/Makefile.am
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
include Makefile.sources
|
||||
include $(top_srcdir)/src/gallium/Automake.inc
|
||||
|
||||
AM_CFLAGS = \
|
||||
$(GALLIUM_DRIVER_CFLAGS)
|
||||
|
||||
noinst_LTLIBRARIES = libddebug.la
|
||||
|
||||
libddebug_la_SOURCES = $(C_SOURCES)
|
||||
6
src/gallium/drivers/ddebug/Makefile.sources
Normal file
6
src/gallium/drivers/ddebug/Makefile.sources
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
C_SOURCES := \
|
||||
dd_pipe.h \
|
||||
dd_public.h \
|
||||
dd_context.c \
|
||||
dd_draw.c \
|
||||
dd_screen.c
|
||||
771
src/gallium/drivers/ddebug/dd_context.c
Normal file
771
src/gallium/drivers/ddebug/dd_context.c
Normal file
|
|
@ -0,0 +1,771 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* 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 "tgsi/tgsi_parse.h"
|
||||
#include "util/u_memory.h"
|
||||
|
||||
|
||||
static void
|
||||
safe_memcpy(void *dst, const void *src, size_t size)
|
||||
{
|
||||
if (src)
|
||||
memcpy(dst, src, size);
|
||||
else
|
||||
memset(dst, 0, size);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* queries
|
||||
*/
|
||||
|
||||
static struct dd_query *
|
||||
dd_query(struct pipe_query *query)
|
||||
{
|
||||
return (struct dd_query *)query;
|
||||
}
|
||||
|
||||
static struct pipe_query *
|
||||
dd_query_unwrap(struct pipe_query *query)
|
||||
{
|
||||
if (query) {
|
||||
return dd_query(query)->query;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static struct pipe_query *
|
||||
dd_context_create_query(struct pipe_context *_pipe, unsigned query_type,
|
||||
unsigned index)
|
||||
{
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe;
|
||||
struct pipe_query *query;
|
||||
|
||||
query = pipe->create_query(pipe, query_type, index);
|
||||
|
||||
/* Wrap query object. */
|
||||
if (query) {
|
||||
struct dd_query *dd_query = CALLOC_STRUCT(dd_query);
|
||||
if (dd_query) {
|
||||
dd_query->type = query_type;
|
||||
dd_query->query = query;
|
||||
query = (struct pipe_query *)dd_query;
|
||||
} else {
|
||||
pipe->destroy_query(pipe, query);
|
||||
query = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
static void
|
||||
dd_context_destroy_query(struct pipe_context *_pipe,
|
||||
struct pipe_query *query)
|
||||
{
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe;
|
||||
|
||||
pipe->destroy_query(pipe, dd_query_unwrap(query));
|
||||
FREE(query);
|
||||
}
|
||||
|
||||
static boolean
|
||||
dd_context_begin_query(struct pipe_context *_pipe, struct pipe_query *query)
|
||||
{
|
||||
struct dd_context *dctx = dd_context(_pipe);
|
||||
struct pipe_context *pipe = dctx->pipe;
|
||||
|
||||
return pipe->begin_query(pipe, dd_query_unwrap(query));
|
||||
}
|
||||
|
||||
static void
|
||||
dd_context_end_query(struct pipe_context *_pipe, struct pipe_query *query)
|
||||
{
|
||||
struct dd_context *dctx = dd_context(_pipe);
|
||||
struct pipe_context *pipe = dctx->pipe;
|
||||
|
||||
pipe->end_query(pipe, dd_query_unwrap(query));
|
||||
}
|
||||
|
||||
static boolean
|
||||
dd_context_get_query_result(struct pipe_context *_pipe,
|
||||
struct pipe_query *query, boolean wait,
|
||||
union pipe_query_result *result)
|
||||
{
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe;
|
||||
|
||||
return pipe->get_query_result(pipe, dd_query_unwrap(query), wait, result);
|
||||
}
|
||||
|
||||
static void
|
||||
dd_context_render_condition(struct pipe_context *_pipe,
|
||||
struct pipe_query *query, boolean condition,
|
||||
uint mode)
|
||||
{
|
||||
struct dd_context *dctx = dd_context(_pipe);
|
||||
struct pipe_context *pipe = dctx->pipe;
|
||||
|
||||
pipe->render_condition(pipe, dd_query_unwrap(query), condition, mode);
|
||||
dctx->render_cond.query = dd_query(query);
|
||||
dctx->render_cond.condition = condition;
|
||||
dctx->render_cond.mode = mode;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* constant (immutable) non-shader states
|
||||
*/
|
||||
|
||||
#define DD_CSO_CREATE(name, shortname) \
|
||||
static void * \
|
||||
dd_context_create_##name##_state(struct pipe_context *_pipe, \
|
||||
const struct pipe_##name##_state *state) \
|
||||
{ \
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe; \
|
||||
struct dd_state *hstate = CALLOC_STRUCT(dd_state); \
|
||||
\
|
||||
if (!hstate) \
|
||||
return NULL; \
|
||||
hstate->cso = pipe->create_##name##_state(pipe, state); \
|
||||
hstate->state.shortname = *state; \
|
||||
return hstate; \
|
||||
}
|
||||
|
||||
#define DD_CSO_BIND(name, shortname) \
|
||||
static void \
|
||||
dd_context_bind_##name##_state(struct pipe_context *_pipe, void *state) \
|
||||
{ \
|
||||
struct dd_context *dctx = dd_context(_pipe); \
|
||||
struct pipe_context *pipe = dctx->pipe; \
|
||||
struct dd_state *hstate = state; \
|
||||
\
|
||||
dctx->shortname = hstate; \
|
||||
pipe->bind_##name##_state(pipe, hstate ? hstate->cso : NULL); \
|
||||
}
|
||||
|
||||
#define DD_CSO_DELETE(name) \
|
||||
static void \
|
||||
dd_context_delete_##name##_state(struct pipe_context *_pipe, void *state) \
|
||||
{ \
|
||||
struct dd_context *dctx = dd_context(_pipe); \
|
||||
struct pipe_context *pipe = dctx->pipe; \
|
||||
struct dd_state *hstate = state; \
|
||||
\
|
||||
pipe->delete_##name##_state(pipe, hstate->cso); \
|
||||
FREE(hstate); \
|
||||
}
|
||||
|
||||
#define DD_CSO_WHOLE(name, shortname) \
|
||||
DD_CSO_CREATE(name, shortname) \
|
||||
DD_CSO_BIND(name, shortname) \
|
||||
DD_CSO_DELETE(name)
|
||||
|
||||
DD_CSO_WHOLE(blend, blend)
|
||||
DD_CSO_WHOLE(rasterizer, rs)
|
||||
DD_CSO_WHOLE(depth_stencil_alpha, dsa)
|
||||
|
||||
DD_CSO_CREATE(sampler, sampler)
|
||||
DD_CSO_DELETE(sampler)
|
||||
|
||||
static void
|
||||
dd_context_bind_sampler_states(struct pipe_context *_pipe, unsigned shader,
|
||||
unsigned start, unsigned count, void **states)
|
||||
{
|
||||
struct dd_context *dctx = dd_context(_pipe);
|
||||
struct pipe_context *pipe = dctx->pipe;
|
||||
|
||||
memcpy(&dctx->sampler_states[shader][start], states,
|
||||
sizeof(void*) * count);
|
||||
|
||||
if (states) {
|
||||
void *samp[PIPE_MAX_SAMPLERS];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
struct dd_state *s = states[i];
|
||||
samp[i] = s ? s->cso : NULL;
|
||||
}
|
||||
|
||||
pipe->bind_sampler_states(pipe, shader, start, count, samp);
|
||||
}
|
||||
else
|
||||
pipe->bind_sampler_states(pipe, shader, start, count, NULL);
|
||||
}
|
||||
|
||||
static void *
|
||||
dd_context_create_vertex_elements_state(struct pipe_context *_pipe,
|
||||
unsigned num_elems,
|
||||
const struct pipe_vertex_element *elems)
|
||||
{
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe;
|
||||
struct dd_state *hstate = CALLOC_STRUCT(dd_state);
|
||||
|
||||
if (!hstate)
|
||||
return NULL;
|
||||
hstate->cso = pipe->create_vertex_elements_state(pipe, num_elems, elems);
|
||||
memcpy(hstate->state.velems.velems, elems, sizeof(elems[0]) * num_elems);
|
||||
hstate->state.velems.count = num_elems;
|
||||
return hstate;
|
||||
}
|
||||
|
||||
DD_CSO_BIND(vertex_elements, velems)
|
||||
DD_CSO_DELETE(vertex_elements)
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* shaders
|
||||
*/
|
||||
|
||||
#define DD_SHADER(NAME, name) \
|
||||
static void * \
|
||||
dd_context_create_##name##_state(struct pipe_context *_pipe, \
|
||||
const struct pipe_shader_state *state) \
|
||||
{ \
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe; \
|
||||
struct dd_state *hstate = CALLOC_STRUCT(dd_state); \
|
||||
\
|
||||
if (!hstate) \
|
||||
return NULL; \
|
||||
hstate->cso = pipe->create_##name##_state(pipe, state); \
|
||||
hstate->state.shader = *state; \
|
||||
hstate->state.shader.tokens = tgsi_dup_tokens(state->tokens); \
|
||||
return hstate; \
|
||||
} \
|
||||
\
|
||||
static void \
|
||||
dd_context_bind_##name##_state(struct pipe_context *_pipe, void *state) \
|
||||
{ \
|
||||
struct dd_context *dctx = dd_context(_pipe); \
|
||||
struct pipe_context *pipe = dctx->pipe; \
|
||||
struct dd_state *hstate = state; \
|
||||
\
|
||||
dctx->shaders[PIPE_SHADER_##NAME] = hstate; \
|
||||
pipe->bind_##name##_state(pipe, hstate ? hstate->cso : NULL); \
|
||||
} \
|
||||
\
|
||||
static void \
|
||||
dd_context_delete_##name##_state(struct pipe_context *_pipe, void *state) \
|
||||
{ \
|
||||
struct dd_context *dctx = dd_context(_pipe); \
|
||||
struct pipe_context *pipe = dctx->pipe; \
|
||||
struct dd_state *hstate = state; \
|
||||
\
|
||||
pipe->delete_##name##_state(pipe, hstate->cso); \
|
||||
tgsi_free_tokens(hstate->state.shader.tokens); \
|
||||
FREE(hstate); \
|
||||
}
|
||||
|
||||
DD_SHADER(FRAGMENT, fs)
|
||||
DD_SHADER(VERTEX, vs)
|
||||
DD_SHADER(GEOMETRY, gs)
|
||||
DD_SHADER(TESS_CTRL, tcs)
|
||||
DD_SHADER(TESS_EVAL, tes)
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* immediate states
|
||||
*/
|
||||
|
||||
#define DD_IMM_STATE(name, type, deref, ref) \
|
||||
static void \
|
||||
dd_context_set_##name(struct pipe_context *_pipe, type deref) \
|
||||
{ \
|
||||
struct dd_context *dctx = dd_context(_pipe); \
|
||||
struct pipe_context *pipe = dctx->pipe; \
|
||||
\
|
||||
dctx->name = deref; \
|
||||
pipe->set_##name(pipe, ref); \
|
||||
}
|
||||
|
||||
DD_IMM_STATE(blend_color, const struct pipe_blend_color, *state, state)
|
||||
DD_IMM_STATE(stencil_ref, const struct pipe_stencil_ref, *state, state)
|
||||
DD_IMM_STATE(clip_state, const struct pipe_clip_state, *state, state)
|
||||
DD_IMM_STATE(sample_mask, unsigned, sample_mask, sample_mask)
|
||||
DD_IMM_STATE(min_samples, unsigned, min_samples, min_samples)
|
||||
DD_IMM_STATE(framebuffer_state, const struct pipe_framebuffer_state, *state, state)
|
||||
DD_IMM_STATE(polygon_stipple, const struct pipe_poly_stipple, *state, state)
|
||||
|
||||
static void
|
||||
dd_context_set_constant_buffer(struct pipe_context *_pipe,
|
||||
uint shader, uint index,
|
||||
struct pipe_constant_buffer *constant_buffer)
|
||||
{
|
||||
struct dd_context *dctx = dd_context(_pipe);
|
||||
struct pipe_context *pipe = dctx->pipe;
|
||||
|
||||
safe_memcpy(&dctx->constant_buffers[shader][index], constant_buffer,
|
||||
sizeof(*constant_buffer));
|
||||
pipe->set_constant_buffer(pipe, shader, index, constant_buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
dd_context_set_scissor_states(struct pipe_context *_pipe,
|
||||
unsigned start_slot, unsigned num_scissors,
|
||||
const struct pipe_scissor_state *states)
|
||||
{
|
||||
struct dd_context *dctx = dd_context(_pipe);
|
||||
struct pipe_context *pipe = dctx->pipe;
|
||||
|
||||
safe_memcpy(&dctx->scissors[start_slot], states,
|
||||
sizeof(*states) * num_scissors);
|
||||
pipe->set_scissor_states(pipe, start_slot, num_scissors, states);
|
||||
}
|
||||
|
||||
static void
|
||||
dd_context_set_viewport_states(struct pipe_context *_pipe,
|
||||
unsigned start_slot, unsigned num_viewports,
|
||||
const struct pipe_viewport_state *states)
|
||||
{
|
||||
struct dd_context *dctx = dd_context(_pipe);
|
||||
struct pipe_context *pipe = dctx->pipe;
|
||||
|
||||
safe_memcpy(&dctx->viewports[start_slot], states,
|
||||
sizeof(*states) * num_viewports);
|
||||
pipe->set_viewport_states(pipe, start_slot, num_viewports, states);
|
||||
}
|
||||
|
||||
static void dd_context_set_tess_state(struct pipe_context *_pipe,
|
||||
const float default_outer_level[4],
|
||||
const float default_inner_level[2])
|
||||
{
|
||||
struct dd_context *dctx = dd_context(_pipe);
|
||||
struct pipe_context *pipe = dctx->pipe;
|
||||
|
||||
memcpy(dctx->tess_default_levels, default_outer_level, sizeof(float) * 4);
|
||||
memcpy(dctx->tess_default_levels+4, default_inner_level, sizeof(float) * 2);
|
||||
pipe->set_tess_state(pipe, default_outer_level, default_inner_level);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* views
|
||||
*/
|
||||
|
||||
static struct pipe_surface *
|
||||
dd_context_create_surface(struct pipe_context *_pipe,
|
||||
struct pipe_resource *resource,
|
||||
const struct pipe_surface *surf_tmpl)
|
||||
{
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe;
|
||||
struct pipe_surface *view =
|
||||
pipe->create_surface(pipe, resource, surf_tmpl);
|
||||
|
||||
if (!view)
|
||||
return NULL;
|
||||
view->context = _pipe;
|
||||
return view;
|
||||
}
|
||||
|
||||
static void
|
||||
dd_context_surface_destroy(struct pipe_context *_pipe,
|
||||
struct pipe_surface *surf)
|
||||
{
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe;
|
||||
|
||||
pipe->surface_destroy(pipe, surf);
|
||||
}
|
||||
|
||||
static struct pipe_sampler_view *
|
||||
dd_context_create_sampler_view(struct pipe_context *_pipe,
|
||||
struct pipe_resource *resource,
|
||||
const struct pipe_sampler_view *templ)
|
||||
{
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe;
|
||||
struct pipe_sampler_view *view =
|
||||
pipe->create_sampler_view(pipe, resource, templ);
|
||||
|
||||
if (!view)
|
||||
return NULL;
|
||||
view->context = _pipe;
|
||||
return view;
|
||||
}
|
||||
|
||||
static void
|
||||
dd_context_sampler_view_destroy(struct pipe_context *_pipe,
|
||||
struct pipe_sampler_view *view)
|
||||
{
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe;
|
||||
|
||||
pipe->sampler_view_destroy(pipe, view);
|
||||
}
|
||||
|
||||
static struct pipe_image_view *
|
||||
dd_context_create_image_view(struct pipe_context *_pipe,
|
||||
struct pipe_resource *resource,
|
||||
const struct pipe_image_view *templ)
|
||||
{
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe;
|
||||
struct pipe_image_view *view =
|
||||
pipe->create_image_view(pipe, resource, templ);
|
||||
|
||||
if (!view)
|
||||
return NULL;
|
||||
view->context = _pipe;
|
||||
return view;
|
||||
}
|
||||
|
||||
static void
|
||||
dd_context_image_view_destroy(struct pipe_context *_pipe,
|
||||
struct pipe_image_view *view)
|
||||
{
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe;
|
||||
|
||||
pipe->image_view_destroy(pipe, view);
|
||||
}
|
||||
|
||||
static struct pipe_stream_output_target *
|
||||
dd_context_create_stream_output_target(struct pipe_context *_pipe,
|
||||
struct pipe_resource *res,
|
||||
unsigned buffer_offset,
|
||||
unsigned buffer_size)
|
||||
{
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe;
|
||||
struct pipe_stream_output_target *view =
|
||||
pipe->create_stream_output_target(pipe, res, buffer_offset,
|
||||
buffer_size);
|
||||
|
||||
if (!view)
|
||||
return NULL;
|
||||
view->context = _pipe;
|
||||
return view;
|
||||
}
|
||||
|
||||
static void
|
||||
dd_context_stream_output_target_destroy(struct pipe_context *_pipe,
|
||||
struct pipe_stream_output_target *target)
|
||||
{
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe;
|
||||
|
||||
pipe->stream_output_target_destroy(pipe, target);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* set states
|
||||
*/
|
||||
|
||||
static void
|
||||
dd_context_set_sampler_views(struct pipe_context *_pipe, unsigned shader,
|
||||
unsigned start, unsigned num,
|
||||
struct pipe_sampler_view **views)
|
||||
{
|
||||
struct dd_context *dctx = dd_context(_pipe);
|
||||
struct pipe_context *pipe = dctx->pipe;
|
||||
|
||||
safe_memcpy(&dctx->sampler_views[shader][start], views,
|
||||
sizeof(views[0]) * num);
|
||||
pipe->set_sampler_views(pipe, shader, start, num, views);
|
||||
}
|
||||
|
||||
static void
|
||||
dd_context_set_shader_images(struct pipe_context *_pipe, unsigned shader,
|
||||
unsigned start, unsigned num,
|
||||
struct pipe_image_view **views)
|
||||
{
|
||||
struct dd_context *dctx = dd_context(_pipe);
|
||||
struct pipe_context *pipe = dctx->pipe;
|
||||
|
||||
safe_memcpy(&dctx->shader_images[shader][start], views,
|
||||
sizeof(views[0]) * num);
|
||||
pipe->set_shader_images(pipe, shader, start, num, views);
|
||||
}
|
||||
|
||||
static void
|
||||
dd_context_set_shader_buffers(struct pipe_context *_pipe, unsigned shader,
|
||||
unsigned start, unsigned num_buffers,
|
||||
struct pipe_shader_buffer *buffers)
|
||||
{
|
||||
struct dd_context *dctx = dd_context(_pipe);
|
||||
struct pipe_context *pipe = dctx->pipe;
|
||||
|
||||
safe_memcpy(&dctx->shader_buffers[shader][start], buffers,
|
||||
sizeof(buffers[0]) * num_buffers);
|
||||
pipe->set_shader_buffers(pipe, shader, start, num_buffers, buffers);
|
||||
}
|
||||
|
||||
static void
|
||||
dd_context_set_vertex_buffers(struct pipe_context *_pipe,
|
||||
unsigned start, unsigned num_buffers,
|
||||
const struct pipe_vertex_buffer *buffers)
|
||||
{
|
||||
struct dd_context *dctx = dd_context(_pipe);
|
||||
struct pipe_context *pipe = dctx->pipe;
|
||||
|
||||
safe_memcpy(&dctx->vertex_buffers[start], buffers,
|
||||
sizeof(buffers[0]) * num_buffers);
|
||||
pipe->set_vertex_buffers(pipe, start, num_buffers, buffers);
|
||||
}
|
||||
|
||||
static void
|
||||
dd_context_set_index_buffer(struct pipe_context *_pipe,
|
||||
const struct pipe_index_buffer *ib)
|
||||
{
|
||||
struct dd_context *dctx = dd_context(_pipe);
|
||||
struct pipe_context *pipe = dctx->pipe;
|
||||
|
||||
safe_memcpy(&dctx->index_buffer, ib, sizeof(*ib));
|
||||
pipe->set_index_buffer(pipe, ib);
|
||||
}
|
||||
|
||||
static void
|
||||
dd_context_set_stream_output_targets(struct pipe_context *_pipe,
|
||||
unsigned num_targets,
|
||||
struct pipe_stream_output_target **tgs,
|
||||
const unsigned *offsets)
|
||||
{
|
||||
struct dd_context *dctx = dd_context(_pipe);
|
||||
struct pipe_context *pipe = dctx->pipe;
|
||||
|
||||
dctx->num_so_targets = num_targets;
|
||||
safe_memcpy(dctx->so_targets, tgs, sizeof(*tgs) * num_targets);
|
||||
safe_memcpy(dctx->so_offsets, offsets, sizeof(*offsets) * num_targets);
|
||||
pipe->set_stream_output_targets(pipe, num_targets, tgs, offsets);
|
||||
}
|
||||
|
||||
static void
|
||||
dd_context_destroy(struct pipe_context *_pipe)
|
||||
{
|
||||
struct dd_context *dctx = dd_context(_pipe);
|
||||
struct pipe_context *pipe = dctx->pipe;
|
||||
|
||||
pipe->destroy(pipe);
|
||||
FREE(dctx);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* transfer
|
||||
*/
|
||||
|
||||
static void *
|
||||
dd_context_transfer_map(struct pipe_context *_pipe,
|
||||
struct pipe_resource *resource, unsigned level,
|
||||
unsigned usage, const struct pipe_box *box,
|
||||
struct pipe_transfer **transfer)
|
||||
{
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe;
|
||||
|
||||
return pipe->transfer_map(pipe, resource, level, usage, box, transfer);
|
||||
}
|
||||
|
||||
static void
|
||||
dd_context_transfer_flush_region(struct pipe_context *_pipe,
|
||||
struct pipe_transfer *transfer,
|
||||
const struct pipe_box *box)
|
||||
{
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe;
|
||||
|
||||
pipe->transfer_flush_region(pipe, transfer, box);
|
||||
}
|
||||
|
||||
static void
|
||||
dd_context_transfer_unmap(struct pipe_context *_pipe,
|
||||
struct pipe_transfer *transfer)
|
||||
{
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe;
|
||||
|
||||
pipe->transfer_unmap(pipe, transfer);
|
||||
}
|
||||
|
||||
static void
|
||||
dd_context_transfer_inline_write(struct pipe_context *_pipe,
|
||||
struct pipe_resource *resource,
|
||||
unsigned level, unsigned usage,
|
||||
const struct pipe_box *box,
|
||||
const void *data, unsigned stride,
|
||||
unsigned layer_stride)
|
||||
{
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe;
|
||||
|
||||
pipe->transfer_inline_write(pipe, resource, level, usage, box, data,
|
||||
stride, layer_stride);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* miscellaneous
|
||||
*/
|
||||
|
||||
static void
|
||||
dd_context_texture_barrier(struct pipe_context *_pipe)
|
||||
{
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe;
|
||||
|
||||
pipe->texture_barrier(pipe);
|
||||
}
|
||||
|
||||
static void
|
||||
dd_context_memory_barrier(struct pipe_context *_pipe, unsigned flags)
|
||||
{
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe;
|
||||
|
||||
pipe->memory_barrier(pipe, flags);
|
||||
}
|
||||
|
||||
static void
|
||||
dd_context_get_sample_position(struct pipe_context *_pipe,
|
||||
unsigned sample_count, unsigned sample_index,
|
||||
float *out_value)
|
||||
{
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe;
|
||||
|
||||
return pipe->get_sample_position(pipe, sample_count, sample_index,
|
||||
out_value);
|
||||
}
|
||||
|
||||
static void
|
||||
dd_context_invalidate_resource(struct pipe_context *_pipe,
|
||||
struct pipe_resource *resource)
|
||||
{
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe;
|
||||
|
||||
pipe->invalidate_resource(pipe, resource);
|
||||
}
|
||||
|
||||
static enum pipe_reset_status
|
||||
dd_context_get_device_reset_status(struct pipe_context *_pipe)
|
||||
{
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe;
|
||||
|
||||
return pipe->get_device_reset_status(pipe);
|
||||
}
|
||||
|
||||
static void
|
||||
dd_context_dump_debug_state(struct pipe_context *_pipe, FILE *stream,
|
||||
unsigned flags)
|
||||
{
|
||||
struct pipe_context *pipe = dd_context(_pipe)->pipe;
|
||||
|
||||
return pipe->dump_debug_state(pipe, stream, flags);
|
||||
}
|
||||
|
||||
struct pipe_context *
|
||||
dd_context_create(struct dd_screen *dscreen, struct pipe_context *pipe)
|
||||
{
|
||||
struct dd_context *dctx;
|
||||
|
||||
if (!pipe)
|
||||
return NULL;
|
||||
|
||||
dctx = CALLOC_STRUCT(dd_context);
|
||||
if (!dctx) {
|
||||
pipe->destroy(pipe);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dctx->pipe = pipe;
|
||||
dctx->base.priv = pipe->priv; /* expose wrapped priv data */
|
||||
dctx->base.screen = &dscreen->base;
|
||||
|
||||
dctx->base.destroy = dd_context_destroy;
|
||||
|
||||
CTX_INIT(render_condition);
|
||||
CTX_INIT(create_query);
|
||||
CTX_INIT(destroy_query);
|
||||
CTX_INIT(begin_query);
|
||||
CTX_INIT(end_query);
|
||||
CTX_INIT(get_query_result);
|
||||
CTX_INIT(create_blend_state);
|
||||
CTX_INIT(bind_blend_state);
|
||||
CTX_INIT(delete_blend_state);
|
||||
CTX_INIT(create_sampler_state);
|
||||
CTX_INIT(bind_sampler_states);
|
||||
CTX_INIT(delete_sampler_state);
|
||||
CTX_INIT(create_rasterizer_state);
|
||||
CTX_INIT(bind_rasterizer_state);
|
||||
CTX_INIT(delete_rasterizer_state);
|
||||
CTX_INIT(create_depth_stencil_alpha_state);
|
||||
CTX_INIT(bind_depth_stencil_alpha_state);
|
||||
CTX_INIT(delete_depth_stencil_alpha_state);
|
||||
CTX_INIT(create_fs_state);
|
||||
CTX_INIT(bind_fs_state);
|
||||
CTX_INIT(delete_fs_state);
|
||||
CTX_INIT(create_vs_state);
|
||||
CTX_INIT(bind_vs_state);
|
||||
CTX_INIT(delete_vs_state);
|
||||
CTX_INIT(create_gs_state);
|
||||
CTX_INIT(bind_gs_state);
|
||||
CTX_INIT(delete_gs_state);
|
||||
CTX_INIT(create_tcs_state);
|
||||
CTX_INIT(bind_tcs_state);
|
||||
CTX_INIT(delete_tcs_state);
|
||||
CTX_INIT(create_tes_state);
|
||||
CTX_INIT(bind_tes_state);
|
||||
CTX_INIT(delete_tes_state);
|
||||
CTX_INIT(create_vertex_elements_state);
|
||||
CTX_INIT(bind_vertex_elements_state);
|
||||
CTX_INIT(delete_vertex_elements_state);
|
||||
CTX_INIT(set_blend_color);
|
||||
CTX_INIT(set_stencil_ref);
|
||||
CTX_INIT(set_sample_mask);
|
||||
CTX_INIT(set_min_samples);
|
||||
CTX_INIT(set_clip_state);
|
||||
CTX_INIT(set_constant_buffer);
|
||||
CTX_INIT(set_framebuffer_state);
|
||||
CTX_INIT(set_polygon_stipple);
|
||||
CTX_INIT(set_scissor_states);
|
||||
CTX_INIT(set_viewport_states);
|
||||
CTX_INIT(set_sampler_views);
|
||||
CTX_INIT(set_tess_state);
|
||||
CTX_INIT(set_shader_buffers);
|
||||
CTX_INIT(set_shader_images);
|
||||
CTX_INIT(set_vertex_buffers);
|
||||
CTX_INIT(set_index_buffer);
|
||||
CTX_INIT(create_stream_output_target);
|
||||
CTX_INIT(stream_output_target_destroy);
|
||||
CTX_INIT(set_stream_output_targets);
|
||||
CTX_INIT(create_sampler_view);
|
||||
CTX_INIT(sampler_view_destroy);
|
||||
CTX_INIT(create_surface);
|
||||
CTX_INIT(surface_destroy);
|
||||
CTX_INIT(create_image_view);
|
||||
CTX_INIT(image_view_destroy);
|
||||
CTX_INIT(transfer_map);
|
||||
CTX_INIT(transfer_flush_region);
|
||||
CTX_INIT(transfer_unmap);
|
||||
CTX_INIT(transfer_inline_write);
|
||||
CTX_INIT(texture_barrier);
|
||||
CTX_INIT(memory_barrier);
|
||||
/* create_video_codec */
|
||||
/* create_video_buffer */
|
||||
/* create_compute_state */
|
||||
/* bind_compute_state */
|
||||
/* delete_compute_state */
|
||||
/* set_compute_resources */
|
||||
/* set_global_binding */
|
||||
CTX_INIT(get_sample_position);
|
||||
CTX_INIT(invalidate_resource);
|
||||
CTX_INIT(get_device_reset_status);
|
||||
CTX_INIT(dump_debug_state);
|
||||
|
||||
dd_init_draw_functions(dctx);
|
||||
|
||||
dctx->sample_mask = ~0;
|
||||
return &dctx->base;
|
||||
}
|
||||
807
src/gallium/drivers/ddebug/dd_draw.c
Normal file
807
src/gallium/drivers/ddebug/dd_draw.c
Normal file
|
|
@ -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 */
|
||||
}
|
||||
141
src/gallium/drivers/ddebug/dd_pipe.h
Normal file
141
src/gallium/drivers/ddebug/dd_pipe.h
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef DD_H_
|
||||
#define DD_H_
|
||||
|
||||
#include "pipe/p_context.h"
|
||||
#include "pipe/p_state.h"
|
||||
#include "pipe/p_screen.h"
|
||||
|
||||
/* name of the directory in home */
|
||||
#define DD_DIR "ddebug_dumps"
|
||||
|
||||
enum dd_mode {
|
||||
DD_DETECT_HANGS,
|
||||
DD_DUMP_ALL_CALLS
|
||||
};
|
||||
|
||||
struct dd_screen
|
||||
{
|
||||
struct pipe_screen base;
|
||||
struct pipe_screen *screen;
|
||||
unsigned timeout_ms;
|
||||
enum dd_mode mode;
|
||||
bool no_flush;
|
||||
};
|
||||
|
||||
struct dd_query
|
||||
{
|
||||
unsigned type;
|
||||
struct pipe_query *query;
|
||||
};
|
||||
|
||||
struct dd_state
|
||||
{
|
||||
void *cso;
|
||||
|
||||
union {
|
||||
struct pipe_blend_state blend;
|
||||
struct pipe_depth_stencil_alpha_state dsa;
|
||||
struct pipe_rasterizer_state rs;
|
||||
struct pipe_sampler_state sampler;
|
||||
struct {
|
||||
struct pipe_vertex_element velems[PIPE_MAX_ATTRIBS];
|
||||
unsigned count;
|
||||
} velems;
|
||||
struct pipe_shader_state shader;
|
||||
} state;
|
||||
};
|
||||
|
||||
struct dd_context
|
||||
{
|
||||
struct pipe_context base;
|
||||
struct pipe_context *pipe;
|
||||
|
||||
struct {
|
||||
struct dd_query *query;
|
||||
bool condition;
|
||||
unsigned mode;
|
||||
} render_cond;
|
||||
|
||||
struct pipe_index_buffer index_buffer;
|
||||
struct pipe_vertex_buffer vertex_buffers[PIPE_MAX_ATTRIBS];
|
||||
|
||||
unsigned num_so_targets;
|
||||
struct pipe_stream_output_target *so_targets[PIPE_MAX_SO_BUFFERS];
|
||||
unsigned so_offsets[PIPE_MAX_SO_BUFFERS];
|
||||
|
||||
struct dd_state *shaders[PIPE_SHADER_TYPES];
|
||||
struct pipe_constant_buffer constant_buffers[PIPE_SHADER_TYPES][PIPE_MAX_CONSTANT_BUFFERS];
|
||||
struct pipe_sampler_view *sampler_views[PIPE_SHADER_TYPES][PIPE_MAX_SAMPLERS];
|
||||
struct dd_state *sampler_states[PIPE_SHADER_TYPES][PIPE_MAX_SAMPLERS];
|
||||
struct pipe_image_view *shader_images[PIPE_SHADER_TYPES][PIPE_MAX_SHADER_IMAGES];
|
||||
struct pipe_shader_buffer shader_buffers[PIPE_SHADER_TYPES][PIPE_MAX_SHADER_BUFFERS];
|
||||
|
||||
struct dd_state *velems;
|
||||
struct dd_state *rs;
|
||||
struct dd_state *dsa;
|
||||
struct dd_state *blend;
|
||||
|
||||
struct pipe_blend_color blend_color;
|
||||
struct pipe_stencil_ref stencil_ref;
|
||||
unsigned sample_mask;
|
||||
unsigned min_samples;
|
||||
struct pipe_clip_state clip_state;
|
||||
struct pipe_framebuffer_state framebuffer_state;
|
||||
struct pipe_poly_stipple polygon_stipple;
|
||||
struct pipe_scissor_state scissors[PIPE_MAX_VIEWPORTS];
|
||||
struct pipe_viewport_state viewports[PIPE_MAX_VIEWPORTS];
|
||||
float tess_default_levels[6];
|
||||
};
|
||||
|
||||
|
||||
struct pipe_context *
|
||||
dd_context_create(struct dd_screen *dscreen, struct pipe_context *pipe);
|
||||
|
||||
void
|
||||
dd_init_draw_functions(struct dd_context *dctx);
|
||||
|
||||
|
||||
static inline struct dd_context *
|
||||
dd_context(struct pipe_context *pipe)
|
||||
{
|
||||
return (struct dd_context *)pipe;
|
||||
}
|
||||
|
||||
static inline struct dd_screen *
|
||||
dd_screen(struct pipe_screen *screen)
|
||||
{
|
||||
return (struct dd_screen*)screen;
|
||||
}
|
||||
|
||||
|
||||
#define CTX_INIT(_member) \
|
||||
dctx->base._member = dctx->pipe->_member ? dd_context_##_member : NULL
|
||||
|
||||
#endif /* DD_H_ */
|
||||
36
src/gallium/drivers/ddebug/dd_public.h
Normal file
36
src/gallium/drivers/ddebug/dd_public.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2015 Advanced Micro Devices, Inc.
|
||||
* Copyright 2010 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.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef DD_PUBLIC_H_
|
||||
#define DD_PUBLIC_H_
|
||||
|
||||
struct pipe_screen;
|
||||
|
||||
struct pipe_screen *
|
||||
ddebug_screen_create(struct pipe_screen *screen);
|
||||
|
||||
#endif /* DD_PUBLIC_H_ */
|
||||
353
src/gallium/drivers/ddebug/dd_screen.c
Normal file
353
src/gallium/drivers/ddebug/dd_screen.c
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* 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 "dd_public.h"
|
||||
#include "util/u_memory.h"
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
static const char *
|
||||
dd_screen_get_name(struct pipe_screen *_screen)
|
||||
{
|
||||
struct pipe_screen *screen = dd_screen(_screen)->screen;
|
||||
|
||||
return screen->get_name(screen);
|
||||
}
|
||||
|
||||
static const char *
|
||||
dd_screen_get_vendor(struct pipe_screen *_screen)
|
||||
{
|
||||
struct pipe_screen *screen = dd_screen(_screen)->screen;
|
||||
|
||||
return screen->get_vendor(screen);
|
||||
}
|
||||
|
||||
static const char *
|
||||
dd_screen_get_device_vendor(struct pipe_screen *_screen)
|
||||
{
|
||||
struct pipe_screen *screen = dd_screen(_screen)->screen;
|
||||
|
||||
return screen->get_device_vendor(screen);
|
||||
}
|
||||
|
||||
static int
|
||||
dd_screen_get_param(struct pipe_screen *_screen,
|
||||
enum pipe_cap param)
|
||||
{
|
||||
struct pipe_screen *screen = dd_screen(_screen)->screen;
|
||||
|
||||
return screen->get_param(screen, param);
|
||||
}
|
||||
|
||||
static float
|
||||
dd_screen_get_paramf(struct pipe_screen *_screen,
|
||||
enum pipe_capf param)
|
||||
{
|
||||
struct pipe_screen *screen = dd_screen(_screen)->screen;
|
||||
|
||||
return screen->get_paramf(screen, param);
|
||||
}
|
||||
|
||||
static int
|
||||
dd_screen_get_shader_param(struct pipe_screen *_screen, unsigned shader,
|
||||
enum pipe_shader_cap param)
|
||||
{
|
||||
struct pipe_screen *screen = dd_screen(_screen)->screen;
|
||||
|
||||
return screen->get_shader_param(screen, shader, param);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
dd_screen_get_timestamp(struct pipe_screen *_screen)
|
||||
{
|
||||
struct pipe_screen *screen = dd_screen(_screen)->screen;
|
||||
|
||||
return screen->get_timestamp(screen);
|
||||
}
|
||||
|
||||
static struct pipe_context *
|
||||
dd_screen_context_create(struct pipe_screen *_screen, void *priv,
|
||||
unsigned flags)
|
||||
{
|
||||
struct dd_screen *dscreen = dd_screen(_screen);
|
||||
struct pipe_screen *screen = dscreen->screen;
|
||||
|
||||
flags |= PIPE_CONTEXT_DEBUG;
|
||||
|
||||
return dd_context_create(dscreen,
|
||||
screen->context_create(screen, priv, flags));
|
||||
}
|
||||
|
||||
static boolean
|
||||
dd_screen_is_format_supported(struct pipe_screen *_screen,
|
||||
enum pipe_format format,
|
||||
enum pipe_texture_target target,
|
||||
unsigned sample_count,
|
||||
unsigned tex_usage)
|
||||
{
|
||||
struct pipe_screen *screen = dd_screen(_screen)->screen;
|
||||
|
||||
return screen->is_format_supported(screen, format, target, sample_count,
|
||||
tex_usage);
|
||||
}
|
||||
|
||||
static boolean
|
||||
dd_screen_can_create_resource(struct pipe_screen *_screen,
|
||||
const struct pipe_resource *templat)
|
||||
{
|
||||
struct pipe_screen *screen = dd_screen(_screen)->screen;
|
||||
|
||||
return screen->can_create_resource(screen, templat);
|
||||
}
|
||||
|
||||
static void
|
||||
dd_screen_flush_frontbuffer(struct pipe_screen *_screen,
|
||||
struct pipe_resource *resource,
|
||||
unsigned level, unsigned layer,
|
||||
void *context_private,
|
||||
struct pipe_box *sub_box)
|
||||
{
|
||||
struct pipe_screen *screen = dd_screen(_screen)->screen;
|
||||
|
||||
screen->flush_frontbuffer(screen, resource, level, layer, context_private,
|
||||
sub_box);
|
||||
}
|
||||
|
||||
static int
|
||||
dd_screen_get_driver_query_info(struct pipe_screen *_screen,
|
||||
unsigned index,
|
||||
struct pipe_driver_query_info *info)
|
||||
{
|
||||
struct pipe_screen *screen = dd_screen(_screen)->screen;
|
||||
|
||||
return screen->get_driver_query_info(screen, index, info);
|
||||
}
|
||||
|
||||
static int
|
||||
dd_screen_get_driver_query_group_info(struct pipe_screen *_screen,
|
||||
unsigned index,
|
||||
struct pipe_driver_query_group_info *info)
|
||||
{
|
||||
struct pipe_screen *screen = dd_screen(_screen)->screen;
|
||||
|
||||
return screen->get_driver_query_group_info(screen, index, info);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* resource
|
||||
*/
|
||||
|
||||
static struct pipe_resource *
|
||||
dd_screen_resource_create(struct pipe_screen *_screen,
|
||||
const struct pipe_resource *templat)
|
||||
{
|
||||
struct pipe_screen *screen = dd_screen(_screen)->screen;
|
||||
struct pipe_resource *res = screen->resource_create(screen, templat);
|
||||
|
||||
if (!res)
|
||||
return NULL;
|
||||
res->screen = _screen;
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct pipe_resource *
|
||||
dd_screen_resource_from_handle(struct pipe_screen *_screen,
|
||||
const struct pipe_resource *templ,
|
||||
struct winsys_handle *handle)
|
||||
{
|
||||
struct pipe_screen *screen = dd_screen(_screen)->screen;
|
||||
struct pipe_resource *res =
|
||||
screen->resource_from_handle(screen, templ, handle);
|
||||
|
||||
if (!res)
|
||||
return NULL;
|
||||
res->screen = _screen;
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct pipe_resource *
|
||||
dd_screen_resource_from_user_memory(struct pipe_screen *_screen,
|
||||
const struct pipe_resource *templ,
|
||||
void *user_memory)
|
||||
{
|
||||
struct pipe_screen *screen = dd_screen(_screen)->screen;
|
||||
struct pipe_resource *res =
|
||||
screen->resource_from_user_memory(screen, templ, user_memory);
|
||||
|
||||
if (!res)
|
||||
return NULL;
|
||||
res->screen = _screen;
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
dd_screen_resource_destroy(struct pipe_screen *_screen,
|
||||
struct pipe_resource *res)
|
||||
{
|
||||
struct pipe_screen *screen = dd_screen(_screen)->screen;
|
||||
|
||||
screen->resource_destroy(screen, res);
|
||||
}
|
||||
|
||||
static boolean
|
||||
dd_screen_resource_get_handle(struct pipe_screen *_screen,
|
||||
struct pipe_resource *resource,
|
||||
struct winsys_handle *handle)
|
||||
{
|
||||
struct pipe_screen *screen = dd_screen(_screen)->screen;
|
||||
|
||||
return screen->resource_get_handle(screen, resource, handle);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* fence
|
||||
*/
|
||||
|
||||
static void
|
||||
dd_screen_fence_reference(struct pipe_screen *_screen,
|
||||
struct pipe_fence_handle **pdst,
|
||||
struct pipe_fence_handle *src)
|
||||
{
|
||||
struct pipe_screen *screen = dd_screen(_screen)->screen;
|
||||
|
||||
screen->fence_reference(screen, pdst, src);
|
||||
}
|
||||
|
||||
static boolean
|
||||
dd_screen_fence_finish(struct pipe_screen *_screen,
|
||||
struct pipe_fence_handle *fence,
|
||||
uint64_t timeout)
|
||||
{
|
||||
struct pipe_screen *screen = dd_screen(_screen)->screen;
|
||||
|
||||
return screen->fence_finish(screen, fence, timeout);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* screen
|
||||
*/
|
||||
|
||||
static void
|
||||
dd_screen_destroy(struct pipe_screen *_screen)
|
||||
{
|
||||
struct dd_screen *dscreen = dd_screen(_screen);
|
||||
struct pipe_screen *screen = dscreen->screen;
|
||||
|
||||
screen->destroy(screen);
|
||||
FREE(dscreen);
|
||||
}
|
||||
|
||||
struct pipe_screen *
|
||||
ddebug_screen_create(struct pipe_screen *screen)
|
||||
{
|
||||
struct dd_screen *dscreen;
|
||||
const char *option = debug_get_option("GALLIUM_DDEBUG", NULL);
|
||||
bool dump_always = option && !strcmp(option, "always");
|
||||
bool no_flush = option && strstr(option, "noflush");
|
||||
bool help = option && !strcmp(option, "help");
|
||||
unsigned timeout = 0;
|
||||
|
||||
if (help) {
|
||||
puts("Gallium driver debugger");
|
||||
puts("");
|
||||
puts("Usage:");
|
||||
puts("");
|
||||
puts(" GALLIUM_DDEBUG=always");
|
||||
puts(" Dump context and driver information after every draw call into");
|
||||
puts(" $HOME/"DD_DIR"/.");
|
||||
puts("");
|
||||
puts(" GALLIUM_DDEBUG=[timeout in ms] noflush");
|
||||
puts(" Flush and detect a device hang after every draw call based on the given");
|
||||
puts(" fence timeout and dump context and driver information into");
|
||||
puts(" $HOME/"DD_DIR"/ when a hang is detected.");
|
||||
puts(" If 'noflush' is specified, only detect hangs in pipe->flush.");
|
||||
puts("");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (!option)
|
||||
return screen;
|
||||
if (!dump_always && sscanf(option, "%u", &timeout) != 1)
|
||||
return screen;
|
||||
|
||||
dscreen = CALLOC_STRUCT(dd_screen);
|
||||
if (!dscreen)
|
||||
return NULL;
|
||||
|
||||
#define SCR_INIT(_member) \
|
||||
dscreen->base._member = screen->_member ? dd_screen_##_member : NULL
|
||||
|
||||
dscreen->base.destroy = dd_screen_destroy;
|
||||
dscreen->base.get_name = dd_screen_get_name;
|
||||
dscreen->base.get_vendor = dd_screen_get_vendor;
|
||||
dscreen->base.get_device_vendor = dd_screen_get_device_vendor;
|
||||
dscreen->base.get_param = dd_screen_get_param;
|
||||
dscreen->base.get_paramf = dd_screen_get_paramf;
|
||||
dscreen->base.get_shader_param = dd_screen_get_shader_param;
|
||||
/* get_video_param */
|
||||
/* get_compute_param */
|
||||
SCR_INIT(get_timestamp);
|
||||
dscreen->base.context_create = dd_screen_context_create;
|
||||
dscreen->base.is_format_supported = dd_screen_is_format_supported;
|
||||
/* is_video_format_supported */
|
||||
SCR_INIT(can_create_resource);
|
||||
dscreen->base.resource_create = dd_screen_resource_create;
|
||||
dscreen->base.resource_from_handle = dd_screen_resource_from_handle;
|
||||
SCR_INIT(resource_from_user_memory);
|
||||
dscreen->base.resource_get_handle = dd_screen_resource_get_handle;
|
||||
dscreen->base.resource_destroy = dd_screen_resource_destroy;
|
||||
SCR_INIT(flush_frontbuffer);
|
||||
SCR_INIT(fence_reference);
|
||||
SCR_INIT(fence_finish);
|
||||
SCR_INIT(get_driver_query_info);
|
||||
SCR_INIT(get_driver_query_group_info);
|
||||
|
||||
#undef SCR_INIT
|
||||
|
||||
dscreen->screen = screen;
|
||||
dscreen->timeout_ms = timeout;
|
||||
dscreen->mode = dump_always ? DD_DUMP_ALL_CALLS : DD_DETECT_HANGS;
|
||||
dscreen->no_flush = no_flush;
|
||||
|
||||
switch (dscreen->mode) {
|
||||
case DD_DUMP_ALL_CALLS:
|
||||
fprintf(stderr, "Gallium debugger active. Logging all calls.\n");
|
||||
break;
|
||||
case DD_DETECT_HANGS:
|
||||
fprintf(stderr, "Gallium debugger active. "
|
||||
"The hang detection timout is %i ms.\n", timeout);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return &dscreen->base;
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ AM_CFLAGS = \
|
|||
AM_CPPFLAGS = \
|
||||
$(DEFINES) \
|
||||
-DDRI_TARGET \
|
||||
-DGALLIUM_DDEBUG \
|
||||
-DGALLIUM_NOOP \
|
||||
-DGALLIUM_RBUG \
|
||||
-DGALLIUM_TRACE
|
||||
|
|
@ -45,6 +46,7 @@ gallium_dri_la_LIBADD = \
|
|||
$(top_builddir)/src/gallium/state_trackers/dri/libdri.la \
|
||||
$(top_builddir)/src/gallium/auxiliary/libgalliumvl.la \
|
||||
$(top_builddir)/src/gallium/auxiliary/libgallium.la \
|
||||
$(top_builddir)/src/gallium/drivers/ddebug/libddebug.la \
|
||||
$(top_builddir)/src/gallium/drivers/noop/libnoop.la \
|
||||
$(top_builddir)/src/gallium/drivers/rbug/librbug.la \
|
||||
$(top_builddir)/src/gallium/drivers/trace/libtrace.la \
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue