[Mesa-dev] [PATCH 10/10] RFC: gallium: add resequencer driver (INCOMPLETE)

Rob Clark robdclark at gmail.com
Tue Jun 14 15:58:02 UTC 2016


From: Rob Clark <robclark at freedesktop.org>

NOTE: the mako templates turned out to be a bit more hairy than
expected.. maybe they would be better split out, or maybe there
is something that could be done more simply.  It more or less is
my first time doing much with mako.  But, I have changed how the
state tracking / emit / replay works a few times as I went, and
making a couple line change in a template and regenerating is
much nicer than manually refactoring the code ;-)

Note that since it might be easier to see how things work from
the resulting code:

  rsq_state.h -> http://hastebin.com/erupecivab.c
  rsq_state.c -> http://hastebin.com/cokenawanu.c

---
 configure.ac                                       |   1 +
 src/gallium/drivers/resequencer/.gitignore         |   2 +
 src/gallium/drivers/resequencer/Makefile.am        |  44 ++
 src/gallium/drivers/resequencer/Makefile.sources   |  23 +
 src/gallium/drivers/resequencer/rsq_batch.c        | 144 +++++
 src/gallium/drivers/resequencer/rsq_batch.h        |  71 +++
 src/gallium/drivers/resequencer/rsq_context.c      | 457 ++++++++++++++++
 src/gallium/drivers/resequencer/rsq_context.h      |  84 +++
 src/gallium/drivers/resequencer/rsq_draw.c         | 230 ++++++++
 src/gallium/drivers/resequencer/rsq_draw.h         |  40 ++
 src/gallium/drivers/resequencer/rsq_fence.c        |  48 ++
 src/gallium/drivers/resequencer/rsq_fence.h        |  43 ++
 src/gallium/drivers/resequencer/rsq_public.h       |  68 +++
 src/gallium/drivers/resequencer/rsq_query.c        | 148 +++++
 src/gallium/drivers/resequencer/rsq_query.h        |  32 ++
 src/gallium/drivers/resequencer/rsq_resource.c     | 222 ++++++++
 src/gallium/drivers/resequencer/rsq_resource.h     |  60 ++
 src/gallium/drivers/resequencer/rsq_screen.c       | 186 +++++++
 src/gallium/drivers/resequencer/rsq_screen.h       |  50 ++
 src/gallium/drivers/resequencer/rsq_state.py       | 607 +++++++++++++++++++++
 .../drivers/resequencer/rsq_state_helpers.h        | 219 ++++++++
 src/gallium/drivers/resequencer/rsq_surface.c      | 107 ++++
 src/gallium/drivers/resequencer/rsq_surface.h      |  72 +++
 23 files changed, 2958 insertions(+)
 create mode 100644 src/gallium/drivers/resequencer/.gitignore
 create mode 100644 src/gallium/drivers/resequencer/Makefile.am
 create mode 100644 src/gallium/drivers/resequencer/Makefile.sources
 create mode 100644 src/gallium/drivers/resequencer/rsq_batch.c
 create mode 100644 src/gallium/drivers/resequencer/rsq_batch.h
 create mode 100644 src/gallium/drivers/resequencer/rsq_context.c
 create mode 100644 src/gallium/drivers/resequencer/rsq_context.h
 create mode 100644 src/gallium/drivers/resequencer/rsq_draw.c
 create mode 100644 src/gallium/drivers/resequencer/rsq_draw.h
 create mode 100644 src/gallium/drivers/resequencer/rsq_fence.c
 create mode 100644 src/gallium/drivers/resequencer/rsq_fence.h
 create mode 100644 src/gallium/drivers/resequencer/rsq_public.h
 create mode 100644 src/gallium/drivers/resequencer/rsq_query.c
 create mode 100644 src/gallium/drivers/resequencer/rsq_query.h
 create mode 100644 src/gallium/drivers/resequencer/rsq_resource.c
 create mode 100644 src/gallium/drivers/resequencer/rsq_resource.h
 create mode 100644 src/gallium/drivers/resequencer/rsq_screen.c
 create mode 100644 src/gallium/drivers/resequencer/rsq_screen.h
 create mode 100644 src/gallium/drivers/resequencer/rsq_state.py
 create mode 100644 src/gallium/drivers/resequencer/rsq_state_helpers.h
 create mode 100644 src/gallium/drivers/resequencer/rsq_surface.c
 create mode 100644 src/gallium/drivers/resequencer/rsq_surface.h

diff --git a/configure.ac b/configure.ac
index c492e15..0dbfc32 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2644,6 +2644,7 @@ AC_CONFIG_FILES([Makefile
 		src/gallium/drivers/llvmpipe/Makefile
 		src/gallium/drivers/noop/Makefile
 		src/gallium/drivers/nouveau/Makefile
+		src/gallium/drivers/resequencer/Makefile
 		src/gallium/drivers/r300/Makefile
 		src/gallium/drivers/r600/Makefile
 		src/gallium/drivers/radeon/Makefile
diff --git a/src/gallium/drivers/resequencer/.gitignore b/src/gallium/drivers/resequencer/.gitignore
new file mode 100644
index 0000000..c827305
--- /dev/null
+++ b/src/gallium/drivers/resequencer/.gitignore
@@ -0,0 +1,2 @@
+rsq_state.c
+rsq_state.h
diff --git a/src/gallium/drivers/resequencer/Makefile.am b/src/gallium/drivers/resequencer/Makefile.am
new file mode 100644
index 0000000..503aa98
--- /dev/null
+++ b/src/gallium/drivers/resequencer/Makefile.am
@@ -0,0 +1,44 @@
+# Copyright © 2016 Red Hat.
+#
+# 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
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# 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
+# NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS 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 Makefile.sources
+include $(top_srcdir)/src/gallium/Automake.inc
+
+AM_CPPFLAGS = \
+	$(GALLIUM_DRIVER_CFLAGS) \
+	$(LIBDRM_CFLAGS)
+
+noinst_LTLIBRARIES = libresequencer.la
+
+PYTHON_GEN = $(AM_V_GEN)$(PYTHON2) $(PYTHON_FLAGS)
+
+# NOTE: dependency on rsq_state.h seems to be required to ensure it
+# is regenerated before other files that #include it are built :-/
+rsq_state.c: rsq_state.py rsq_state.h
+	$(MKDIR_GEN)
+	$(PYTHON_GEN) $(srcdir)/rsq_state.py -c > $@ || ($(RM) $@; false)
+
+rsq_state.h: rsq_state.py
+	$(MKDIR_GEN)
+	$(PYTHON_GEN) $(srcdir)/rsq_state.py -h > $@ || ($(RM) $@; false)
+
+libresequencer_la_SOURCES = $(C_SOURCES) $(C_GENERATED_SOURCES)
diff --git a/src/gallium/drivers/resequencer/Makefile.sources b/src/gallium/drivers/resequencer/Makefile.sources
new file mode 100644
index 0000000..42ffbcd
--- /dev/null
+++ b/src/gallium/drivers/resequencer/Makefile.sources
@@ -0,0 +1,23 @@
+C_SOURCES := \
+	rsq_batch.c \
+	rsq_batch.h \
+	rsq_context.c \
+	rsq_context.h \
+	rsq_draw.c \
+	rsq_draw.h \
+	rsq_fence.c \
+	rsq_fence.h \
+	rsq_public.h \
+	rsq_query.c \
+	rsq_query.h \
+	rsq_resource.c \
+	rsq_resource.h \
+	rsq_screen.c \
+	rsq_screen.h \
+	rsq_state.h \
+	rsq_surface.c \
+	rsq_surface.h
+
+C_GENERATED_SOURCES := \
+	rsq_state.c \
+	rsq_state.h
diff --git a/src/gallium/drivers/resequencer/rsq_batch.c b/src/gallium/drivers/resequencer/rsq_batch.c
new file mode 100644
index 0000000..35b1919
--- /dev/null
+++ b/src/gallium/drivers/resequencer/rsq_batch.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright © 2016 Red Hat
+ *
+ * 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
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 "util/u_memory.h"
+
+#include "rsq_batch.h"
+#include "rsq_context.h"
+#include "rsq_draw.h"
+#include "rsq_state.h"
+
+static struct rsq_batch_chunk * chunk_alloc(struct rsq_context *ctx)
+{
+   struct rsq_batch_chunk *chunk = util_slab_alloc(&ctx->slab);
+   chunk->rd_idx = chunk->wr_idx = 0;
+   chunk->next = NULL;
+   return chunk;
+}
+
+struct rsq_batch * rsq_batch_create(struct rsq_context *ctx)
+{
+   struct rsq_batch *batch = CALLOC_STRUCT(rsq_batch);
+
+   if (!batch)
+      return NULL;
+
+   pipe_reference_init(&batch->reference, 1);
+   batch->ctx = ctx;
+
+   batch->first = batch->current = chunk_alloc(ctx);
+
+   return batch;
+}
+
+void _rsq_batch_destroy(struct rsq_batch *batch)
+{
+   struct rsq_batch_chunk *current = batch->first;
+
+   while (current) {
+      struct rsq_batch_chunk *next = current->next;
+      util_slab_free(&batch->ctx->slab, current);
+      current = next;
+   }
+
+   free(batch);
+}
+
+void * rsq_batch_emit_buf(struct rsq_batch *batch, unsigned sz)
+{
+   struct rsq_batch_chunk *chunk = batch->current;
+   void *ptr;
+
+   if ((chunk->wr_idx + sz) > sizeof(chunk->buf)) {
+      struct rsq_batch_chunk *n = chunk_alloc(batch->ctx);
+      chunk->next = n;
+      chunk = batch->current = n;
+   }
+
+   ptr = &chunk->buf[chunk->wr_idx];
+   chunk->wr_idx += sz;
+
+   return ptr;
+}
+
+void * rsq_batch_consume_buf(struct rsq_batch *batch, unsigned sz)
+{
+   struct rsq_batch_chunk *chunk = batch->current;
+   void *ptr;
+
+   ptr = &chunk->buf[chunk->rd_idx];
+   chunk->rd_idx += sz;
+
+   /* this should only happen if we have mismatched emit's and consumes: */
+   debug_assert(chunk->rd_idx <= chunk->wr_idx);
+
+   if (chunk->rd_idx == chunk->wr_idx)
+      batch->current = chunk->next;
+
+   return ptr;
+}
+
+void rsq_batch_flush(struct rsq_batch *batch)
+{
+   if (!batch || batch->flushed)
+      return;
+
+   /* TODO if we had out-of-order already, this is where we'd need
+    * to recursively flush our dependencies..
+    */
+
+   /* reset position to beginning: */
+   batch->current = batch->first;
+
+   if (batch->current->wr_idx == 0)
+      return;
+
+   while (batch->current) {
+      enum rsq_state_id id = rsq_batch_consume_uint(batch);
+      switch (id) {
+      case rsq_string_marker_cmd:
+         rsq_replay_emit_string_marker(batch);
+         break;
+      case rsq_draw_cmd:
+         rsq_replay_draw_vbo(batch);
+         break;
+      case rsq_clear_cmd:
+         rsq_replay_clear(batch);
+         break;
+      case rsq_launch_grid_cmd:
+         rsq_replace_launch_grid(batch);
+         break;
+      case rsq_copy_region_cmd:
+         rsq_replay_copy_region(batch);
+         break;
+      case rsq_blit_cmd:
+         rsq_replay_blit(batch);
+         break;
+      default:
+         rsq_context_replay(batch, id);
+         break;
+      }
+   }
+
+   batch->flushed = true;
+}
diff --git a/src/gallium/drivers/resequencer/rsq_batch.h b/src/gallium/drivers/resequencer/rsq_batch.h
new file mode 100644
index 0000000..39e80b4
--- /dev/null
+++ b/src/gallium/drivers/resequencer/rsq_batch.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright © 2016 Red Hat
+ *
+ * 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
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 RSQ_BATCH_H
+#define RSQ_BATCH_H
+
+#include "util/u_inlines.h"
+
+struct rsq_batch_chunk {
+   unsigned rd_idx, wr_idx;
+   struct rsq_batch_chunk *next;
+   uint8_t buf[4096];             /* TODO what is a reasonable size? */
+};
+
+struct rsq_batch {
+   struct pipe_reference reference;
+   struct rsq_context *ctx;
+   bool flushed;
+   struct rsq_batch_chunk *current, *first;
+};
+
+struct rsq_batch * rsq_batch_create(struct rsq_context *ctx);
+void _rsq_batch_destroy(struct rsq_batch *batch);
+
+static inline void
+rsq_batch_reference(struct rsq_batch **ptr, struct rsq_batch *batch)
+{
+   if (pipe_reference(&(*ptr)->reference, &batch->reference))
+      _rsq_batch_destroy(*ptr);
+   *ptr = batch;
+}
+
+void *rsq_batch_emit_buf(struct rsq_batch *batch, unsigned sz);
+
+static inline void rsq_batch_emit_uint(struct rsq_batch *batch, unsigned val)
+{
+   unsigned *ptr = rsq_batch_emit_buf(batch, sizeof(*ptr));
+   *ptr = val;
+}
+
+void *rsq_batch_consume_buf(struct rsq_batch *batch, unsigned sz);
+
+static inline unsigned rsq_batch_consume_uint(struct rsq_batch *batch)
+{
+   unsigned *ptr = rsq_batch_consume_buf(batch, sizeof(*ptr));
+   return *ptr;
+}
+
+void rsq_batch_flush(struct rsq_batch *batch);
+
+#endif /* RSQ_BATCH_H */
diff --git a/src/gallium/drivers/resequencer/rsq_context.c b/src/gallium/drivers/resequencer/rsq_context.c
new file mode 100644
index 0000000..ac3eb13
--- /dev/null
+++ b/src/gallium/drivers/resequencer/rsq_context.c
@@ -0,0 +1,457 @@
+/*
+ * Copyright © 2016 Red Hat
+ *
+ * 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
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 "util/u_memory.h"
+
+#include "rsq_batch.h"
+#include "rsq_context.h"
+#include "rsq_draw.h"
+#include "rsq_resource.h"
+#include "rsq_state.h"
+#include "rsq_surface.h"
+#include "rsq_query.h"
+
+static void rsq_context_destroy(struct pipe_context *pctx)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+
+   rsq_batch_flush(ctx->batch);
+   rsq_batch_reference(&ctx->batch, NULL);
+
+   ctx->drv->destroy(ctx->drv);
+
+   util_slab_destroy(&ctx->slab);
+
+   free(ctx);
+}
+
+static void rsq_set_debug_callback(struct pipe_context *pctx,
+                                   const struct pipe_debug_callback *cb)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+   ctx->drv->set_debug_callback(ctx->drv, cb);
+}
+
+static void rsq_get_sample_position(struct pipe_context *pctx,
+                                    unsigned sample_count,
+                                    unsigned sample_index,
+                                    float *out_value)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+   ctx->drv->get_sample_position(ctx->drv, sample_count, sample_index, out_value);
+}
+
+static enum pipe_reset_status rsq_get_device_reset_status(struct pipe_context *pctx)
+{
+   /* presumably this is async to rendering and doesn't require flushing? */
+   struct rsq_context *ctx = rsq_context(pctx);
+   return ctx->drv->get_device_reset_status(ctx->drv);
+}
+
+static void rsq_dump_debug_state(struct pipe_context *pctx, FILE *stream,
+                                 unsigned flags)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+   ctx->drv->dump_debug_state(ctx->drv, stream, flags);
+}
+
+/*
+ * Handle sampler-views manually since it doesn't quite fit the CSO mold.
+ * Perhaps should be refactored to be a normal CSO?
+ */
+
+struct rsq_sampler_view {
+   struct pipe_sampler_view base;
+   unsigned seqno;
+   struct pipe_sampler_view *drv;
+};
+
+static inline struct rsq_sampler_view *
+rsq_sampler_view(struct pipe_sampler_view *pview)
+{
+   return (struct rsq_sampler_view *)pview;
+}
+
+static struct pipe_sampler_view *
+rsq_create_sampler_view(struct pipe_context *pctx,
+                        struct pipe_resource *texture,
+                        const struct pipe_sampler_view *templat)
+{
+   struct rsq_sampler_view *view = CALLOC_STRUCT(rsq_sampler_view);
+   if (!view)
+      return NULL;
+   view->base = *templat;
+   pipe_reference_init(&view->base.reference, 1);
+   pipe_reference(NULL, &texture->reference);
+   view->base.texture = texture;
+   view->base.context = pctx;
+   return &view->base;
+}
+
+static void rsq_sampler_view_destroy(struct pipe_context *pctx,
+                                     struct pipe_sampler_view *pview)
+{
+   struct rsq_sampler_view *view = rsq_sampler_view(pview);
+   pipe_sampler_view_reference(&view->drv, NULL);
+   free(view);
+}
+
+static struct pipe_sampler_view *
+rsq_sampler_view_validate(struct pipe_sampler_view *pview)
+{
+   struct rsq_sampler_view *view = rsq_sampler_view(pview);
+
+   if (!pview)
+      return NULL;
+
+   if (view->seqno != seqno(pview->texture))
+      pipe_sampler_view_reference(&view->drv, NULL);
+
+   if (!view->drv) {
+      struct rsq_context *ctx = rsq_context(pview->context);
+      view->drv = ctx->drv->create_sampler_view(ctx->drv,
+                                                unwrap(pview->texture),
+                                                pview);
+      view->seqno = seqno(pview->texture);
+   }
+
+   return view->drv;
+}
+
+static void rsq_set_sampler_views(struct pipe_context *pctx, unsigned shader,
+                                  unsigned start_slot, unsigned num_views,
+                                  struct pipe_sampler_view **pviews)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+
+   debug_assert(start_slot == 0);
+
+   for (unsigned i = 0; i < num_views; i++) {
+      pipe_sampler_view_reference(&ctx->sampler_view[shader][i], pviews[i]);
+      ctx->dirty_sampler_view[shader] |= (1 << i);
+      if (pviews[i])
+         ctx->valid_sampler_view[shader] |= (1 << i);
+      else
+         ctx->valid_sampler_view[shader] &= ~(1 << i);
+   }
+
+   ctx->state.dirty |= (1 << rsq_sampler_view_id);
+   ctx->dirty_sampler_view_shader |= (1 << shader);
+   if (ctx->valid_sampler_view[shader])
+      ctx->valid_sampler_view_shader |= (1 << shader);
+   else
+      ctx->valid_sampler_view_shader &= ~(1 << shader);
+}
+
+/*
+ * Handle stream-output-target manually since it doesn't quite fit the
+ * CSO mold..  perhaps should be refactored into a normal CSO?
+ */
+
+struct rsq_stream_output_target {
+   struct pipe_stream_output_target base;
+   unsigned seqno;
+   struct pipe_stream_output_target *drv;
+};
+
+static inline struct rsq_stream_output_target *
+rsq_stream_output_target(struct pipe_stream_output_target *ptarget)
+{
+   return (struct rsq_stream_output_target *)ptarget;
+}
+
+static struct pipe_stream_output_target *
+rsq_create_stream_output_target(struct pipe_context *pctx,
+                                struct pipe_resource *prsc,
+                                unsigned buffer_offset,
+                                unsigned buffer_size)
+{
+   struct rsq_stream_output_target *target = CALLOC_STRUCT(rsq_stream_output_target);
+   if (!target)
+      return NULL;
+   pipe_reference_init(&target->base.reference, 1);
+   pipe_resource_reference(&target->base.buffer, prsc);
+   target->base.context = pctx;
+   target->base.buffer_offset = buffer_offset;
+   target->base.buffer_size = buffer_size;
+   return &target->base;
+}
+
+static void rsq_stream_output_target_destroy(struct pipe_context *pctx,
+                                             struct pipe_stream_output_target *ptarget)
+{
+   struct rsq_stream_output_target *target = rsq_stream_output_target(ptarget);
+   pipe_so_target_reference(&target->drv, NULL);
+   free(target);
+}
+
+static struct pipe_stream_output_target *
+rsq_stream_output_target_validate(struct pipe_stream_output_target *ptarget)
+{
+   struct rsq_stream_output_target *target = rsq_stream_output_target(ptarget);
+
+   if (!ptarget)
+      return NULL;
+
+   if (target->seqno != seqno(ptarget->buffer))
+      pipe_so_target_reference(&target->drv, NULL);
+
+   if (!target->drv) {
+      struct rsq_context *ctx = rsq_context(ptarget->context);
+      target->drv = ctx->drv->create_stream_output_target(ctx->drv,
+                                                          unwrap(ptarget->buffer),
+                                                          ptarget->buffer_offset,
+                                                          ptarget->buffer_size);
+      target->seqno = seqno(ptarget->buffer);
+   }
+
+   return target->drv;
+}
+
+static void rsq_set_stream_output_targets(struct pipe_context *pctx,
+                                          unsigned num_targets,
+                                          struct pipe_stream_output_target **ptargets,
+                                          const unsigned *offsets)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+   unsigned i;
+
+   for (i = 0; i < num_targets; i++) {
+      pipe_so_target_reference(&ctx->so_targets[i], ptargets[i]);
+      ctx->so_offsets[i] = offsets[i];
+   }
+
+   for ( ; i < ARRAY_SIZE(ctx->so_targets); i++)
+      pipe_so_target_reference(&ctx->so_targets[i], NULL);
+
+   ctx->nr_so_targets = num_targets;
+   ctx->state.dirty |= (1 << rsq_stream_output_target_id);
+}
+
+/**
+ * Emit state.  This serializes all the dirty state into the current batch,
+ * for example prior to emitting a draw cmd.  This includes state which is
+ * implicitly dirty due to a shadowed resource.
+ */
+void rsq_context_emit(struct pipe_context *pctx)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+   unsigned idx_mask, shader_mask;
+   int idx, shader;
+
+   /* detect if state is dirty due to resource shadowing: */
+   if (unlikely(ctx->dirty_clone)) {
+      shader_mask = ctx->valid_sampler_view_shader;
+      while ((shader = util_last_bit(shader_mask) - 1) >= 0) {
+         idx_mask = ctx->valid_sampler_view[shader];
+         while ((idx = util_last_bit(idx_mask) - 1) >= 0) {
+            struct pipe_sampler_view *pview = ctx->sampler_view[shader][idx];
+            if (!pview)
+               continue;
+            struct rsq_sampler_view *view = rsq_sampler_view(pview);
+            if (view->seqno != seqno(pview->texture)) {
+               ctx->dirty_sampler_view_shader |= (1 << shader);
+               ctx->dirty_sampler_view[shader] |= (1 << idx);
+               ctx->state.dirty |= (1 << rsq_sampler_view_id);
+               break;
+            }
+            idx_mask &= ~(1 << idx);
+         }
+         shader_mask &= ~(1 << shader);
+      }
+   }
+
+   if (ctx->state.dirty & (1 << rsq_sampler_view_id)) {
+      shader_mask = ctx->dirty_sampler_view_shader;
+      while ((shader = util_last_bit(shader_mask) - 1) >= 0) {
+         idx_mask = ctx->dirty_sampler_view[shader];
+         while ((idx = util_last_bit(idx_mask) - 1) >= 0) {
+            struct pipe_sampler_view **ptr;
+            struct pipe_sampler_view *pview =
+               rsq_sampler_view_validate(ctx->sampler_view[shader][idx]);
+
+            rsq_batch_emit_uint(ctx->batch, rsq_sampler_view_id);
+            rsq_batch_emit_uint(ctx->batch, shader);
+            rsq_batch_emit_uint(ctx->batch, idx);
+            ptr = rsq_batch_emit_buf(ctx->batch, sizeof(*ptr));
+            *ptr = NULL;
+            pipe_sampler_view_reference(ptr, pview);
+
+            idx_mask &= ~(1 << idx);
+         }
+         ctx->dirty_sampler_view[shader] = 0;
+         shader_mask &= ~(1 << shader);
+      }
+      ctx->dirty_sampler_view_shader = 0;
+   }
+
+   /* detect if state is dirty due to resource shadowing: */
+   if (unlikely(ctx->dirty_clone)) {
+      for (unsigned idx = 0; idx < ctx->nr_so_targets; idx++) {
+         struct pipe_stream_output_target *ptarget = ctx->so_targets[idx];
+         if (!ptarget)
+            continue;
+         struct rsq_stream_output_target *target = rsq_stream_output_target(ptarget);
+         if (target->seqno != seqno(ptarget->buffer)) {
+            ctx->state.dirty |= (1 << rsq_stream_output_target_id);
+            break;
+         }
+      }
+   }
+
+   if (ctx->state.dirty & (1 << rsq_stream_output_target_id)) {
+      struct pipe_stream_output_target **ptr;
+      unsigned *offsets;
+
+      rsq_batch_emit_uint(ctx->batch, rsq_stream_output_target_id);
+      rsq_batch_emit_uint(ctx->batch, ctx->nr_so_targets);
+
+      ptr = rsq_batch_emit_buf(ctx->batch, sizeof(*ptr) * ctx->nr_so_targets);
+      for (unsigned idx = 0; idx < ctx->nr_so_targets; idx++) {
+         struct pipe_stream_output_target *ptarget =
+            rsq_stream_output_target_validate(ctx->so_targets[idx]);
+         ptr[idx] = NULL;
+         pipe_so_target_reference(&ptr[idx], ptarget);
+      }
+
+      offsets = rsq_batch_emit_buf(ctx->batch, sizeof(*offsets) * ctx->nr_so_targets);
+      memcpy(offsets, ctx->so_offsets, sizeof(*offsets) * ctx->nr_so_targets);
+   }
+
+   /* Most of it is handled by the generated code: */
+   rsq_state_emit(pctx);
+
+   ctx->dirty_clone = false;
+}
+
+void rsq_context_replay(struct rsq_batch *batch, enum rsq_state_id id)
+{
+   struct rsq_context *ctx = batch->ctx;
+
+   switch (id) {
+   /* specially handled state: */
+   case rsq_sampler_view_id: {
+      unsigned shader = rsq_batch_consume_uint(batch);
+      unsigned idx = rsq_batch_consume_uint(batch);
+      struct pipe_sampler_view **ptr = rsq_batch_consume_buf(batch, sizeof(*ptr));
+
+      ctx->drv->set_sampler_views(ctx->drv, shader, idx, 1, ptr);
+      pipe_sampler_view_reference(ptr, NULL);
+
+      break;
+   }
+   case rsq_stream_output_target_id: {
+      unsigned nr_so_targets = rsq_batch_consume_uint(batch);
+      struct pipe_stream_output_target **ptr =
+         rsq_batch_consume_buf(ctx->batch, sizeof(*ptr) * nr_so_targets);
+      unsigned *offsets =
+         rsq_batch_consume_buf(ctx->batch, sizeof(*offsets) * nr_so_targets);
+
+      ctx->drv->set_stream_output_targets(ctx->drv, nr_so_targets,
+                                          ptr, offsets);
+
+      for (unsigned idx; idx < nr_so_targets; idx++)
+         pipe_so_target_reference(&ptr[idx], NULL);
+
+      break;
+   }
+   default:
+      rsq_state_replay(batch, id);
+   }
+}
+
+/**
+ * Update current batch when framebuffer state has changed
+ */
+void rsq_context_update_batch(struct pipe_context *pctx,
+                              const struct pipe_framebuffer_state *pfb)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+
+   /* TODO, no out of order yet, otherwise we'd use *pfb as key
+    * into hashtable
+    *
+    * TODO we might need to sanitize the key w/ surf seqno's?
+    * At least if the batch is not holding a ref to the surface..
+    */
+
+   rsq_batch_flush(ctx->batch);
+   rsq_batch_reference(&ctx->batch, NULL);
+
+   ctx->batch = rsq_batch_create(ctx);
+}
+
+struct pipe_context * rsq_context_create(struct pipe_screen *pscreen,
+                                         void *priv, unsigned flags)
+{
+   struct rsq_screen *screen = rsq_screen(pscreen);
+   struct rsq_context *ctx = CALLOC_STRUCT(rsq_context);
+
+   if (!ctx)
+      return NULL;
+
+   ctx->drv = screen->drv->context_create(screen->drv, ctx, flags);
+   if (!ctx->drv) {
+      free(ctx);
+      return NULL;
+   }
+
+   ctx->screen = screen;
+
+   struct pipe_context *pctx = &ctx->base;
+   pctx->priv = priv;
+   pctx->screen = pscreen;
+   pctx->destroy = rsq_context_destroy;
+
+   CTX_INIT(set_debug_callback);
+   CTX_INIT(get_sample_position);
+   CTX_INIT(get_device_reset_status);
+   CTX_INIT(dump_debug_state);
+
+   pctx->create_surface = rsq_create_surface;
+   pctx->surface_destroy = rsq_surface_destroy;
+
+   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(set_sampler_views);
+
+//   CTX_INIT(texture_barrier);
+//   CTX_INIT(memory_barrier);
+
+//   CTX_INIT(create_video_codec);
+//   CTX_INIT(create_video_buffer);
+
+   rsq_draw_context_init(pctx);
+   rsq_resource_context_init(pctx);
+   rsq_query_context_init(pctx);
+   rsq_state_context_init(pctx);
+
+   util_slab_create(&ctx->slab, sizeof(struct rsq_batch_chunk),
+                    16, UTIL_SLAB_SINGLETHREADED);
+
+   return pctx;
+}
diff --git a/src/gallium/drivers/resequencer/rsq_context.h b/src/gallium/drivers/resequencer/rsq_context.h
new file mode 100644
index 0000000..1470dbd
--- /dev/null
+++ b/src/gallium/drivers/resequencer/rsq_context.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright © 2016 Red Hat
+ *
+ * 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
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 RSQ_CONTEXT_H
+#define RSQ_CONTEXT_H
+
+#include "pipe/p_context.h"
+#include "util/u_slab.h"
+
+#include "rsq_screen.h"
+#include "rsq_state.h"
+
+struct rsq_context {
+   struct pipe_context base;
+
+   struct rsq_screen *screen;
+
+   struct pipe_context *drv;      /* wrapped driver ctx */
+
+   unsigned surf_cnt;
+
+   /* has a resource been cloned since last emit?  Skip dirty-due-to-clone
+    * checking otherwise:
+    */
+   bool dirty_clone;
+
+   /* state handled by autogenerated code: */
+   struct rsq_state state;
+
+   /* state we have to handle manually: */
+   unsigned short dirty_sampler_view_shader;
+   unsigned short valid_sampler_view_shader;
+   unsigned dirty_sampler_view[PIPE_SHADER_TYPES];
+   unsigned valid_sampler_view[PIPE_SHADER_TYPES];
+   struct pipe_sampler_view *sampler_view[PIPE_SHADER_TYPES][PIPE_MAX_SAMPLERS];
+
+   struct pipe_stream_output_target *so_targets[PIPE_MAX_SO_BUFFERS];
+   unsigned so_offsets[PIPE_MAX_SO_BUFFERS];
+   unsigned nr_so_targets;
+
+   /* the current batch: */
+   struct rsq_batch *batch;
+
+   /* slab for batch-chunk allocations: */
+   struct util_slab_mempool slab;
+};
+
+static inline struct rsq_context * rsq_context(struct pipe_context *pctx)
+{
+   return (struct rsq_context *)pctx;
+}
+
+void rsq_context_emit(struct pipe_context *pctx);
+void rsq_context_replay(struct rsq_batch *batch, enum rsq_state_id id);
+void rsq_context_update_batch(struct pipe_context *pctx,
+                              const struct pipe_framebuffer_state *pfb);
+
+struct pipe_context * rsq_context_create(struct pipe_screen *screen,
+                                         void *priv, unsigned flags);
+
+#define CTX_INIT(_member) \
+   pctx->_member = ctx->drv->_member ? rsq_##_member : NULL
+
+#endif /* RSQ_CONTEXT_H */
diff --git a/src/gallium/drivers/resequencer/rsq_draw.c b/src/gallium/drivers/resequencer/rsq_draw.c
new file mode 100644
index 0000000..fb6370f
--- /dev/null
+++ b/src/gallium/drivers/resequencer/rsq_draw.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright © 2016 Red Hat
+ *
+ * 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
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 "util/u_memory.h"
+
+#include "rsq_batch.h"
+#include "rsq_context.h"
+#include "rsq_draw.h"
+#include "rsq_resource.h"
+
+static void rsq_emit_string_marker(struct pipe_context *pctx,
+                                    const char *string, int len)
+{
+   // TODO this needs to be written to batch..
+}
+
+void rsq_replay_emit_string_marker(struct rsq_batch *batch)
+{
+   // TODO
+}
+
+static void rsq_draw_vbo(struct pipe_context *pctx,
+                         const struct pipe_draw_info *info)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+   struct pipe_draw_info *ptr;
+
+   /* TODO: */
+   debug_assert(!info->count_from_stream_output);
+   debug_assert(!info->indirect);
+   debug_assert(!info->indirect_params);
+
+   rsq_context_emit(pctx);
+
+   rsq_batch_emit_uint(ctx->batch, rsq_draw_cmd);
+   ptr = rsq_batch_emit_buf(ctx->batch, sizeof(*ptr));
+   *ptr = *info;
+}
+
+void rsq_replay_draw_vbo(struct rsq_batch *batch)
+{
+   struct rsq_context *ctx = batch->ctx;
+   struct pipe_draw_info *ptr;
+
+   ptr = rsq_batch_consume_buf(batch, sizeof(*ptr));
+
+   ctx->drv->draw_vbo(ctx->drv, ptr);
+}
+
+struct rsq_clear_state {
+   union pipe_color_union color;
+   double depth;
+   unsigned buffers;
+   unsigned stencil;
+};
+
+static void rsq_clear(struct pipe_context *pctx,
+                      unsigned buffers,
+                      const union pipe_color_union *color,
+                      double depth,
+                      unsigned stencil)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+   struct rsq_clear_state *ptr;
+
+   /* TODO probably most state doesn't need to be emitted.. but things like
+    * framebuffer state do.  Perhaps it is useful to pass a state-mask?
+    */
+   rsq_context_emit(pctx);
+
+   rsq_batch_emit_uint(ctx->batch, rsq_clear_cmd);
+   ptr = rsq_batch_emit_buf(ctx->batch, sizeof(*ptr));
+   ptr->color = *color;
+   ptr->depth = depth;
+   ptr->buffers = buffers;
+   ptr->stencil = stencil;
+}
+
+void rsq_replay_clear(struct rsq_batch *batch)
+{
+   struct rsq_context *ctx = batch->ctx;
+   struct rsq_clear_state *ptr;
+
+   ptr = rsq_batch_consume_buf(batch, sizeof(*ptr));
+
+   ctx->drv->clear(ctx->drv, ptr->buffers, &ptr->color, ptr->depth, ptr->stencil);
+}
+
+static void rsq_launch_grid(struct pipe_context *pctx,
+                            const struct pipe_grid_info *info)
+{
+   // TODO ... pipe_grid_info::input needs to be a pipe_resource!!!
+}
+
+void rsq_replace_launch_grid(struct rsq_batch *batch)
+{
+   // TODO
+}
+
+struct rsq_copy_region_state {
+   struct pipe_box src_box;
+   struct pipe_resource *dst;
+   struct pipe_resource *src;
+   unsigned dst_level, dstx, dsty, dstz;
+   unsigned src_level;
+};
+
+static void rsq_resource_copy_region(struct pipe_context *pctx,
+                                     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 rsq_context *ctx = rsq_context(pctx);
+   struct rsq_copy_region_state *ptr;
+
+   // TODO: rsq_context_update_batch(pctx, fake_framebuffer_state);
+
+   rsq_batch_emit_uint(ctx->batch, rsq_copy_region_cmd);
+   ptr = rsq_batch_emit_buf(ctx->batch, sizeof(*ptr));
+   ptr->src_box = *src_box;
+   ptr->dst = NULL;
+   pipe_resource_reference(&ptr->dst, unwrap(dst));
+   ptr->src = NULL;
+   pipe_resource_reference(&ptr->src, unwrap(src));
+   ptr->dst_level = dst_level;
+   ptr->dstx = dstx;
+   ptr->dsty = dsty;
+   ptr->dstz = dstz;
+   ptr->src_level = src_level;
+}
+
+void rsq_replay_copy_region(struct rsq_batch *batch)
+{
+   struct rsq_context *ctx = batch->ctx;
+   struct rsq_copy_region_state *ptr;
+
+   ptr = rsq_batch_consume_buf(batch, sizeof(*ptr));
+
+   ctx->drv->resource_copy_region(ctx->drv, ptr->dst, ptr->dst_level,
+                                  ptr->dstx, ptr->dsty, ptr->dstz,
+                                  ptr->src, ptr->src_level, &ptr->src_box);
+
+   pipe_resource_reference(&ptr->dst, NULL);
+   pipe_resource_reference(&ptr->src, NULL);
+}
+
+static void rsq_blit(struct pipe_context *pctx,
+                     const struct pipe_blit_info *info)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+   struct pipe_blit_info *ptr;
+
+   // TODO: rsq_context_update_batch(pctx, fake_framebuffer_state);
+
+   rsq_batch_emit_uint(ctx->batch, rsq_blit_cmd);
+   ptr = rsq_batch_emit_buf(ctx->batch, sizeof(*ptr));
+   *ptr = *info;
+   ptr->dst.resource = NULL;
+   pipe_resource_reference(&ptr->dst.resource, unwrap(info->dst.resource));
+   ptr->src.resource = NULL;
+   pipe_resource_reference(&ptr->src.resource, unwrap(info->src.resource));
+}
+
+void rsq_replay_blit(struct rsq_batch *batch)
+{
+   struct rsq_context *ctx = batch->ctx;
+   struct pipe_blit_info *ptr;
+
+   ptr = rsq_batch_consume_buf(batch, sizeof(*ptr));
+
+   ctx->drv->blit(ctx->drv, ptr);
+
+   pipe_resource_reference(&ptr->dst.resource, NULL);
+   pipe_resource_reference(&ptr->src.resource, NULL);
+}
+
+static void rsq_flush(struct pipe_context *pctx,
+                      struct pipe_fence_handle **fence,
+                      unsigned flags)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+
+   /* flush current and dependent batches: */
+   rsq_batch_flush(ctx->batch);
+
+   rsq_batch_reference(&ctx->batch, NULL);
+   ctx->batch = rsq_batch_create(ctx);
+
+   ctx->drv->flush(ctx->drv, fence, flags);
+}
+
+void rsq_draw_context_init(struct pipe_context *pctx)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+
+   CTX_INIT(emit_string_marker);
+   CTX_INIT(flush);
+   CTX_INIT(draw_vbo);
+   CTX_INIT(clear);
+   CTX_INIT(launch_grid);
+   CTX_INIT(resource_copy_region);
+   CTX_INIT(blit);
+
+//   CTX_INIT(clear_render_target);
+//   CTX_INIT(clear_depth_stencil);
+//   CTX_INIT(clear_buffer);
+}
diff --git a/src/gallium/drivers/resequencer/rsq_draw.h b/src/gallium/drivers/resequencer/rsq_draw.h
new file mode 100644
index 0000000..6782cc5
--- /dev/null
+++ b/src/gallium/drivers/resequencer/rsq_draw.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright © 2016 Red Hat
+ *
+ * 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
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 RSQ_DRAW_H
+#define RSQ_DRAW_H
+
+#include "pipe/p_context.h"
+
+struct rsq_batch;
+
+void rsq_replay_emit_string_marker(struct rsq_batch *batch);
+void rsq_replay_draw_vbo(struct rsq_batch *batch);
+void rsq_replay_clear(struct rsq_batch *batch);
+void rsq_replace_launch_grid(struct rsq_batch *batch);
+void rsq_replay_copy_region(struct rsq_batch *batch);
+void rsq_replay_blit(struct rsq_batch *batch);
+
+void rsq_draw_context_init(struct pipe_context *pctx);
+
+#endif /* RSQ_DRAW_H */
diff --git a/src/gallium/drivers/resequencer/rsq_fence.c b/src/gallium/drivers/resequencer/rsq_fence.c
new file mode 100644
index 0000000..88b7fac
--- /dev/null
+++ b/src/gallium/drivers/resequencer/rsq_fence.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright © 2016 Red Hat
+ *
+ * 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
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 "rsq_fence.h"
+#include "rsq_screen.h"
+
+static void rsq_fence_reference(struct pipe_screen *pscreen,
+                                struct pipe_fence_handle **ptr,
+                                struct pipe_fence_handle *pfence)
+{
+   // XXX
+}
+
+static boolean rsq_fence_finish(struct pipe_screen *pscreen,
+                                struct pipe_fence_handle *pfence,
+                                uint64_t timeout)
+{
+   // XXX
+   return false;
+}
+
+void rsq_fence_screen_init(struct pipe_screen *pscreen)
+{
+   struct rsq_screen *screen = rsq_screen(pscreen);
+
+   SCR_INIT(fence_reference);
+   SCR_INIT(fence_finish);
+}
diff --git a/src/gallium/drivers/resequencer/rsq_fence.h b/src/gallium/drivers/resequencer/rsq_fence.h
new file mode 100644
index 0000000..87485e9
--- /dev/null
+++ b/src/gallium/drivers/resequencer/rsq_fence.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright © 2016 Red Hat
+ *
+ * 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
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 RSQ_FENCE_H
+#define RSQ_FENCE_H
+
+#include "pipe/p_screen.h"
+
+struct rsq_fence {
+   struct pipe_fence_handle *drv;
+   /* TODO need to track associated batch, since waiting on a fence
+    * could trigger flushing the batch..
+    */
+};
+
+static inline struct rsq_fence * rsq_fence(struct pipe_fence_handle *pfence)
+{
+   return (struct rsq_fence *)pfence;
+}
+
+void rsq_fence_screen_init(struct pipe_screen *pscreen);
+
+#endif /* RSQ_FENCE_H */
diff --git a/src/gallium/drivers/resequencer/rsq_public.h b/src/gallium/drivers/resequencer/rsq_public.h
new file mode 100644
index 0000000..8aef886
--- /dev/null
+++ b/src/gallium/drivers/resequencer/rsq_public.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright © 2016 Red Hat
+ *
+ * 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
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 RSQ_PUBLIC_H
+#define RSQ_PUBLIC_H
+
+#include "pipe/p_state.h"
+
+/**
+ * Public interface interface for resequencer layer.
+ *
+ * The resequencer layer reorders state updates, draws, etc, for better
+ * efficiency on tiling GPUs.  Many GL apps/games which are not properly
+ * optimized for tilers will do things like unnecessary render target
+ * switches or mid-batch texture uploads.
+ *
+ * This is solved by tracking dependencies between rendering to surfaces
+ * and use of those surfaces, and replaying the sequence of state updates
+ * and draws to the driver in a more optimal order.
+ *
+ * The resequencer can also clone/shadow resources to avoid flushes.  For
+ * example, a mid-batch texture upload can clone the pipe_resource (so
+ * an existing rsq_resource now refers to a new driver pipe_resource).
+ */
+
+struct rsq_funcs {
+   /**
+    * Would read and/or write to buffer cause a flush/stall?  This is
+    * used to make decisions about cloning/ghosting resources.
+    */
+   bool (*is_busy)(struct pipe_resource *prsc, bool write);
+};
+
+struct pipe_screen * rsq_wrap(struct pipe_screen *pscreen,
+                              const struct rsq_funcs *funcs);
+
+#endif /* RSQ_PUBLIC_H */
diff --git a/src/gallium/drivers/resequencer/rsq_query.c b/src/gallium/drivers/resequencer/rsq_query.c
new file mode 100644
index 0000000..1521a3d
--- /dev/null
+++ b/src/gallium/drivers/resequencer/rsq_query.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright © 2016 Red Hat
+ *
+ * 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
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 "rsq_context.h"
+#include "rsq_query.h"
+#include "rsq_screen.h"
+
+/* TODO how should queries work?  I guess we need to emit cmds to start/
+ * stop queries into the batch?
+ */
+
+
+static int rsq_get_driver_query_info(struct pipe_screen *pscreen,
+                                     unsigned index,
+                                     struct pipe_driver_query_info *info)
+{
+   struct rsq_screen *screen = rsq_screen(pscreen);
+   return screen->drv->get_driver_query_info(screen->drv, index, info);
+}
+
+static int rsq_get_driver_query_group_info(struct pipe_screen *pscreen,
+                                           unsigned index,
+                                           struct pipe_driver_query_group_info *info)
+{
+   struct rsq_screen *screen = rsq_screen(pscreen);
+   return screen->drv->get_driver_query_group_info(screen->drv, index, info);
+}
+
+static void rsq_query_memory_info(struct pipe_screen *pscreen,
+                                  struct pipe_memory_info *info)
+{
+   struct rsq_screen *screen = rsq_screen(pscreen);
+   screen->drv->query_memory_info(screen->drv, info);
+}
+
+void rsq_query_screen_init(struct pipe_screen *pscreen)
+{
+   struct rsq_screen *screen = rsq_screen(pscreen);
+
+   SCR_INIT(get_driver_query_info);
+   SCR_INIT(get_driver_query_group_info);
+   pscreen->query_memory_info = rsq_query_memory_info;
+}
+
+
+static void rsq_render_condition(struct pipe_context *pctx,
+                                 struct pipe_query *pquery,
+                                 boolean condition,
+                                 uint mode)
+{
+   // TODO
+}
+
+static struct pipe_query * rsq_create_query(struct pipe_context *pctx,
+                                            unsigned query_type,
+                                            unsigned index)
+{
+   // TODO
+   return NULL;
+}
+
+static struct pipe_query *rsq_create_batch_query(struct pipe_context *pctx,
+                                                 unsigned num_queries,
+                                                 unsigned *query_types)
+{
+   // TODO
+   return NULL;
+}
+
+static void rsq_destroy_query(struct pipe_context *pctx,
+                              struct pipe_query *pquery)
+{
+
+}
+
+static boolean rsq_begin_query(struct pipe_context *pctx,
+                               struct pipe_query *pquery)
+{
+   // TODO
+   return false;
+}
+
+static boolean rsq_end_query(struct pipe_context *pctx,
+                             struct pipe_query *pquery)
+{
+   // TODO
+   return false;
+}
+
+static boolean rsq_get_query_result(struct pipe_context *pctx,
+                                    struct pipe_query *pquery,
+                                    boolean wait,
+                                    union pipe_query_result *result)
+{
+   // TODO
+   return false;
+}
+
+static void rsq_get_query_result_resource(struct pipe_context *pctx,
+                                          struct pipe_query *pquery,
+                                          boolean wait,
+                                          enum pipe_query_value_type result_type,
+                                          int index,
+                                          struct pipe_resource *resource,
+                                          unsigned offset)
+{
+   // TODO
+}
+
+static void rsq_set_active_query_state(struct pipe_context *pctx, boolean enable)
+{
+   // TODO
+}
+
+void rsq_query_context_init(struct pipe_context *pctx)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+
+   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);
+}
diff --git a/src/gallium/drivers/resequencer/rsq_query.h b/src/gallium/drivers/resequencer/rsq_query.h
new file mode 100644
index 0000000..bc3a19f
--- /dev/null
+++ b/src/gallium/drivers/resequencer/rsq_query.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright © 2016 Red Hat
+ *
+ * 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
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 RSQ_QUERY_H
+#define RSQ_QUERY_H
+
+#include "pipe/p_screen.h"
+
+void rsq_query_screen_init(struct pipe_screen *pscreen);
+void rsq_query_context_init(struct pipe_context *pctx);
+
+#endif /* RSQ_QUERY_H */
diff --git a/src/gallium/drivers/resequencer/rsq_resource.c b/src/gallium/drivers/resequencer/rsq_resource.c
new file mode 100644
index 0000000..5dd3716
--- /dev/null
+++ b/src/gallium/drivers/resequencer/rsq_resource.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright © 2016 Red Hat
+ *
+ * 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
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 "util/u_inlines.h"
+#include "util/u_memory.h"
+
+#include "rsq_context.h"
+#include "rsq_resource.h"
+#include "rsq_screen.h"
+
+static boolean rsq_can_create_resource(struct pipe_screen *pscreen,
+                                       const struct pipe_resource *templat)
+{
+   struct rsq_screen *screen = rsq_screen(pscreen);
+   return screen->drv->can_create_resource(screen->drv, templat);
+}
+
+static void rsc_resource_destroy(struct pipe_screen *pscrean,
+                                 struct pipe_resource *prsc)
+{
+   struct rsq_resource *rsc = rsq_resource(prsc);
+   pipe_resource_reference(&rsc->drv, NULL);
+   free(rsc);
+}
+
+/* (re)allocate backing driver prsc */
+static void get_driver_resource(struct rsq_resource *rsc)
+{
+   struct rsq_screen *screen = rsq_screen(rsc->base.screen);
+
+   pipe_resource_reference(&rsc->drv, NULL);
+
+   /* allocate a new buffer from driver: */
+   rsc->drv = screen->drv->resource_create(screen->drv, &rsc->base);
+   rsc->seqno = screen->rsc_cnt++;
+}
+
+static struct rsq_resource * rsq_resource_new(struct pipe_screen *pscreen,
+                                              const struct pipe_resource *tmpl)
+{
+   struct rsq_resource *rsc = CALLOC_STRUCT(rsq_resource);
+
+   if (!rsc)
+      return NULL;
+
+   rsc->base = *tmpl;
+   rsc->base.screen = pscreen;
+
+   pipe_reference_init(&rsc->base.reference, 1);
+
+   return rsc;
+}
+
+static struct pipe_resource * rsq_resource_create(struct pipe_screen *pscreen,
+                                                  const struct pipe_resource *tmpl)
+{
+   struct rsq_resource *rsc = rsq_resource_new(pscreen, tmpl);
+
+   if (!rsc)
+      return NULL;
+
+   get_driver_resource(rsc);
+
+   if (!rsc->drv)
+      goto fail;
+
+   return &rsc->base;
+
+fail:
+   rsc_resource_destroy(pscreen, &rsc->base);
+   return NULL;
+}
+
+static struct pipe_resource *
+rsq_resource_from_handle(struct pipe_screen *pscreen,
+                         const struct pipe_resource *tmpl,
+                         struct winsys_handle *handle,
+                         unsigned usage)
+{
+   struct rsq_screen *screen = rsq_screen(pscreen);
+   struct rsq_resource *rsc = rsq_resource_new(pscreen, tmpl);
+
+   if (!rsc)
+      return NULL;
+
+   rsc->external = true;
+
+   struct pipe_resource *drv;
+   drv = screen->drv->resource_from_handle(screen->drv, tmpl, handle, usage);
+
+   if (!drv)
+      goto fail;
+
+   pipe_resource_reference(&rsc->drv, drv);
+
+   return &rsc->base;
+
+fail:
+   rsc_resource_destroy(pscreen, &rsc->base);
+   return NULL;
+}
+
+static boolean rsq_resource_get_handle(struct pipe_screen *pscreen,
+                                       struct pipe_resource *prsc,
+                                       struct winsys_handle *handle,
+                                       unsigned usage)
+{
+   struct rsq_screen *screen = rsq_screen(pscreen);
+   struct rsq_resource *rsc = rsq_resource(prsc);
+
+   rsc->external = true;
+
+   return screen->drv->resource_get_handle(screen->drv, rsc->drv, handle, usage);
+}
+
+
+void rsq_resource_screen_init(struct pipe_screen *pscreen)
+{
+   struct rsq_screen *screen = rsq_screen(pscreen);
+
+   SCR_INIT(can_create_resource);
+   pscreen->resource_create = rsq_resource_create;
+   pscreen->resource_destroy = rsc_resource_destroy;
+   pscreen->resource_from_handle = rsq_resource_from_handle;
+   pscreen->resource_get_handle = rsq_resource_get_handle;
+}
+
+/* TODO
+ * For now just trivial implementation of transfer_map and friends
+ * that always flushes the current batch and passes down to drv..
+ * once we have resequencing we will want to be more clever..
+ */
+
+static void * rsq_transfer_map(struct pipe_context *pctx,
+                               struct pipe_resource *prsc,
+                               unsigned level,
+                               unsigned usage,  /* a combination of PIPE_TRANSFER_x */
+                               const struct pipe_box *box,
+                               struct pipe_transfer **out_transfer)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+
+   pctx->flush(pctx, NULL, 0);
+
+   return ctx->drv->transfer_map(ctx->drv, unwrap(prsc), level, usage,
+                                 box, out_transfer);
+}
+
+static void rsq_transfer_flush_region(struct pipe_context *pctx,
+                                      struct pipe_transfer *transfer,
+                                      const struct pipe_box *box)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+   ctx->drv->transfer_flush_region(ctx->drv, transfer, box);
+}
+
+static void rsq_transfer_unmap(struct pipe_context *pctx,
+                               struct pipe_transfer *transfer)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+   ctx->drv->transfer_unmap(ctx->drv, transfer);
+}
+
+static void rsq_transfer_inline_write(struct pipe_context *pctx,
+                                      struct pipe_resource *prsc,
+                                      unsigned level,
+                                      unsigned usage, /* a combination of PIPE_TRANSFER_x */
+                                      const struct pipe_box *box,
+                                      const void *data,
+                                      unsigned stride,
+                                      unsigned layer_stride)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+
+   pctx->flush(pctx, NULL, 0);
+
+   ctx->drv->transfer_inline_write(ctx->drv, unwrap(prsc), level, usage, box,
+                                   data, stride, layer_stride);
+}
+
+static void rsq_flush_resource(struct pipe_context *pctx,
+                               struct pipe_resource *prsc)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+   struct rsq_resource *rsc = rsq_resource(prsc);
+
+   rsq_context_emit(pctx);
+
+   ctx->drv->flush_resource(ctx->drv, rsc->drv);
+}
+
+void rsq_resource_context_init(struct pipe_context *pctx)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+
+   CTX_INIT(transfer_map);
+   CTX_INIT(transfer_flush_region);
+   CTX_INIT(transfer_unmap);
+   CTX_INIT(transfer_inline_write);
+   CTX_INIT(flush_resource);
+//   CTX_INIT(invalidate_resource);
+}
diff --git a/src/gallium/drivers/resequencer/rsq_resource.h b/src/gallium/drivers/resequencer/rsq_resource.h
new file mode 100644
index 0000000..188bd8c
--- /dev/null
+++ b/src/gallium/drivers/resequencer/rsq_resource.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright © 2016 Red Hat
+ *
+ * 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
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 RSQ_RESOURCE_H
+#define RSQ_RESOURCE_H
+
+#include "pipe/p_state.h"
+
+struct rsq_resource {
+   struct pipe_resource base;
+
+   struct pipe_resource *drv;     /* wrapped driver's resource */
+   unsigned seqno;
+   bool external;                 /* external resources cannot be shadowed */
+};
+
+static inline struct rsq_resource * rsq_resource(struct pipe_resource *prsc)
+{
+   return (struct rsq_resource *)prsc;
+}
+
+void rsq_resource_screen_init(struct pipe_screen *pscreen);
+void rsq_resource_context_init(struct pipe_context *pctx);
+
+
+static inline struct pipe_resource * unwrap(struct pipe_resource *prsc)
+{
+   if (!prsc)
+      return NULL;
+   return rsq_resource(prsc)->drv;
+}
+
+static inline unsigned seqno(struct pipe_resource *prsc)
+{
+   if (!prsc)
+      return 0;
+   return rsq_resource(prsc)->seqno;
+}
+
+#endif /* RSQ_RESOURCE_H */
diff --git a/src/gallium/drivers/resequencer/rsq_screen.c b/src/gallium/drivers/resequencer/rsq_screen.c
new file mode 100644
index 0000000..1160e92
--- /dev/null
+++ b/src/gallium/drivers/resequencer/rsq_screen.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright © 2016 Red Hat
+ *
+ * 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
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 "util/u_memory.h"
+
+#include "rsq_context.h"
+#include "rsq_fence.h"
+#include "rsq_resource.h"
+#include "rsq_screen.h"
+#include "rsq_query.h"
+
+
+static void rsq_screen_destroy(struct pipe_screen *pscreen)
+{
+   struct rsq_screen *screen = rsq_screen(pscreen);
+
+   screen->drv->destroy(screen->drv);
+
+   free(screen);
+}
+
+static const char * rsq_screen_get_name(struct pipe_screen *pscreen)
+{
+   struct rsq_screen *screen = rsq_screen(pscreen);
+   return screen->drv->get_name(screen->drv);
+}
+
+static const char * rsq_screen_get_vendor(struct pipe_screen *pscreen)
+{
+   struct rsq_screen *screen = rsq_screen(pscreen);
+   return screen->drv->get_vendor(screen->drv);
+}
+
+static const char * rsq_screen_get_device_vendor(struct pipe_screen *pscreen)
+{
+   struct rsq_screen *screen = rsq_screen(pscreen);
+   return screen->drv->get_device_vendor(screen->drv);
+}
+
+static int
+rsq_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
+{
+   struct rsq_screen *screen = rsq_screen(pscreen);
+
+   /* NOTE: we need pipe_resources, since user buffer ptrs are likely
+    * to be invalid by the time we actually flush rendering:
+    */
+   switch (param) {
+   case PIPE_CAP_USER_CONSTANT_BUFFERS:
+   case PIPE_CAP_USER_VERTEX_BUFFERS:
+   case PIPE_CAP_USER_INDEX_BUFFERS:
+      return 0;
+   default:
+      return screen->drv->get_param(screen->drv, param);
+   }
+}
+
+static float rsq_screen_get_paramf(struct pipe_screen *pscreen,
+                                   enum pipe_capf param)
+{
+   struct rsq_screen *screen = rsq_screen(pscreen);
+   return screen->drv->get_paramf(screen->drv, param);
+}
+
+static int rsq_screen_get_shader_param(struct pipe_screen *pscreen,
+                                       unsigned shader,
+                                       enum pipe_shader_cap param)
+{
+   struct rsq_screen *screen = rsq_screen(pscreen);
+   return screen->drv->get_shader_param(screen->drv, shader, param);
+}
+
+static int rsq_get_video_param(struct pipe_screen *pscreen,
+                               enum pipe_video_profile profile,
+                               enum pipe_video_entrypoint entrypoint,
+                               enum pipe_video_cap param)
+{
+   struct rsq_screen *screen = rsq_screen(pscreen);
+   return screen->drv->get_video_param(screen->drv, profile, entrypoint, param);
+}
+
+static int rsq_get_compute_param(struct pipe_screen *pscreen,
+                                 enum pipe_shader_ir ir_type,
+                                 enum pipe_compute_cap param,
+                                 void *ret)
+{
+   struct rsq_screen *screen = rsq_screen(pscreen);
+   return screen->drv->get_compute_param(screen->drv, ir_type, param, ret);
+}
+
+static uint64_t rsq_get_timestamp(struct pipe_screen *pscreen)
+{
+   struct rsq_screen *screen = rsq_screen(pscreen);
+   return screen->drv->get_timestamp(screen->drv);
+}
+
+static boolean rsq_is_format_supported(struct pipe_screen *pscreen,
+                                       enum pipe_format format,
+                                       enum pipe_texture_target target,
+                                       unsigned sample_count,
+                                       unsigned bindings)
+{
+   struct rsq_screen *screen = rsq_screen(pscreen);
+   return screen->drv->is_format_supported(screen->drv, format, target,
+                                           sample_count, bindings);
+}
+
+static boolean rsq_is_video_format_supported(struct pipe_screen *pscreen,
+                                             enum pipe_format format,
+                                             enum pipe_video_profile profile,
+                                             enum pipe_video_entrypoint entrypoint)
+{
+   struct rsq_screen *screen = rsq_screen(pscreen);
+   return screen->drv->is_video_format_supported(screen->drv, format, profile,
+                                                 entrypoint);
+}
+
+static const void * rsq_get_compiler_options(struct pipe_screen *pscreen,
+                                             enum pipe_shader_ir ir,
+                                             unsigned shader)
+{
+   struct rsq_screen *screen = rsq_screen(pscreen);
+   return screen->drv->get_compiler_options(screen->drv, ir, shader);
+}
+
+
+struct pipe_screen * rsq_wrap(struct pipe_screen *drv,
+                              const struct rsq_funcs *funcs)
+{
+   struct rsq_screen *screen = CALLOC_STRUCT(rsq_screen);
+
+   if (!screen)
+      return NULL;
+
+   screen->funcs = funcs;
+   screen->drv = drv;
+
+   struct pipe_screen *pscreen = &screen->base;
+
+   pscreen->destroy = rsq_screen_destroy;
+
+   pscreen->get_name = rsq_screen_get_name;
+   pscreen->get_vendor = rsq_screen_get_vendor;
+   pscreen->get_device_vendor = rsq_screen_get_device_vendor;
+   pscreen->get_param = rsq_screen_get_param;
+   pscreen->get_paramf = rsq_screen_get_paramf;
+   pscreen->get_shader_param = rsq_screen_get_shader_param;
+   pscreen->get_video_param = rsq_get_video_param;
+   pscreen->get_compute_param = rsq_get_compute_param;
+   SCR_INIT(get_timestamp);
+   pscreen->context_create = rsq_context_create;
+   pscreen->is_format_supported = rsq_is_format_supported;
+   pscreen->is_video_format_supported = rsq_is_video_format_supported;
+
+   rsq_resource_screen_init(pscreen);
+
+//XXX   SCR_INIT(flush_frontbuffer);
+
+   rsq_fence_screen_init(pscreen);
+
+   rsq_query_screen_init(pscreen);
+
+   pscreen->get_compiler_options = rsq_get_compiler_options;
+
+   return pscreen;
+}
diff --git a/src/gallium/drivers/resequencer/rsq_screen.h b/src/gallium/drivers/resequencer/rsq_screen.h
new file mode 100644
index 0000000..359f173
--- /dev/null
+++ b/src/gallium/drivers/resequencer/rsq_screen.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2016 Red Hat
+ *
+ * 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
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 RSQ_SCREEN_H
+#define RSQ_SCREEN_H
+
+#include "pipe/p_screen.h"
+
+#include "rsq_public.h"
+
+struct rsq_screen {
+   struct pipe_screen base;
+
+   struct pipe_screen *drv;       /* wrapped driver's screen */
+
+   unsigned rsc_cnt;
+
+   const struct rsq_funcs *funcs;
+};
+
+static inline struct rsq_screen * rsq_screen(struct pipe_screen *pscreen)
+{
+   return (struct rsq_screen *)pscreen;
+}
+
+
+#define SCR_INIT(_member) \
+   pscreen->_member = screen->drv->_member ? rsq_##_member : NULL
+
+#endif /* RSQ_SCREEN_H */
diff --git a/src/gallium/drivers/resequencer/rsq_state.py b/src/gallium/drivers/resequencer/rsq_state.py
new file mode 100644
index 0000000..8efc739
--- /dev/null
+++ b/src/gallium/drivers/resequencer/rsq_state.py
@@ -0,0 +1,607 @@
+#! /usr/bin/env python
+#
+# Copyright (c) 2016 Red Hat
+# 
+# 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
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS 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.
+
+import mako.template
+import sys
+
+#
+# CSO state:
+#
+class CSO(object):
+   __type_template = mako.template.Template("""
+% if not s.manual:
+/* refcounted container to track matching driver state: */
+struct rsq_${s.typename}_state {
+   struct pipe_reference reference;
+   void *drv;
+};
+% else:
+struct rsq_${s.typename}_state;
+% endif
+""")
+
+   __id_template = mako.template.Template("""
+% for name in s.statenames:
+   rsq_${name}_id,
+% endfor
+""")
+
+   __funcs_template = mako.template.Template("""
+% for name in s.statenames:
+static inline void rsq_${name}_ref(struct pipe_context *pctx,
+                        struct rsq_${s.typename}_state **ptr,
+                        struct rsq_${s.typename}_state *val)
+{
+   if (pipe_reference(&(*ptr)->reference, &val->reference)) {
+      struct rsq_context *ctx = rsq_context(pctx);
+      ctx->drv->delete_${name}_state(ctx->drv, (*ptr)->drv);
+      free(*ptr);
+   }
+   *ptr = val;
+}
+% if not s.manual:
+static void * rsq_create_${name}_state(struct pipe_context *pctx,
+                        const struct pipe_${s.typename}_state *s)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+   struct rsq_${s.typename}_state *so = CALLOC_STRUCT(rsq_${s.typename}_state);
+   if (!so)
+      return NULL;
+   so->drv = ctx->drv->create_${name}_state(ctx->drv, s);
+   if (!so->drv) {
+      free(so);
+      return NULL;
+   }
+   pipe_reference_init(&so->reference, 1);
+   return so;
+}
+% endif
+static void rsq_bind_${name}_state${"" if s.length is None else "s"}(struct pipe_context *pctx,
+% if s.per_shader_stage:
+                        unsigned stage,
+% endif
+% if s.length:
+                        unsigned start, unsigned num, void **s)
+% else:
+                        void *s)
+% endif
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+   ctx->state.dirty |= (1 << rsq_${name}_id);
+% if s.length:
+   debug_assert((start + num) < ${s.length});
+   for (unsigned i = 0; i < num; i++) {
+      ctx->state.${name}${"[stage]" if s.per_shader_stage else ""}[i + start] = s[i];
+      ctx->state.dirty_${name}${'[stage]' if s.per_shader_stage else ''} |= (1 << (i + start));
+      ctx->state.valid_${name}${'[stage]' if s.per_shader_stage else ''} |= (1 << (i + start));
+   }
+% else:
+   ctx->state.${name} = s;
+% endif
+% if s.per_shader_stage:
+   ctx->state.dirty_${name}_shader |= (1 << stage);
+   ctx->state.valid_${name}_shader |= (1 << stage);
+% endif
+}
+static void rsq_delete_${name}_state(struct pipe_context *pctx, void *s)
+{
+   struct rsq_${s.typename}_state *so = s;
+   rsq_${name}_ref(pctx, &so, NULL);
+   free(so);
+}
+% endfor
+""")
+
+   __setup_template = mako.template.Template("""
+% for name in s.statenames:
+   CTX_INIT(create_${name}_state);
+   CTX_INIT(bind_${name}_state${"" if s.length is None else "s"});
+   CTX_INIT(delete_${name}_state);
+% endfor
+""")
+
+   __state_template = mako.template.Template("""
+% for name in s.statenames:
+% if s.per_shader_stage:
+   unsigned short valid_${name}_shader;
+   unsigned short dirty_${name}_shader;
+% endif
+% if s.length:
+   unsigned dirty_${name}${'[PIPE_SHADER_TYPES]' if s.per_shader_stage else ''};
+   unsigned valid_${name}${'[PIPE_SHADER_TYPES]' if s.per_shader_stage else ''};
+% endif
+   struct rsq_${s.typename}_state *${name}
+% if s.per_shader_stage:
+   [PIPE_SHADER_TYPES]
+% endif
+% if s.length is not None:
+   [${s.length}]
+% endif
+   ;
+% endfor
+""")
+
+   __emit_template = mako.template.Template("""
+% for name in s.statenames:
+   if (ctx->state.dirty & (1 << rsq_${name}_id)) {
+% if s.per_shader_stage:
+      shader_mask = ctx->state.dirty_${name}_shader;
+      while((shader = util_last_bit(shader_mask) - 1) >= 0) {
+% endif
+% if s.length:
+         idx_mask = ctx->state.dirty_${name}${'[shader]' if s.per_shader_stage else ''};
+         while ((idx = util_last_bit(idx_mask) - 1) >= 0) {
+            struct rsq_${s.typename}_state **ptr;
+            rsq_batch_emit_uint(ctx->batch, rsq_${name}_id);
+% if s.per_shader_stage:
+            rsq_batch_emit_uint(ctx->batch, shader);
+% endif:
+            rsq_batch_emit_uint(ctx->batch, idx);
+            ptr = rsq_batch_emit_buf(ctx->batch, sizeof(*ptr));
+            *ptr = NULL;
+            rsq_${name}_ref(pctx, ptr, ctx->state.${name}${'[shader]' if s.per_shader_stage else ''}[idx]);
+            idx_mask &= ~(1 << idx);
+         }
+         ctx->state.dirty_${name}${'[shader]' if s.per_shader_stage else ''} = 0;
+% else:
+         struct rsq_${s.typename}_state **ptr;
+         rsq_batch_emit_uint(ctx->batch, rsq_${name}_id);
+         ptr = rsq_batch_emit_buf(ctx->batch, sizeof(*ptr));
+         *ptr = NULL;
+         rsq_${name}_ref(pctx, ptr, ctx->state.${name}${'[shader]' if s.per_shader_stage else ''});
+% endif
+% if s.per_shader_stage:
+         shader_mask &= ~(1 << shader);
+      }
+      ctx->state.dirty_${name}_shader = 0;
+% endif
+   }
+% endfor
+""")
+
+   __replay_template = mako.template.Template("""
+% for name in s.statenames:
+   case rsq_${name}_id: {
+% if s.per_shader_stage:
+      unsigned stage = rsq_batch_consume_uint(batch);
+% endif
+% if s.length:
+      static const struct pipe_${s.typename}_state *nullstate = NULL;
+      unsigned i = rsq_batch_consume_uint(batch);
+% endif
+      struct rsq_${s.typename}_state **ptr = rsq_batch_consume_buf(batch, sizeof(*ptr));
+      ctx->drv->bind_${name}_state${'s' if s.length else ''}(ctx->drv,
+% if s.per_shader_stage:
+                                   stage,
+% endif
+% if s.length:
+                                   i, 1, *ptr ? &(*ptr)->drv : (void **)&nullstate);
+% else:
+                                   *ptr ? (*ptr)->drv : NULL);
+% endif
+      rsq_${name}_ref(&ctx->base, ptr, NULL);
+      break;
+   }
+% endfor
+""")
+
+   def __init__(self, typename, statenames=None, length=None,
+                per_shader_stage=False, manual=False):
+      self.typename = typename
+      if statenames:
+         self.statenames = statenames
+      else:
+         self.statenames = [ typename ]
+      self.length = length
+      self.per_shader_stage = per_shader_stage
+      self.manual = manual
+
+   def render_type(self):
+      return self.__type_template.render(s=self)
+
+   def render_id(self):
+      return self.__id_template.render(s=self)
+
+   def render_funcs(self):
+      return self.__funcs_template.render(s=self)
+
+   def render_setup(self):
+      return self.__setup_template.render(s=self)
+
+   def render_state(self):
+      return self.__state_template.render(s=self)
+
+   def render_emit(self):
+      return self.__emit_template.render(s=self)
+
+   def render_replay(self):
+      return self.__replay_template.render(s=self)
+
+
+
+#
+# Non-CSO state:
+#
+class Param(object):
+   __funcs_template = mako.template.Template("""
+static void rsq_set_${s.statename}(struct pipe_context *pctx,
+% if s.per_shader_stage:
+                        unsigned stage,
+% endif
+% if s.cb_hack:
+                        unsigned start,
+% elif s.length:
+                        unsigned start, unsigned num,
+% endif
+                        ${"const " if not s.cs_hack else ""}${s.typename} val)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+% if s.cb_hack:
+   const unsigned num = 1;
+% endif
+   ctx->state.dirty |= (1 << rsq_${s.statename}_id);
+% if s.length:
+   debug_assert((start + num) < ${s.length});
+   for (unsigned i = 0; i < num; i++) {
+      ${s.copy_command("ctx->state." + s.statename + ("[stage]" if s.per_shader_stage else "") + "[i + start]", "&val[i]")};
+      ctx->state.dirty_${s.statename}${'[stage]' if s.per_shader_stage else ''} |= (1 << (i + start));
+      ctx->state.valid_${s.statename}${'[stage]' if s.per_shader_stage else ''} |= (1 << (i + start));
+   }
+% else:
+   ${s.copy_command("ctx->state." + s.statename + ("[stage]" if s.per_shader_stage else ""), "val")};
+% endif
+% if s.per_shader_stage:
+   ctx->state.dirty_${s.statename}_shader |= (1 << stage);
+   ctx->state.valid_${s.statename}_shader |= (1 << stage);
+% endif
+% if s.statename is "framebuffer_state":
+   rsq_context_update_batch(pctx, val);
+% endif
+}
+""")
+
+   __setup_template = mako.template.Template("""
+   CTX_INIT(set_${s.statename});
+""")
+
+   __state_template = mako.template.Template("""
+% if s.per_shader_stage:
+   unsigned short valid_${s.statename}_shader;
+   unsigned short dirty_${s.statename}_shader;
+% endif
+% if s.length:
+   unsigned dirty_${s.statename}${'[PIPE_SHADER_TYPES]' if s.per_shader_stage else ''};
+   unsigned valid_${s.statename}${'[PIPE_SHADER_TYPES]' if s.per_shader_stage else ''};
+% endif
+% if s.has_resources:
+   unsigned seqno_${s.statename}
+% if s.per_shader_stage:
+   [PIPE_SHADER_TYPES]
+% endif
+% if s.length:
+   [${s.length}]
+% endif
+   ;
+% endif
+   ${s.typename.replace(" *", "")} ${s.statename}
+% if s.per_shader_stage:
+   [PIPE_SHADER_TYPES]
+% endif
+% if s.length:
+   [${s.length}]
+% endif
+   ;
+""")
+
+   __emit_template = mako.template.Template("""
+% if s.has_resources:
+   /* detect if state is dirty due to resource shadowing: */
+   if (unlikely(ctx->dirty_clone)) {
+% if s.per_shader_stage:
+      shader_mask = ctx->state.valid_${s.statename}_shader;
+      while((shader = util_last_bit(shader_mask) - 1) >= 0) {
+% endif
+% if s.length:
+         idx_mask = ctx->state.valid_${s.statename}${'[shader]' if s.per_shader_stage else ''};
+         while ((idx = util_last_bit(idx_mask) - 1) >= 0) {
+% endif
+            seqno = rsq_${s.basename}_seqno(
+                      &ctx->state.${s.statename}${'[shader]' if s.per_shader_stage else ''}
+                      ${'[idx]' if s.length else ''});
+            if (ctx->state.seqno_${s.statename}${'[shader]' if s.per_shader_stage else ''}
+                   ${'[idx]' if s.length else ''} != seqno) {
+% if s.length:
+               ctx->state.dirty_${s.statename}${'[shader]' if s.per_shader_stage else ''} |= (1 << idx);
+% endif
+% if s.per_shader_stage:
+               ctx->state.dirty_${s.statename}_shader |= (1 << shader);
+% endif
+               ctx->state.dirty |= (1 << rsq_${s.statename}_id);
+               ctx->state.seqno_${s.statename}${'[shader]' if s.per_shader_stage else ''}${'[idx]' if s.length else ''} = seqno;
+            }
+% if s.length:
+            idx_mask &= ~(1 << idx);
+         }
+% endif
+% if s.per_shader_stage:
+         shader_mask &= ~(1 << shader);
+      }
+% endif
+   }
+% endif
+
+   if (ctx->state.dirty & (1 << rsq_${s.statename}_id)) {
+% if s.per_shader_stage:
+      shader_mask = ctx->state.dirty_${s.statename}_shader;
+      while((shader = util_last_bit(shader_mask) - 1) >= 0) {
+% endif
+% if s.length:
+         idx_mask = ctx->state.dirty_${s.statename}${'[shader]' if s.per_shader_stage else ''};
+         while ((idx = util_last_bit(idx_mask) - 1) >= 0) {
+            ${s.typename.replace(" *", "")} *ptr;
+            rsq_batch_emit_uint(ctx->batch, rsq_${s.statename}_id);
+% if s.per_shader_stage:
+            rsq_batch_emit_uint(ctx->batch, shader);
+% endif:
+            rsq_batch_emit_uint(ctx->batch, idx);
+            ptr = rsq_batch_emit_buf(ctx->batch, sizeof(*ptr));
+% if s.has_resources:
+            rsq_export_${s.basename}(ptr, &ctx->state.${s.statename}${'[shader]' if s.per_shader_stage else ''}[idx]);
+% else:
+            *ptr = ctx->state.${s.statename}${'[shader]' if s.per_shader_stage else ''}[idx];
+% endif
+            idx_mask &= ~(1 << idx);
+         }
+         ctx->state.dirty_${s.statename}${'[shader]' if s.per_shader_stage else ''} = 0;
+% else:
+         ${s.typename.replace(" *", "")} *ptr;
+         rsq_batch_emit_uint(ctx->batch, rsq_${s.statename}_id);
+         ptr = rsq_batch_emit_buf(ctx->batch, sizeof(*ptr));
+% if s.has_resources:
+         rsq_export_${s.basename}(ptr, &ctx->state.${s.statename}${'[shader]' if s.per_shader_stage else ''});
+% else:
+         *ptr = ctx->state.${s.statename}${'[shader]' if s.per_shader_stage else ''};
+% endif
+% endif
+% if s.per_shader_stage:
+         shader_mask &= ~(1 << shader);
+      }
+      ctx->state.dirty_${s.statename}_shader = 0;
+% endif
+   }
+""")
+
+   __replay_template = mako.template.Template("""
+   case rsq_${s.statename}_id: {
+% if s.per_shader_stage:
+      unsigned stage = rsq_batch_consume_uint(batch);
+% endif
+% if s.length:
+      unsigned i = rsq_batch_consume_uint(batch);
+% endif
+      ${s.typename.replace(" *", "")} *ptr = rsq_batch_consume_buf(batch, sizeof(*ptr));
+      ctx->drv->set_${s.statename}(ctx->drv,
+% if s.per_shader_stage:
+                                   stage,
+% endif
+% if s.length:
+                                   i, ${'1,' if not s.cb_hack else ''} ptr);
+% else:
+                                   ${'*' if not s.typename.endswith("*") else ''}ptr);
+% endif
+% if s.has_resources:
+      util_copy_${s.basename}(ptr, NULL);
+% endif
+      break;
+   }
+""")
+
+   def __init__(self, statename, typename=None, length=None,
+                has_resources=False, per_shader_stage=False):
+      self.statename = statename
+      if typename:
+         self.typename = typename
+      else:
+         self.typename = "struct pipe_" + statename + " *"
+      self.length = length
+
+      # XXX special hack.. TODO fix gallium API to be more uniform..
+      self.cb_hack = statename is "constant_buffer"
+      self.cs_hack = statename is "compute_resource"
+
+      if length is not None and not self.cb_hack:
+         self.statename = self.statename + "s"
+      self.has_resources = has_resources
+      self.per_shader_stage = per_shader_stage
+      self.basename = self.typename.replace("struct pipe_", "").replace(" ", "").replace("*", "")
+
+   def copy_command(self, dst, src):
+      if self.has_resources:
+         return "util_copy_" + self.basename + "(&" + dst + ", val ? " + src + " : NULL)"
+      elif self.typename.endswith("*"):
+         return dst + " = *" + src
+      else:
+         return dst + " = " + src
+
+   def render_type(self):
+      return ""
+
+   def render_id(self):
+      return "rsq_" + self.statename + "_id,"
+
+   def render_funcs(self):
+      return self.__funcs_template.render(s=self)
+
+   def render_setup(self):
+      return self.__setup_template.render(s=self)
+
+   def render_state(self):
+      return self.__state_template.render(s=self)
+
+   def render_emit(self):
+      return self.__emit_template.render(s=self)
+
+   def render_replay(self):
+      return self.__replay_template.render(s=self)
+
+state = [
+   CSO("blend"),
+   CSO("sampler", length="PIPE_MAX_SAMPLERS", per_shader_stage=True),
+   CSO("rasterizer"),
+   CSO("depth_stencil_alpha"),
+   CSO("shader", [ "fs", "vs", "gs", "tcs", "tes" ]),
+   CSO("compute"),
+   CSO("vertex_elements", manual=True),  # create/bind/destroy handled manually..
+   Param("blend_color"),
+   Param("stencil_ref"),
+   Param("sample_mask", "unsigned"),
+   Param("min_samples", "unsigned"),
+   Param("clip_state"),
+   Param("constant_buffer", length="PIPE_MAX_CONSTANT_BUFFERS", has_resources=True, per_shader_stage=True),
+   Param("framebuffer_state", has_resources=True),
+   Param("polygon_stipple", "struct pipe_poly_stipple *"),
+   Param("scissor_state", length="PIPE_MAX_VIEWPORTS"),
+   Param("viewport_state", length="PIPE_MAX_VIEWPORTS"),
+   Param("tess_state"),
+   Param("shader_buffer", length="PIPE_MAX_SHADER_BUFFERS", has_resources=True, per_shader_stage=True),
+   Param("shader_image", "struct pipe_image_view *", length="PIPE_MAX_SHADER_IMAGES", has_resources=True, per_shader_stage=True),
+   Param("vertex_buffer", length="PIPE_MAX_SHADER_INPUTS", has_resources=True),
+   Param("index_buffer", has_resources=True),
+   Param("compute_resource", "struct pipe_surface **", length="PIPE_MAX_SHADER_IMAGES", has_resources=True),
+]
+
+__state_c_template = mako.template.Template("""
+/* GENERATED FILE - DO NOT EDIT */
+#include "pipe/p_context.h"
+#include "pipe/p_state.h"
+#include "util/u_framebuffer.h"
+#include "util/u_memory.h"
+#include "util/u_inlines.h"
+
+#include "rsq_batch.h"
+#include "rsq_context.h"
+#include "rsq_state.h"
+#include "rsq_state_helpers.h"
+
+% for s in state:
+   ${s.render_funcs()}
+% endfor
+
+void rsq_state_context_init(struct pipe_context *pctx)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+
+   debug_assert(rsq_state_count < (8 * sizeof(rsq_context(pctx)->state.dirty)));
+
+% for s in state:
+   ${s.render_setup()}
+% endfor
+}
+
+void rsq_state_emit(struct pipe_context *pctx)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+   unsigned seqno, shader_mask, idx_mask;
+   int idx, shader;
+
+% for s in state:
+   ${s.render_emit()}
+% endfor
+
+   ctx->state.dirty = 0;
+}
+
+void rsq_state_dirty(struct pipe_context *pctx)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+   ctx->state.dirty = ~0;
+}
+
+void rsq_state_replay(struct rsq_batch *batch, enum rsq_state_id id)
+{
+   struct rsq_context *ctx = batch->ctx;
+   switch (id) {
+% for s in state:
+   ${s.render_replay()}
+% endfor
+   default:
+      unreachable("invalid state id");
+   }
+}
+""")
+
+__state_h_template = mako.template.Template("""
+/* GENERATED FILE - DO NOT EDIT */
+#ifndef RSQ_STATE_H
+#define RSQ_STATE_H
+
+#include "pipe/p_context.h"
+#include "pipe/p_state.h"
+
+enum rsq_state_id {
+% for s in state:
+   ${s.render_id()}
+% endfor
+
+   /* handled specially, since it doesn't fit the mold: */
+   rsq_sampler_view_id,
+   rsq_stream_output_target_id,
+
+   rsq_state_count,
+
+   /* it is convenient to use the same header for draw/blit/etc: */
+   rsq_string_marker_cmd,
+   rsq_draw_cmd,
+   rsq_clear_cmd,
+   rsq_launch_grid_cmd,
+   rsq_copy_region_cmd,
+   rsq_blit_cmd,
+};
+
+% for s in state:
+   ${s.render_type()}
+% endfor
+
+struct rsq_state {
+   unsigned dirty;
+% for s in state:
+   ${s.render_state()}
+% endfor
+};
+
+void rsq_state_context_init(struct pipe_context *pctx);
+void rsq_state_emit(struct pipe_context *pctx);
+void rsq_state_dirty(struct pipe_context *pctx);
+
+struct rsq_batch;
+void rsq_state_replay(struct rsq_batch *batch, enum rsq_state_id id);
+
+#endif /* RSQ_STATE_H */
+""")
+
+if sys.argv[1] == "-c":
+   print(__state_c_template.render(state=state))
+elif sys.argv[1] == "-h":
+   print(__state_h_template.render(state=state))
+else:
+   print("unknown arg: " + sys.argv[1])
diff --git a/src/gallium/drivers/resequencer/rsq_state_helpers.h b/src/gallium/drivers/resequencer/rsq_state_helpers.h
new file mode 100644
index 0000000..8c300c1
--- /dev/null
+++ b/src/gallium/drivers/resequencer/rsq_state_helpers.h
@@ -0,0 +1,219 @@
+/*
+ * Copyright © 2016 Red Hat
+ *
+ * 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
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 RSQ_STATE_HELPERS_H
+#define RSQ_STATE_HELPERS_H
+
+#include "rsq_resource.h"
+#include "rsq_surface.h"
+
+/* helpers for the auto-generated state code */
+
+static inline void util_copy_surface(struct pipe_surface **dst,
+                                     struct pipe_surface **src)
+{
+   pipe_surface_reference(dst, *src);
+}
+
+/* a few of the state objects handled manually: */
+
+struct rsq_vertex_elements_state {
+   struct pipe_reference reference;
+   void *drv;
+};
+
+static inline void *
+rsq_create_vertex_elements_state(struct pipe_context *pctx,
+                                 unsigned num_elements,
+                                 const struct pipe_vertex_element *elems)
+{
+   struct rsq_context *ctx = rsq_context(pctx);
+   struct rsq_vertex_elements_state *so = CALLOC_STRUCT(rsq_vertex_elements_state);
+   if (!so)
+      return NULL;
+   so->drv = ctx->drv->create_vertex_elements_state(ctx->drv, num_elements, elems);
+   if (!so->drv) {
+      free(so);
+      return NULL;
+   }
+   pipe_reference_init(&so->reference, 1);
+   return so;
+}
+
+/*
+ * Seqno/export helpers.. any state that directly or indirectly
+ * references a pipe_surface gets a sequence # which is defined
+ * of the MAX of the sequence # of any referenced rsq_resource-s.
+ * If a resource is shadowed then it's seqno is bumped, so this
+ * lets us know when we need to apply otherwise clean state to
+ * underlying driver.
+ *
+ * The export helpers act like util_copy_${state}() except that
+ * they replace the rsq_resource's in the src struct with driver
+ * resource.
+ */
+
+static inline unsigned
+rsq_constant_buffer_seqno(const struct pipe_constant_buffer *cb)
+{
+   debug_assert(!cb->user_buffer);
+   return seqno(cb->buffer);
+}
+
+static inline void
+rsq_export_constant_buffer(struct pipe_constant_buffer *dst,
+                           const struct pipe_constant_buffer *src)
+{
+   dst->buffer = NULL;
+   pipe_resource_reference(&dst->buffer, unwrap(src->buffer));
+   dst->buffer_offset = src->buffer_offset;
+   dst->buffer_size = src->buffer_size;
+   dst->user_buffer = src->user_buffer;
+}
+
+
+static inline unsigned
+rsq_shader_buffer_seqno(const struct pipe_shader_buffer *sb)
+{
+   return seqno(sb->buffer);
+}
+
+static inline void
+rsq_export_shader_buffer(struct pipe_shader_buffer *dst,
+                         const struct pipe_shader_buffer *src)
+{
+   dst->buffer = NULL;
+   pipe_resource_reference(&dst->buffer, unwrap(src->buffer));
+   dst->buffer_offset = src->buffer_offset;
+   dst->buffer_size = src->buffer_size;
+}
+
+
+static inline unsigned
+rsq_image_view_seqno(const struct pipe_image_view *cb)
+{
+   return seqno(cb->resource);
+}
+
+static inline void
+rsq_export_image_view(struct pipe_image_view *dst,
+                      const struct pipe_image_view *src)
+{
+   dst->resource = NULL;
+   pipe_resource_reference(&dst->resource, unwrap(src->resource));
+   dst->format = src->format;
+   dst->access = src->access;
+   dst->u = src->u;
+}
+
+
+static inline unsigned
+rsq_vertex_buffer_seqno(const struct pipe_vertex_buffer *vb)
+{
+   debug_assert(!vb->user_buffer);
+   return seqno(vb->buffer);
+}
+
+static inline void
+rsq_export_vertex_buffer(struct pipe_vertex_buffer *dst,
+                         const struct pipe_vertex_buffer *src)
+{
+   dst->stride = src->stride;
+   dst->buffer_offset = src->buffer_offset;
+   dst->buffer = NULL;
+   pipe_resource_reference(&dst->buffer, unwrap(src->buffer));
+   dst->user_buffer = src->user_buffer;
+}
+
+
+static inline unsigned
+rsq_index_buffer_seqno(const struct pipe_index_buffer *ib)
+{
+   debug_assert(!ib->user_buffer);
+   return seqno(ib->buffer);
+}
+
+static inline void
+rsq_export_index_buffer(struct pipe_index_buffer *dst,
+                        const struct pipe_index_buffer *src)
+{
+   dst->index_size = src->index_size;
+   dst->offset = src->offset;
+   dst->buffer = NULL;
+   pipe_resource_reference(&dst->buffer, unwrap(src->buffer));
+   dst->user_buffer = src->user_buffer;
+}
+
+
+static inline unsigned
+rsq_surface_seqno(struct pipe_surface **surf)
+{
+   return seqno_surf(*surf);
+}
+
+static inline void rsq_export_surface(struct pipe_surface **dst,
+                                      struct pipe_surface **src)
+{
+   *dst = NULL;
+   pipe_surface_reference(dst, unwrap_surf(*src));
+}
+
+
+static inline unsigned
+rsq_framebuffer_state_seqno(const struct pipe_framebuffer_state *pfb)
+{
+   unsigned i, n = 0;
+   for (i = 0; i < pfb->nr_cbufs; i++)
+      n = MAX2(n, seqno_surf(pfb->cbufs[i]));
+   n = MAX2(n, seqno_surf(pfb->zsbuf));
+   return n;
+}
+
+static inline void
+rsq_export_framebuffer_state(struct pipe_framebuffer_state *dst,
+                             const struct pipe_framebuffer_state *src)
+{
+   unsigned i;
+
+   dst->width = src->width;
+   dst->height = src->height;
+
+   dst->samples = src->samples;
+   dst->layers  = src->layers;
+
+   for (i = 0; i < src->nr_cbufs; i++) {
+      dst->cbufs[i] = NULL;
+      pipe_surface_reference(&dst->cbufs[i], unwrap_surf(src->cbufs[i]));
+   }
+
+   /* Set remaining dest cbuf pointers to NULL */
+   for ( ; i < ARRAY_SIZE(dst->cbufs); i++)
+      dst->cbufs[i] = NULL;
+
+   dst->nr_cbufs = src->nr_cbufs;
+
+   dst->zsbuf = NULL;
+   pipe_surface_reference(&dst->zsbuf, unwrap_surf(src->zsbuf));
+}
+
+#endif /* RSQ_STATE_HELPERS_H */
diff --git a/src/gallium/drivers/resequencer/rsq_surface.c b/src/gallium/drivers/resequencer/rsq_surface.c
new file mode 100644
index 0000000..0164d29
--- /dev/null
+++ b/src/gallium/drivers/resequencer/rsq_surface.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright © 2016 Red Hat
+ *
+ * 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
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 "util/u_inlines.h"
+#include "util/u_memory.h"
+
+#include "rsq_context.h"
+#include "rsq_resource.h"
+#include "rsq_surface.h"
+
+/* (re)allocate backing driver surface: */
+static void get_driver_surface(struct pipe_surface *psurf)
+{
+   struct rsq_surface *surf = rsq_surface(psurf);
+   struct rsq_context *ctx = rsq_context(psurf->context);
+   struct rsq_resource *rsc = rsq_resource(psurf->texture);
+
+   pipe_surface_reference(&surf->drv, NULL);
+
+   surf->drv = ctx->drv->create_surface(ctx->drv, rsc->drv, psurf);
+   surf->rsc_seqno = rsc->seqno;
+   surf->seqno = ctx->surf_cnt++;
+}
+
+unsigned rsq_surface_validate(struct pipe_surface *psurf)
+{
+   struct rsq_surface *surf = rsq_surface(psurf);
+
+   /* recreate driver surface if backing resource has been shadowed: */
+   if (rsq_resource(psurf->texture)->seqno != surf->rsc_seqno)
+      get_driver_surface(psurf);
+
+   return surf->seqno;
+}
+
+struct pipe_surface* rsq_create_surface(struct pipe_context *pctx,
+                                        struct pipe_resource *ptex,
+                                        const struct pipe_surface *surf_tmpl)
+{
+   struct rsq_surface *surf;
+
+   /* TODO we almost certainly want a sort of cache to avoid creating duplicate
+    * surfaces for the same rsc + surf_tmpl.  Cache needs to be big enough for
+    * 2x max mip-levels, I think.   After rendering is flushed to driver would
+    * be a good time to clean cache to avoid hanging on to ref's to resources
+    * too long.
+    */
+
+   surf = CALLOC_STRUCT(rsq_surface);
+
+   if (!surf)
+      return NULL;
+
+   struct pipe_surface *psurf = &surf->base;
+   unsigned level = surf_tmpl->u.tex.level;
+
+   *psurf = *surf_tmpl;
+
+   pipe_reference_init(&psurf->reference, 1);
+   pipe_resource_reference(&psurf->texture, ptex);
+   psurf->context = pctx;
+   psurf->format = surf_tmpl->format;
+   psurf->width = u_minify(ptex->width0, level);
+   psurf->height = u_minify(ptex->height0, level);
+   psurf->u.tex.level = level;
+   psurf->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
+   psurf->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
+
+   get_driver_surface(psurf);
+   if (!surf->drv) {
+      pipe_resource_reference(&psurf->texture, NULL);
+      free(surf);
+      return NULL;
+   }
+
+   return &surf->base;
+}
+
+void rsq_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf)
+{
+   struct rsq_surface *surf = rsq_surface(psurf);
+
+   pipe_surface_reference(&surf->drv, NULL);
+   pipe_resource_reference(&psurf->texture, NULL);
+
+   FREE(psurf);
+}
diff --git a/src/gallium/drivers/resequencer/rsq_surface.h b/src/gallium/drivers/resequencer/rsq_surface.h
new file mode 100644
index 0000000..e46b754
--- /dev/null
+++ b/src/gallium/drivers/resequencer/rsq_surface.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright © 2016 Red Hat
+ *
+ * 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
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 RSQ_SURFACE_H
+#define RSQ_SURFACE_H
+
+#include "pipe/p_state.h"
+
+struct rsq_surface {
+   struct pipe_surface base;
+
+   struct pipe_surface *drv;      /* driver's surface */
+
+   unsigned rsc_seqno;
+
+   /* Each surface gets an incrementing sequence # which is used in the
+    * sanitized fb state key into batch hashtable.  This avoids using
+    * pointer values in a key (since a surface could be destroyed and
+    * re-allocated with the same pointer address:
+    */
+   unsigned seqno;
+};
+
+static inline struct rsq_surface * rsq_surface(struct pipe_surface *psurf)
+{
+   return (struct rsq_surface *)psurf;
+}
+
+unsigned rsq_surface_validate(struct pipe_surface *psurf);
+
+struct pipe_surface* rsq_create_surface(struct pipe_context *pctx,
+                                        struct pipe_resource *ptex,
+                                        const struct pipe_surface *surf_tmpl);
+void rsq_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf);
+
+
+static inline unsigned seqno_surf(struct pipe_surface *psurf)
+{
+   if (!psurf)
+      return 0;
+   return rsq_surface_validate(psurf);
+}
+
+static inline struct pipe_surface * unwrap_surf(struct pipe_surface *psurf)
+{
+   if (!psurf)
+      return NULL;
+   /* NOTE: assumes seqno_surf()/rsq_surface_validate() already called: */
+   return rsq_surface(psurf)->drv;
+}
+
+#endif /* RSQ_SURFACE_H */
-- 
2.5.5



More information about the mesa-dev mailing list