trace/rbug: Add new contexts functions to trace rbug
diff --git a/src/gallium/drivers/trace/tr_context.c b/src/gallium/drivers/trace/tr_context.c
index 2ad5ca4..b04cc2c 100644
--- a/src/gallium/drivers/trace/tr_context.c
+++ b/src/gallium/drivers/trace/tr_context.c
@@ -113,6 +113,28 @@
 }
 
 
+static INLINE void
+trace_context_draw_block(struct trace_context *tr_ctx, int flag)
+{
+   pipe_mutex_lock(tr_ctx->draw_mutex);
+
+   if (tr_ctx->draw_blocker & flag) {
+      tr_ctx->draw_blocked |= flag;
+
+      trace_rbug_notify_draw_blocked(tr_ctx);
+   }
+
+   /* wait for rbug to clear the blocked flag */
+   while (tr_ctx->draw_blocked & flag) {
+      tr_ctx->draw_blocked |= flag;
+      pipe_mutex_unlock(tr_ctx->draw_mutex);
+      /* TODO sleep or use conditional */
+      pipe_mutex_lock(tr_ctx->draw_mutex);
+   }
+
+   pipe_mutex_unlock(tr_ctx->draw_mutex);
+}
+
 static INLINE boolean
 trace_context_draw_arrays(struct pipe_context *_pipe,
                           unsigned mode, unsigned start, unsigned count)
@@ -124,6 +146,8 @@
    if (tr_ctx->curr.fs->disabled || tr_ctx->curr.vs->disabled)
       return 0;
 
+   trace_context_draw_block(tr_ctx, 1);
+
    trace_dump_call_begin("pipe_context", "draw_arrays");
 
    trace_dump_arg(ptr, pipe);
@@ -137,6 +161,8 @@
 
    trace_dump_call_end();
 
+   trace_context_draw_block(tr_ctx, 2);
+
    return result;
 }
 
@@ -156,6 +182,8 @@
    if (tr_ctx->curr.fs->disabled || tr_ctx->curr.vs->disabled)
       return 0;
 
+   trace_context_draw_block(tr_ctx, 1);
+
    trace_screen_user_buffer_update(_pipe->screen, indexBuffer);
 
    trace_dump_call_begin("pipe_context", "draw_elements");
@@ -173,6 +201,8 @@
 
    trace_dump_call_end();
 
+   trace_context_draw_block(tr_ctx, 2);
+
    return result;
 }
 
@@ -196,6 +226,8 @@
    if (tr_ctx->curr.fs->disabled || tr_ctx->curr.vs->disabled)
       return 0;
 
+   trace_context_draw_block(tr_ctx, 1);
+
    trace_screen_user_buffer_update(_pipe->screen, indexBuffer);
 
    trace_dump_call_begin("pipe_context", "draw_range_elements");
@@ -218,6 +250,8 @@
 
    trace_dump_call_end();
 
+   trace_context_draw_block(tr_ctx, 2);
+
    return result;
 }
 
@@ -782,6 +816,19 @@
    struct pipe_framebuffer_state unwrapped_state;
    unsigned i;
 
+   {
+      tr_ctx->curr.nr_cbufs = state->nr_cbufs;
+      for (i = 0; i < state->nr_cbufs; i++)
+         if (state->cbufs[i])
+            tr_ctx->curr.cbufs[i] = trace_texture(state->cbufs[i]->texture);
+         else
+            tr_ctx->curr.cbufs[i] = NULL;
+      if (state->zsbuf)
+         tr_ctx->curr.zsbuf = trace_texture(state->zsbuf->texture);
+      else
+         tr_ctx->curr.zsbuf = NULL;
+   }
+
    /* Unwrap the input state */
    memcpy(&unwrapped_state, state, sizeof(unwrapped_state));
    for(i = 0; i < state->nr_cbufs; ++i)
@@ -1113,6 +1160,12 @@
    return referenced;
 }
 
+static const struct debug_named_value rbug_blocker_flags[] = {
+   {"before", 1},
+   {"after", 2},
+   {NULL, 0},
+};
+
 struct pipe_context *
 trace_context_create(struct pipe_screen *_screen,
                      struct pipe_context *pipe)
@@ -1134,6 +1187,10 @@
    if(!tr_ctx)
       goto error1;
 
+   tr_ctx->draw_blocker = debug_get_flags_option("RBUG_BLOCK",
+                                                 rbug_blocker_flags,
+                                                 0);
+   pipe_mutex_init(tr_ctx->draw_mutex);
    pipe_mutex_init(tr_ctx->list_mutex);
    make_empty_list(&tr_ctx->shaders);
 
diff --git a/src/gallium/drivers/trace/tr_context.h b/src/gallium/drivers/trace/tr_context.h
index 86827f9..770e975 100644
--- a/src/gallium/drivers/trace/tr_context.h
+++ b/src/gallium/drivers/trace/tr_context.h
@@ -50,8 +50,16 @@
    struct {
       struct trace_shader *fs;
       struct trace_shader *vs;
+
+      unsigned nr_cbufs;
+      struct trace_texture *cbufs[PIPE_MAX_COLOR_BUFS];
+      struct trace_texture *zsbuf;
    } curr;
 
+   pipe_mutex draw_mutex;
+   int draw_blocker;
+   int draw_blocked;
+
    /* for list on screen */
    struct tr_list list;
 
@@ -75,6 +83,9 @@
 trace_context_create(struct pipe_screen *screen,
                      struct pipe_context *pipe);
 
+void
+trace_rbug_notify_draw_blocked(struct trace_context *tr_ctx);
+
 
 #ifdef __cplusplus
 }
diff --git a/src/gallium/drivers/trace/tr_rbug.c b/src/gallium/drivers/trace/tr_rbug.c
index 1b26f60..db9de8f 100644
--- a/src/gallium/drivers/trace/tr_rbug.c
+++ b/src/gallium/drivers/trace/tr_rbug.c
@@ -289,6 +289,147 @@
 }
 
 static int
+trace_rbug_context_info(struct trace_rbug *tr_rbug, struct rbug_header *header, uint32_t serial)
+{
+   struct rbug_proto_context_info *info = (struct rbug_proto_context_info *)header;
+
+   struct trace_screen *tr_scr = tr_rbug->tr_scr;
+   struct trace_context *tr_ctx = NULL;
+   rbug_texture_t cbufs[PIPE_MAX_COLOR_BUFS];
+   int i;
+
+   pipe_mutex_lock(tr_scr->list_mutex);
+   tr_ctx = trace_rbug_get_context_locked(tr_scr, info->context);
+
+   if (!tr_ctx) {
+      pipe_mutex_unlock(tr_scr->list_mutex);
+      return -ESRCH;
+   }
+
+   /* protect the pipe context */
+   pipe_mutex_lock(tr_ctx->draw_mutex);
+   trace_dump_call_lock();
+
+   for (i = 0; i < tr_ctx->curr.nr_cbufs; i++)
+      cbufs[i] = VOID2U64(tr_ctx->curr.cbufs[i]);
+
+   rbug_send_context_info_reply(tr_rbug->con, serial,
+                                VOID2U64(tr_ctx->curr.vs), VOID2U64(tr_ctx->curr.fs),
+                                cbufs, tr_ctx->curr.nr_cbufs, VOID2U64(tr_ctx->curr.zsbuf),
+                                tr_ctx->draw_blocker, tr_ctx->draw_blocked, NULL);
+
+   trace_dump_call_unlock();
+   pipe_mutex_unlock(tr_ctx->draw_mutex);
+
+   pipe_mutex_unlock(tr_scr->list_mutex);
+
+   return 0;
+}
+
+static int
+trace_rbug_context_draw_block(struct trace_rbug *tr_rbug, struct rbug_header *header, uint32_t serial)
+{
+   struct rbug_proto_context_draw_block *block = (struct rbug_proto_context_draw_block *)header;
+
+   struct trace_screen *tr_scr = tr_rbug->tr_scr;
+   struct trace_context *tr_ctx = NULL;
+
+   pipe_mutex_lock(tr_scr->list_mutex);
+   tr_ctx = trace_rbug_get_context_locked(tr_scr, block->context);
+
+   if (!tr_ctx) {
+      pipe_mutex_unlock(tr_scr->list_mutex);
+      return -ESRCH;
+   }
+
+   pipe_mutex_lock(tr_ctx->draw_mutex);
+   tr_ctx->draw_blocker |= block->block;
+   pipe_mutex_unlock(tr_ctx->draw_mutex);
+
+   pipe_mutex_unlock(tr_scr->list_mutex);
+
+   return 0;
+}
+
+static int
+trace_rbug_context_draw_step(struct trace_rbug *tr_rbug, struct rbug_header *header, uint32_t serial)
+{
+   struct rbug_proto_context_draw_step *step = (struct rbug_proto_context_draw_step *)header;
+
+   struct trace_screen *tr_scr = tr_rbug->tr_scr;
+   struct trace_context *tr_ctx = NULL;
+
+   pipe_mutex_lock(tr_scr->list_mutex);
+   tr_ctx = trace_rbug_get_context_locked(tr_scr, step->context);
+
+   if (!tr_ctx) {
+      pipe_mutex_unlock(tr_scr->list_mutex);
+      return -ESRCH;
+   }
+
+   pipe_mutex_lock(tr_ctx->draw_mutex);
+   tr_ctx->draw_blocked &= ~step->step;
+   pipe_mutex_unlock(tr_ctx->draw_mutex);
+
+   pipe_mutex_unlock(tr_scr->list_mutex);
+
+   return 0;
+}
+
+static int
+trace_rbug_context_draw_unblock(struct trace_rbug *tr_rbug, struct rbug_header *header, uint32_t serial)
+{
+   struct rbug_proto_context_draw_unblock *unblock = (struct rbug_proto_context_draw_unblock *)header;
+
+   struct trace_screen *tr_scr = tr_rbug->tr_scr;
+   struct trace_context *tr_ctx = NULL;
+
+   pipe_mutex_lock(tr_scr->list_mutex);
+   tr_ctx = trace_rbug_get_context_locked(tr_scr, unblock->context);
+
+   if (!tr_ctx) {
+      pipe_mutex_unlock(tr_scr->list_mutex);
+      return -ESRCH;
+   }
+
+   pipe_mutex_lock(tr_ctx->draw_mutex);
+   tr_ctx->draw_blocked &= ~unblock->unblock;
+   tr_ctx->draw_blocker &= ~unblock->unblock;
+   pipe_mutex_unlock(tr_ctx->draw_mutex);
+
+   pipe_mutex_unlock(tr_scr->list_mutex);
+
+   return 0;
+}
+
+static int
+trace_rbug_context_flush(struct trace_rbug *tr_rbug, struct rbug_header *header, uint32_t serial)
+{
+   struct rbug_proto_context_flush *flush = (struct rbug_proto_context_flush *)header;
+
+   struct trace_screen *tr_scr = tr_rbug->tr_scr;
+   struct trace_context *tr_ctx = NULL;
+
+   pipe_mutex_lock(tr_scr->list_mutex);
+   tr_ctx = trace_rbug_get_context_locked(tr_scr, flush->context);
+
+   if (!tr_ctx) {
+      pipe_mutex_unlock(tr_scr->list_mutex);
+      return -ESRCH;
+   }
+
+   /* protect the pipe context */
+   trace_dump_call_lock();
+
+   tr_ctx->pipe->flush(tr_ctx->pipe, flush->flags, NULL);
+
+   trace_dump_call_unlock();
+   pipe_mutex_unlock(tr_scr->list_mutex);
+
+   return 0;
+}
+
+static int
 trace_rbug_shader_list(struct trace_rbug *tr_rbug, struct rbug_header *header, uint32_t serial)
 {
    struct rbug_proto_shader_list *list = (struct rbug_proto_shader_list *)header;
@@ -512,6 +653,21 @@
       case RBUG_OP_CONTEXT_LIST:
          ret = trace_rbug_context_list(tr_rbug, header, serial);
          break;
+      case RBUG_OP_CONTEXT_INFO:
+         ret = trace_rbug_context_info(tr_rbug, header, serial);
+         break;
+      case RBUG_OP_CONTEXT_DRAW_BLOCK:
+         ret = trace_rbug_context_draw_block(tr_rbug, header, serial);
+         break;
+      case RBUG_OP_CONTEXT_DRAW_STEP:
+         ret = trace_rbug_context_draw_step(tr_rbug, header, serial);
+         break;
+      case RBUG_OP_CONTEXT_DRAW_UNBLOCK:
+         ret = trace_rbug_context_draw_unblock(tr_rbug, header, serial);
+         break;
+      case RBUG_OP_CONTEXT_FLUSH:
+         ret = trace_rbug_context_flush(tr_rbug, header, serial);
+         break;
       case RBUG_OP_SHADER_LIST:
          ret = trace_rbug_shader_list(tr_rbug, header, serial);
          break;
@@ -610,7 +766,7 @@
 struct trace_rbug *
 trace_rbug_start(struct trace_screen *tr_scr)
 {
-   struct trace_rbug *tr_rbug = MALLOC_STRUCT(trace_rbug);
+   struct trace_rbug *tr_rbug = CALLOC_STRUCT(trace_rbug);
    if (!tr_rbug)
       return NULL;
 
@@ -634,3 +790,14 @@
 
    return;
 }
+
+void
+trace_rbug_notify_draw_blocked(struct trace_context *tr_ctx)
+{
+   struct trace_screen *tr_scr = trace_screen(tr_ctx->base.screen);
+   struct trace_rbug *tr_rbug = tr_scr->rbug;
+
+   if (tr_rbug && tr_rbug->con)
+      rbug_send_context_draw_blocked(tr_rbug->con,
+                                     VOID2U64(tr_ctx), tr_ctx->draw_blocked, NULL);
+}