ddebug: handle some cases of non-TGSI shaders
[mesa.git] / src / gallium / drivers / ddebug / dd_context.c
index 9dfaa0af2898419affe5386b9d3cb5770986152a..6b1ddc9d46be72a7f223e190b64fc7758825a521 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "dd_pipe.h"
 #include "tgsi/tgsi_parse.h"
+#include "util/u_inlines.h"
 #include "util/u_memory.h"
 
 
@@ -85,6 +86,32 @@ dd_context_create_query(struct pipe_context *_pipe, unsigned query_type,
    return query;
 }
 
+static struct pipe_query *
+dd_context_create_batch_query(struct pipe_context *_pipe, unsigned num_queries,
+                              unsigned *query_types)
+{
+   struct pipe_context *pipe = dd_context(_pipe)->pipe;
+   struct pipe_query *query;
+
+   query = pipe->create_batch_query(pipe, num_queries, query_types);
+
+   /* Wrap query object. */
+   if (query) {
+      struct dd_query *dd_query = CALLOC_STRUCT(dd_query);
+      if (dd_query) {
+         /* no special handling for batch queries yet */
+         dd_query->type = query_types[0];
+         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)
@@ -104,13 +131,13 @@ dd_context_begin_query(struct pipe_context *_pipe, struct pipe_query *query)
    return pipe->begin_query(pipe, dd_query_unwrap(query));
 }
 
-static void
+static bool
 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));
+   return pipe->end_query(pipe, dd_query_unwrap(query));
 }
 
 static boolean
@@ -123,18 +150,42 @@ dd_context_get_query_result(struct pipe_context *_pipe,
    return pipe->get_query_result(pipe, dd_query_unwrap(query), wait, result);
 }
 
+static void
+dd_context_get_query_result_resource(struct pipe_context *_pipe,
+                                     struct pipe_query *query,
+                                     boolean wait,
+                                     enum pipe_query_value_type result_type,
+                                     int index,
+                                     struct pipe_resource *resource,
+                                     unsigned offset)
+{
+   struct pipe_context *pipe = dd_context(_pipe)->pipe;
+
+   pipe->get_query_result_resource(pipe, dd_query_unwrap(query), wait,
+                                   result_type, index, resource, offset);
+}
+
+static void
+dd_context_set_active_query_state(struct pipe_context *_pipe, boolean enable)
+{
+   struct pipe_context *pipe = dd_context(_pipe)->pipe;
+
+   pipe->set_active_query_state(pipe, enable);
+}
+
 static void
 dd_context_render_condition(struct pipe_context *_pipe,
                             struct pipe_query *query, boolean condition,
-                            uint mode)
+                            enum pipe_render_cond_flag mode)
 {
    struct dd_context *dctx = dd_context(_pipe);
    struct pipe_context *pipe = dctx->pipe;
+   struct dd_draw_state *dstate = &dctx->draw_state;
 
    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;
+   dstate->render_cond.query = dd_query(query);
+   dstate->render_cond.condition = condition;
+   dstate->render_cond.mode = mode;
 }
 
 
@@ -165,7 +216,7 @@ dd_context_render_condition(struct pipe_context *_pipe,
       struct pipe_context *pipe = dctx->pipe; \
       struct dd_state *hstate = state; \
  \
-      dctx->shortname = hstate; \
+      dctx->draw_state.shortname = hstate; \
       pipe->bind_##name##_state(pipe, hstate ? hstate->cso : NULL); \
    }
 
@@ -194,13 +245,14 @@ DD_CSO_CREATE(sampler, sampler)
 DD_CSO_DELETE(sampler)
 
 static void
-dd_context_bind_sampler_states(struct pipe_context *_pipe, unsigned shader,
+dd_context_bind_sampler_states(struct pipe_context *_pipe,
+                               enum pipe_shader_type 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,
+   memcpy(&dctx->draw_state.sampler_states[shader][start], states,
           sizeof(void*) * count);
 
    if (states) {
@@ -242,22 +294,7 @@ 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; \
-   } \
-    \
+#define DD_SHADER_NOCREATE(NAME, name) \
    static void \
    dd_context_bind_##name##_state(struct pipe_context *_pipe, void *state) \
    { \
@@ -265,7 +302,7 @@ DD_CSO_DELETE(vertex_elements)
       struct pipe_context *pipe = dctx->pipe; \
       struct dd_state *hstate = state; \
    \
-      dctx->shaders[PIPE_SHADER_##NAME] = hstate; \
+      dctx->draw_state.shaders[PIPE_SHADER_##NAME] = hstate; \
       pipe->bind_##name##_state(pipe, hstate ? hstate->cso : NULL); \
    } \
     \
@@ -277,16 +314,56 @@ DD_CSO_DELETE(vertex_elements)
       struct dd_state *hstate = state; \
    \
       pipe->delete_##name##_state(pipe, hstate->cso); \
-      tgsi_free_tokens(hstate->state.shader.tokens); \
+      if (hstate->state.shader.type == PIPE_SHADER_IR_TGSI) \
+         tgsi_free_tokens(hstate->state.shader.tokens); \
       FREE(hstate); \
    }
 
+#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; \
+      if (hstate->state.shader.type == PIPE_SHADER_IR_TGSI) \
+         hstate->state.shader.tokens = tgsi_dup_tokens(state->tokens); \
+      return hstate; \
+   } \
+    \
+   DD_SHADER_NOCREATE(NAME, name)
+
 DD_SHADER(FRAGMENT, fs)
 DD_SHADER(VERTEX, vs)
 DD_SHADER(GEOMETRY, gs)
 DD_SHADER(TESS_CTRL, tcs)
 DD_SHADER(TESS_EVAL, tes)
 
+static void * \
+dd_context_create_compute_state(struct pipe_context *_pipe,
+                                 const struct pipe_compute_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_compute_state(pipe, state);
+
+   hstate->state.shader.type = state->ir_type;
+
+   if (state->ir_type == PIPE_SHADER_IR_TGSI)
+      hstate->state.shader.tokens = tgsi_dup_tokens(state->prog);
+
+   return hstate;
+}
+
+DD_SHADER_NOCREATE(COMPUTE, compute)
 
 /********************************************************************
  * immediate states
@@ -299,7 +376,7 @@ DD_SHADER(TESS_EVAL, tes)
       struct dd_context *dctx = dd_context(_pipe); \
       struct pipe_context *pipe = dctx->pipe; \
  \
-      dctx->name = deref; \
+      dctx->draw_state.name = deref; \
       pipe->set_##name(pipe, ref); \
    }
 
@@ -313,14 +390,14 @@ 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)
+                               enum pipe_shader_type shader, uint index,
+                               const 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));
+   safe_memcpy(&dctx->draw_state.constant_buffers[shader][index],
+               constant_buffer, sizeof(*constant_buffer));
    pipe->set_constant_buffer(pipe, shader, index, constant_buffer);
 }
 
@@ -332,7 +409,7 @@ dd_context_set_scissor_states(struct pipe_context *_pipe,
    struct dd_context *dctx = dd_context(_pipe);
    struct pipe_context *pipe = dctx->pipe;
 
-   safe_memcpy(&dctx->scissors[start_slot], states,
+   safe_memcpy(&dctx->draw_state.scissors[start_slot], states,
                sizeof(*states) * num_scissors);
    pipe->set_scissor_states(pipe, start_slot, num_scissors, states);
 }
@@ -345,7 +422,7 @@ dd_context_set_viewport_states(struct pipe_context *_pipe,
    struct dd_context *dctx = dd_context(_pipe);
    struct pipe_context *pipe = dctx->pipe;
 
-   safe_memcpy(&dctx->viewports[start_slot], states,
+   safe_memcpy(&dctx->draw_state.viewports[start_slot], states,
                sizeof(*states) * num_viewports);
    pipe->set_viewport_states(pipe, start_slot, num_viewports, states);
 }
@@ -357,8 +434,10 @@ static void dd_context_set_tess_state(struct pipe_context *_pipe,
    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);
+   memcpy(dctx->draw_state.tess_default_levels, default_outer_level,
+          sizeof(float) * 4);
+   memcpy(dctx->draw_state.tess_default_levels+4, default_inner_level,
+          sizeof(float) * 2);
    pipe->set_tess_state(pipe, default_outer_level, default_inner_level);
 }
 
@@ -447,27 +526,29 @@ dd_context_stream_output_target_destroy(struct pipe_context *_pipe,
  */
 
 static void
-dd_context_set_sampler_views(struct pipe_context *_pipe, unsigned shader,
+dd_context_set_sampler_views(struct pipe_context *_pipe,
+                             enum pipe_shader_type 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,
+   safe_memcpy(&dctx->draw_state.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,
+dd_context_set_shader_images(struct pipe_context *_pipe,
+                             enum pipe_shader_type shader,
                              unsigned start, unsigned num,
-                             struct pipe_image_view *views)
+                             const 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,
+   safe_memcpy(&dctx->draw_state.shader_images[shader][start], views,
                sizeof(views[0]) * num);
    pipe->set_shader_images(pipe, shader, start, num, views);
 }
@@ -475,12 +556,12 @@ dd_context_set_shader_images(struct pipe_context *_pipe, unsigned shader,
 static void
 dd_context_set_shader_buffers(struct pipe_context *_pipe, unsigned shader,
                               unsigned start, unsigned num_buffers,
-                              struct pipe_shader_buffer *buffers)
+                              const 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,
+   safe_memcpy(&dctx->draw_state.shader_buffers[shader][start], buffers,
                sizeof(buffers[0]) * num_buffers);
    pipe->set_shader_buffers(pipe, shader, start, num_buffers, buffers);
 }
@@ -493,22 +574,11 @@ dd_context_set_vertex_buffers(struct pipe_context *_pipe,
    struct dd_context *dctx = dd_context(_pipe);
    struct pipe_context *pipe = dctx->pipe;
 
-   safe_memcpy(&dctx->vertex_buffers[start], buffers,
+   safe_memcpy(&dctx->draw_state.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,
@@ -517,10 +587,11 @@ dd_context_set_stream_output_targets(struct pipe_context *_pipe,
 {
    struct dd_context *dctx = dd_context(_pipe);
    struct pipe_context *pipe = dctx->pipe;
+   struct dd_draw_state *dstate = &dctx->draw_state;
 
-   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);
+   dstate->num_so_targets = num_targets;
+   safe_memcpy(dstate->so_targets, tgs, sizeof(*tgs) * num_targets);
+   safe_memcpy(dstate->so_offsets, offsets, sizeof(*offsets) * num_targets);
    pipe->set_stream_output_targets(pipe, num_targets, tgs, offsets);
 }
 
@@ -530,6 +601,19 @@ dd_context_destroy(struct pipe_context *_pipe)
    struct dd_context *dctx = dd_context(_pipe);
    struct pipe_context *pipe = dctx->pipe;
 
+   if (dctx->thread) {
+      mtx_lock(&dctx->mutex);
+      dctx->kill_thread = 1;
+      mtx_unlock(&dctx->mutex);
+      thrd_join(dctx->thread, NULL);
+      mtx_destroy(&dctx->mutex);
+      assert(!dctx->records);
+   }
+
+   if (dctx->fence) {
+      pipe->transfer_unmap(pipe, dctx->fence_transfer);
+      pipe_resource_reference(&dctx->fence, NULL);
+   }
    pipe->destroy(pipe);
    FREE(dctx);
 }
@@ -570,17 +654,28 @@ dd_context_transfer_unmap(struct pipe_context *_pipe,
 }
 
 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)
+dd_context_buffer_subdata(struct pipe_context *_pipe,
+                          struct pipe_resource *resource,
+                          unsigned usage, unsigned offset,
+                          unsigned size, const void *data)
+{
+   struct pipe_context *pipe = dd_context(_pipe)->pipe;
+
+   pipe->buffer_subdata(pipe, resource, usage, offset, size, data);
+}
+
+static void
+dd_context_texture_subdata(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);
+   pipe->texture_subdata(pipe, resource, level, usage, box, data,
+                         stride, layer_stride);
 }
 
 
@@ -589,11 +684,11 @@ dd_context_transfer_inline_write(struct pipe_context *_pipe,
  */
 
 static void
-dd_context_texture_barrier(struct pipe_context *_pipe)
+dd_context_texture_barrier(struct pipe_context *_pipe, unsigned flags)
 {
    struct pipe_context *pipe = dd_context(_pipe)->pipe;
 
-   pipe->texture_barrier(pipe);
+   pipe->texture_barrier(pipe, flags);
 }
 
 static void
@@ -604,6 +699,16 @@ dd_context_memory_barrier(struct pipe_context *_pipe, unsigned flags)
    pipe->memory_barrier(pipe, flags);
 }
 
+static bool
+dd_context_resource_commit(struct pipe_context *_pipe,
+                           struct pipe_resource *resource,
+                           unsigned level, struct pipe_box *box, bool commit)
+{
+   struct pipe_context *pipe = dd_context(_pipe)->pipe;
+
+   return pipe->resource_commit(pipe, resource, level, box, commit);
+}
+
 static void
 dd_context_get_sample_position(struct pipe_context *_pipe,
                                unsigned sample_count, unsigned sample_index,
@@ -632,6 +737,26 @@ dd_context_get_device_reset_status(struct pipe_context *_pipe)
    return pipe->get_device_reset_status(pipe);
 }
 
+static void
+dd_context_set_device_reset_callback(struct pipe_context *_pipe,
+                                     const struct pipe_device_reset_callback *cb)
+{
+   struct pipe_context *pipe = dd_context(_pipe)->pipe;
+
+   return pipe->set_device_reset_callback(pipe, cb);
+}
+
+static void
+dd_context_emit_string_marker(struct pipe_context *_pipe,
+                              const char *string, int len)
+{
+   struct dd_context *dctx = dd_context(_pipe);
+   struct pipe_context *pipe = dctx->pipe;
+
+   pipe->emit_string_marker(pipe, string, len);
+   dd_parse_apitrace_marker(string, len, &dctx->draw_state.apitrace_call_number);
+}
+
 static void
 dd_context_dump_debug_state(struct pipe_context *_pipe, FILE *stream,
                             unsigned flags)
@@ -641,6 +766,60 @@ dd_context_dump_debug_state(struct pipe_context *_pipe, FILE *stream,
    return pipe->dump_debug_state(pipe, stream, flags);
 }
 
+static uint64_t
+dd_context_create_texture_handle(struct pipe_context *_pipe,
+                                 struct pipe_sampler_view *view,
+                                 const struct pipe_sampler_state *state)
+{
+   struct pipe_context *pipe = dd_context(_pipe)->pipe;
+
+   return pipe->create_texture_handle(pipe, view, state);
+}
+
+static void
+dd_context_delete_texture_handle(struct pipe_context *_pipe, uint64_t handle)
+{
+   struct pipe_context *pipe = dd_context(_pipe)->pipe;
+
+   pipe->delete_texture_handle(pipe, handle);
+}
+
+static void
+dd_context_make_texture_handle_resident(struct pipe_context *_pipe,
+                                        uint64_t handle, bool resident)
+{
+   struct pipe_context *pipe = dd_context(_pipe)->pipe;
+
+   pipe->make_texture_handle_resident(pipe, handle, resident);
+}
+
+static uint64_t
+dd_context_create_image_handle(struct pipe_context *_pipe,
+                               const struct pipe_image_view *image)
+{
+   struct pipe_context *pipe = dd_context(_pipe)->pipe;
+
+   return pipe->create_image_handle(pipe, image);
+}
+
+static void
+dd_context_delete_image_handle(struct pipe_context *_pipe, uint64_t handle)
+{
+   struct pipe_context *pipe = dd_context(_pipe)->pipe;
+
+   pipe->delete_image_handle(pipe, handle);
+}
+
+static void
+dd_context_make_image_handle_resident(struct pipe_context *_pipe,
+                                      uint64_t handle, unsigned access,
+                                      bool resident)
+{
+   struct pipe_context *pipe = dd_context(_pipe)->pipe;
+
+   pipe->make_image_handle_resident(pipe, handle, access, resident);
+}
+
 struct pipe_context *
 dd_context_create(struct dd_screen *dscreen, struct pipe_context *pipe)
 {
@@ -650,23 +829,26 @@ dd_context_create(struct dd_screen *dscreen, struct pipe_context *pipe)
       return NULL;
 
    dctx = CALLOC_STRUCT(dd_context);
-   if (!dctx) {
-      pipe->destroy(pipe);
-      return NULL;
-   }
+   if (!dctx)
+      goto fail;
 
    dctx->pipe = pipe;
    dctx->base.priv = pipe->priv; /* expose wrapped priv data */
    dctx->base.screen = &dscreen->base;
+   dctx->base.stream_uploader = pipe->stream_uploader;
+   dctx->base.const_uploader = pipe->const_uploader;
 
    dctx->base.destroy = dd_context_destroy;
 
    CTX_INIT(render_condition);
    CTX_INIT(create_query);
+   CTX_INIT(create_batch_query);
    CTX_INIT(destroy_query);
    CTX_INIT(begin_query);
    CTX_INIT(end_query);
    CTX_INIT(get_query_result);
+   CTX_INIT(get_query_result_resource);
+   CTX_INIT(set_active_query_state);
    CTX_INIT(create_blend_state);
    CTX_INIT(bind_blend_state);
    CTX_INIT(delete_blend_state);
@@ -694,6 +876,9 @@ dd_context_create(struct dd_screen *dscreen, struct pipe_context *pipe)
    CTX_INIT(create_tes_state);
    CTX_INIT(bind_tes_state);
    CTX_INIT(delete_tes_state);
+   CTX_INIT(create_compute_state);
+   CTX_INIT(bind_compute_state);
+   CTX_INIT(delete_compute_state);
    CTX_INIT(create_vertex_elements_state);
    CTX_INIT(bind_vertex_elements_state);
    CTX_INIT(delete_vertex_elements_state);
@@ -712,7 +897,6 @@ dd_context_create(struct dd_screen *dscreen, struct pipe_context *pipe)
    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);
@@ -723,23 +907,65 @@ dd_context_create(struct dd_screen *dscreen, struct pipe_context *pipe)
    CTX_INIT(transfer_map);
    CTX_INIT(transfer_flush_region);
    CTX_INIT(transfer_unmap);
-   CTX_INIT(transfer_inline_write);
+   CTX_INIT(buffer_subdata);
+   CTX_INIT(texture_subdata);
    CTX_INIT(texture_barrier);
    CTX_INIT(memory_barrier);
+   CTX_INIT(resource_commit);
    /* 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(set_device_reset_callback);
    CTX_INIT(dump_debug_state);
+   CTX_INIT(emit_string_marker);
+   CTX_INIT(create_texture_handle);
+   CTX_INIT(delete_texture_handle);
+   CTX_INIT(make_texture_handle_resident);
+   CTX_INIT(create_image_handle);
+   CTX_INIT(delete_image_handle);
+   CTX_INIT(make_image_handle_resident);
 
    dd_init_draw_functions(dctx);
 
-   dctx->sample_mask = ~0;
+   dctx->draw_state.sample_mask = ~0;
+
+   if (dscreen->mode == DD_DETECT_HANGS_PIPELINED) {
+      dctx->fence = pipe_buffer_create(dscreen->screen, PIPE_BIND_CUSTOM,
+                                            PIPE_USAGE_STAGING, 4);
+      if (!dctx->fence)
+         goto fail;
+
+      dctx->mapped_fence = pipe_buffer_map(pipe, dctx->fence,
+                                           PIPE_TRANSFER_READ_WRITE |
+                                           PIPE_TRANSFER_PERSISTENT |
+                                           PIPE_TRANSFER_COHERENT,
+                                           &dctx->fence_transfer);
+      if (!dctx->mapped_fence)
+         goto fail;
+
+      *dctx->mapped_fence = 0;
+
+      (void) mtx_init(&dctx->mutex, mtx_plain);
+      dctx->thread = u_thread_create(dd_thread_pipelined_hang_detect, dctx);
+      if (!dctx->thread) {
+         mtx_destroy(&dctx->mutex);
+         goto fail;
+      }
+   }
+
    return &dctx->base;
+
+fail:
+   if (dctx) {
+      if (dctx->mapped_fence)
+         pipe_transfer_unmap(pipe, dctx->fence_transfer);
+      pipe_resource_reference(&dctx->fence, NULL);
+      FREE(dctx);
+   }
+   pipe->destroy(pipe);
+   return NULL;
 }