Mesa (master): gallium: Make sure we flush before some texture / buffer operations.

Thomas Hellstrom thomash at kemper.freedesktop.org
Thu Apr 16 08:30:54 UTC 2009


Module: Mesa
Branch: master
Commit: 9b75627fab5bf2ea90f27ddd31b60c54895f6de6
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=9b75627fab5bf2ea90f27ddd31b60c54895f6de6

Author: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
Date:   Wed Apr 15 15:53:34 2009 +0200

gallium: Make sure we flush before some texture / buffer operations.

Also implement context member functions to optimize away those
flushes whenever possible.

Signed-off-by: Thomas Hellstrom <thellstrom-at-vmware-dot-com>

---

 src/gallium/drivers/cell/ppu/cell_context.c   |   25 ++++++++++++++
 src/gallium/drivers/failover/fo_context.c     |   23 +++++++++++++
 src/gallium/drivers/i915simple/i915_context.c |   26 ++++++++++++++
 src/gallium/drivers/i965simple/brw_context.c  |   25 ++++++++++++++
 src/gallium/drivers/nv04/nv04_context.c       |   27 +++++++++++++++
 src/gallium/drivers/nv10/nv10_context.c       |   26 ++++++++++++++
 src/gallium/drivers/nv20/nv20_context.c       |   27 +++++++++++++++
 src/gallium/drivers/nv30/nv30_context.c       |   26 ++++++++++++++
 src/gallium/drivers/nv40/nv40_context.c       |   26 ++++++++++++++
 src/gallium/drivers/nv50/nv50_context.c       |   26 ++++++++++++++
 src/gallium/drivers/softpipe/sp_context.c     |   18 ++++++++++
 src/gallium/drivers/trace/tr_context.c        |   44 +++++++++++++++++++++++++
 src/gallium/include/pipe/p_context.h          |   29 ++++++++++++++++-
 src/gallium/include/pipe/p_defines.h          |    7 ++++
 src/mesa/state_tracker/st_cb_accum.c          |   36 +++++++++++++++++---
 src/mesa/state_tracker/st_cb_bufferobjects.c  |   16 ++++++++-
 src/mesa/state_tracker/st_cb_drawpixels.c     |    8 +++-
 src/mesa/state_tracker/st_cb_readpixels.c     |   10 +++++-
 src/mesa/state_tracker/st_cb_texture.c        |   17 +++++++++
 src/mesa/state_tracker/st_gen_mipmap.c        |    7 ++++
 src/mesa/state_tracker/st_texture.c           |   22 ++++++++++++-
 src/mesa/state_tracker/st_texture.h           |    7 +++-
 22 files changed, 466 insertions(+), 12 deletions(-)

diff --git a/src/gallium/drivers/cell/ppu/cell_context.c b/src/gallium/drivers/cell/ppu/cell_context.c
index 808be58..ebb7a7a 100644
--- a/src/gallium/drivers/cell/ppu/cell_context.c
+++ b/src/gallium/drivers/cell/ppu/cell_context.c
@@ -99,6 +99,28 @@ static const struct debug_named_value cell_debug_flags[] = {
    {NULL, 0}
 };
 
+static unsigned int
+cell_is_texture_referenced( struct pipe_context *pipe,
+			    struct pipe_texture *texture,
+			    unsigned face, unsigned level)
+{
+   /**
+    * FIXME: Optimize.
+    */
+
+   return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
+}
+
+static unsigned int
+cell_is_buffer_referenced( struct pipe_context *pipe,
+			   struct pipe_buffer *buf)
+{
+   /**
+    * FIXME: Optimize.
+    */
+
+   return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
+}
 
 struct pipe_context *
 cell_create_context(struct pipe_screen *screen,
@@ -122,6 +144,9 @@ cell_create_context(struct pipe_screen *screen,
    cell->pipe.clear = cell_clear;
    cell->pipe.flush = cell_flush;
 
+   cell->pipe.is_texture_referenced = cell_is_texture_referenced;
+   cell->pipe.is_buffer_referenced = cell_is_buffer_referenced;
+
 #if 0
    cell->pipe.begin_query = cell_begin_query;
    cell->pipe.end_query = cell_end_query;
diff --git a/src/gallium/drivers/failover/fo_context.c b/src/gallium/drivers/failover/fo_context.c
index fcad717..37184ea 100644
--- a/src/gallium/drivers/failover/fo_context.c
+++ b/src/gallium/drivers/failover/fo_context.c
@@ -105,7 +105,28 @@ static boolean failover_draw_arrays( struct pipe_context *pipe,
    return failover_draw_elements(pipe, NULL, 0, prim, start, count);
 }
 
+static unsigned int
+failover_is_texture_referenced( struct pipe_context *_pipe,
+				struct pipe_texture *texture,
+				unsigned face, unsigned level)
+{
+   struct failover_context *failover = failover_context( _pipe );
+   struct pipe_context *pipe = (failover->mode == FO_HW) ?
+      failover->hw : failover->sw;
+
+   return pipe->is_texture_referenced(pipe, texture, face, level);
+}
 
+static unsigned int
+failover_is_buffer_referenced( struct pipe_context *_pipe,
+			       struct pipe_buffer *buf)
+{
+   struct failover_context *failover = failover_context( _pipe );
+   struct pipe_context *pipe = (failover->mode == FO_HW) ?
+      failover->hw : failover->sw;
+
+   return pipe->is_buffer_referenced(pipe, buf);
+}
 
 struct pipe_context *failover_create( struct pipe_context *hw,
 				      struct pipe_context *sw )
@@ -151,6 +172,8 @@ struct pipe_context *failover_create( struct pipe_context *hw,
 #endif
 
    failover->pipe.flush = hw->flush;
+   failover->pipe.is_texture_referenced = failover_is_texture_referenced;
+   failover->pipe.is_buffer_referenced = failover_is_buffer_referenced;
 
    failover->dirty = 0;
 
diff --git a/src/gallium/drivers/i915simple/i915_context.c b/src/gallium/drivers/i915simple/i915_context.c
index 3e3a596..ccf9bb3 100644
--- a/src/gallium/drivers/i915simple/i915_context.c
+++ b/src/gallium/drivers/i915simple/i915_context.c
@@ -136,6 +136,29 @@ static boolean i915_draw_arrays( struct pipe_context *pipe,
 }
 
 
+static unsigned int
+i915_is_texture_referenced( struct pipe_context *pipe,
+			    struct pipe_texture *texture,
+			    unsigned face, unsigned level)
+{
+   /**
+    * FIXME: Optimize.
+    */
+
+   return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
+}
+
+static unsigned int
+i915_is_buffer_referenced( struct pipe_context *pipe,
+			   struct pipe_buffer *buf)
+{
+   /**
+    * FIXME: Optimize.
+    */
+
+   return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
+}
+
 
 struct pipe_context *i915_create_context( struct pipe_screen *screen,
                                           struct pipe_winsys *pipe_winsys,
@@ -160,6 +183,9 @@ struct pipe_context *i915_create_context( struct pipe_screen *screen,
    i915->pipe.draw_elements = i915_draw_elements;
    i915->pipe.draw_range_elements = i915_draw_range_elements;
 
+   i915->pipe.is_texture_referenced = i915_is_texture_referenced;
+   i915->pipe.is_buffer_referenced = i915_is_buffer_referenced;
+
    /*
     * Create drawing context and plug our rendering stage into it.
     */
diff --git a/src/gallium/drivers/i965simple/brw_context.c b/src/gallium/drivers/i965simple/brw_context.c
index c74cbf8..9b33285 100644
--- a/src/gallium/drivers/i965simple/brw_context.c
+++ b/src/gallium/drivers/i965simple/brw_context.c
@@ -73,6 +73,28 @@ static void brw_clear(struct pipe_context *pipe, struct pipe_surface *ps,
    pipe->surface_fill(pipe, ps, x, y, w, h, clearValue);
 }
 
+static unsigned int
+brw_is_texture_referenced( struct pipe_context *pipe,
+			   struct pipe_texture *texture,
+			   unsigned face, unsigned level)
+{
+   /**
+    * FIXME: Optimize.
+    */
+
+   return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
+}
+
+static unsigned int
+brw_is_buffer_referenced( struct pipe_context *pipe,
+			  struct pipe_buffer *buf)
+{
+   /**
+    * FIXME: Optimize.
+    */
+
+   return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
+}
 
 struct pipe_context *brw_create(struct pipe_screen *screen,
                                 struct brw_winsys *brw_winsys,
@@ -94,6 +116,9 @@ struct pipe_context *brw_create(struct pipe_screen *screen,
    brw->pipe.destroy = brw_destroy;
    brw->pipe.clear = brw_clear;
 
+   brw->pipe.is_texture_referenced = brw_is_texture_referenced;
+   brw->pipe.is_buffer_referenced = brw_is_buffer_referenced;
+
    brw_init_surface_functions(brw);
    brw_init_texture_functions(brw);
    brw_init_state_functions(brw);
diff --git a/src/gallium/drivers/nv04/nv04_context.c b/src/gallium/drivers/nv04/nv04_context.c
index d6710cd..17166c9 100644
--- a/src/gallium/drivers/nv04/nv04_context.c
+++ b/src/gallium/drivers/nv04/nv04_context.c
@@ -64,6 +64,30 @@ nv04_init_hwctx(struct nv04_context *nv04)
 	return TRUE;
 }
 
+static unsigned int
+nv04_is_texture_referenced( struct pipe_context *pipe,
+			    struct pipe_texture *texture,
+			    unsigned face, unsigned level)
+{
+   /**
+    * FIXME: Optimize.
+    */
+
+   return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
+}
+
+static unsigned int
+nv04_is_buffer_referenced( struct pipe_context *pipe,
+			   struct pipe_buffer *buf)
+{
+   /**
+    * FIXME: Optimize.
+    */
+
+   return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
+}
+
+
 struct pipe_context *
 nv04_create(struct pipe_screen *pscreen, unsigned pctx_id)
 {
@@ -89,6 +113,9 @@ nv04_create(struct pipe_screen *pscreen, unsigned pctx_id)
 	nv04->pipe.clear = nv04_clear;
 	nv04->pipe.flush = nv04_flush;
 
+	nv04->pipe.is_texture_referenced = nv04_is_texture_referenced;
+	nv04->pipe.is_buffer_referenced = nv04_is_buffer_referenced;
+
 	nv04_init_surface_functions(nv04);
 	nv04_init_state_functions(nv04);
 
diff --git a/src/gallium/drivers/nv10/nv10_context.c b/src/gallium/drivers/nv10/nv10_context.c
index ef2c0c5..3da8d2f 100644
--- a/src/gallium/drivers/nv10/nv10_context.c
+++ b/src/gallium/drivers/nv10/nv10_context.c
@@ -257,6 +257,29 @@ nv10_set_edgeflags(struct pipe_context *pipe, const unsigned *bitfield)
 {
 }
 
+static unsigned int
+nv10_is_texture_referenced( struct pipe_context *pipe,
+			    struct pipe_texture *texture,
+			    unsigned face, unsigned level)
+{
+   /**
+    * FIXME: Optimize.
+    */
+
+   return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
+}
+
+static unsigned int
+nv10_is_buffer_referenced( struct pipe_context *pipe,
+			   struct pipe_buffer *buf)
+{
+   /**
+    * FIXME: Optimize.
+    */
+
+   return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
+}
+
 struct pipe_context *
 nv10_create(struct pipe_screen *pscreen, unsigned pctx_id)
 {
@@ -282,6 +305,9 @@ nv10_create(struct pipe_screen *pscreen, unsigned pctx_id)
 	nv10->pipe.clear = nv10_clear;
 	nv10->pipe.flush = nv10_flush;
 
+	nv10->pipe.is_texture_referenced = nv10_is_texture_referenced;
+	nv10->pipe.is_buffer_referenced = nv10_is_buffer_referenced;
+
 	nv10_init_surface_functions(nv10);
 	nv10_init_state_functions(nv10);
 
diff --git a/src/gallium/drivers/nv20/nv20_context.c b/src/gallium/drivers/nv20/nv20_context.c
index 1659aec..cbc4170 100644
--- a/src/gallium/drivers/nv20/nv20_context.c
+++ b/src/gallium/drivers/nv20/nv20_context.c
@@ -380,6 +380,30 @@ nv20_set_edgeflags(struct pipe_context *pipe, const unsigned *bitfield)
 {
 }
 
+
+static unsigned int
+nv20_is_texture_referenced( struct pipe_context *pipe,
+			    struct pipe_texture *texture,
+			    unsigned face, unsigned level)
+{
+   /**
+    * FIXME: Optimize.
+    */
+
+   return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
+}
+
+static unsigned int
+nv20_is_buffer_referenced( struct pipe_context *pipe,
+			   struct pipe_buffer *buf)
+{
+   /**
+    * FIXME: Optimize.
+    */
+
+   return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
+}
+
 struct pipe_context *
 nv20_create(struct pipe_screen *pscreen, unsigned pctx_id)
 {
@@ -405,6 +429,9 @@ nv20_create(struct pipe_screen *pscreen, unsigned pctx_id)
 	nv20->pipe.clear = nv20_clear;
 	nv20->pipe.flush = nv20_flush;
 
+	nv20->pipe.is_texture_referenced = nv20_is_texture_referenced;
+	nv20->pipe.is_buffer_referenced = nv20_is_buffer_referenced;
+
 	nv20_init_surface_functions(nv20);
 	nv20_init_state_functions(nv20);
 
diff --git a/src/gallium/drivers/nv30/nv30_context.c b/src/gallium/drivers/nv30/nv30_context.c
index 61654f8..f827bdc 100644
--- a/src/gallium/drivers/nv30/nv30_context.c
+++ b/src/gallium/drivers/nv30/nv30_context.c
@@ -31,6 +31,29 @@ nv30_destroy(struct pipe_context *pipe)
 	FREE(nv30);
 }
 
+static unsigned int
+nv30_is_texture_referenced( struct pipe_context *pipe,
+			    struct pipe_texture *texture,
+			    unsigned face, unsigned level)
+{
+   /**
+    * FIXME: Optimize.
+    */
+
+   return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
+}
+
+static unsigned int
+nv30_is_buffer_referenced( struct pipe_context *pipe,
+			   struct pipe_buffer *buf)
+{
+   /**
+    * FIXME: Optimize.
+    */
+
+   return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
+}
+
 struct pipe_context *
 nv30_create(struct pipe_screen *pscreen, unsigned pctx_id)
 {
@@ -55,6 +78,9 @@ nv30_create(struct pipe_screen *pscreen, unsigned pctx_id)
 	nv30->pipe.clear = nv30_clear;
 	nv30->pipe.flush = nv30_flush;
 
+	nv30->pipe.is_texture_referenced = nv30_is_texture_referenced;
+	nv30->pipe.is_buffer_referenced = nv30_is_buffer_referenced;
+
 	nv30_init_query_functions(nv30);
 	nv30_init_surface_functions(nv30);
 	nv30_init_state_functions(nv30);
diff --git a/src/gallium/drivers/nv40/nv40_context.c b/src/gallium/drivers/nv40/nv40_context.c
index 5d325f5..8eba6a4 100644
--- a/src/gallium/drivers/nv40/nv40_context.c
+++ b/src/gallium/drivers/nv40/nv40_context.c
@@ -31,6 +31,29 @@ nv40_destroy(struct pipe_context *pipe)
 	FREE(nv40);
 }
 
+static unsigned int
+nv40_is_texture_referenced( struct pipe_context *pipe,
+			    struct pipe_texture *texture,
+			    unsigned face, unsigned level)
+{
+   /**
+    * FIXME: Optimize.
+    */
+
+   return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
+}
+
+static unsigned int
+nv40_is_buffer_referenced( struct pipe_context *pipe,
+			   struct pipe_buffer *buf)
+{
+   /**
+    * FIXME: Optimize.
+    */
+
+   return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
+}
+
 struct pipe_context *
 nv40_create(struct pipe_screen *pscreen, unsigned pctx_id)
 {
@@ -55,6 +78,9 @@ nv40_create(struct pipe_screen *pscreen, unsigned pctx_id)
 	nv40->pipe.clear = nv40_clear;
 	nv40->pipe.flush = nv40_flush;
 
+	nv40->pipe.is_texture_referenced = nv40_is_texture_referenced;
+	nv40->pipe.is_buffer_referenced = nv40_is_buffer_referenced;
+
 	nv40_init_query_functions(nv40);
 	nv40_init_surface_functions(nv40);
 	nv40_init_state_functions(nv40);
diff --git a/src/gallium/drivers/nv50/nv50_context.c b/src/gallium/drivers/nv50/nv50_context.c
index 565a5da..a511f65 100644
--- a/src/gallium/drivers/nv50/nv50_context.c
+++ b/src/gallium/drivers/nv50/nv50_context.c
@@ -51,6 +51,29 @@ nv50_set_edgeflags(struct pipe_context *pipe, const unsigned *bitfield)
 {
 }
 
+static unsigned int
+nv50_is_texture_referenced( struct pipe_context *pipe,
+			    struct pipe_texture *texture,
+			    unsigned face, unsigned level)
+{
+   /**
+    * FIXME: Optimize.
+    */
+
+   return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
+}
+
+static unsigned int
+nv50_is_buffer_referenced( struct pipe_context *pipe,
+			   struct pipe_buffer *buf)
+{
+   /**
+    * FIXME: Optimize.
+    */
+
+   return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
+}
+
 struct pipe_context *
 nv50_create(struct pipe_screen *pscreen, unsigned pctx_id)
 {
@@ -76,6 +99,9 @@ nv50_create(struct pipe_screen *pscreen, unsigned pctx_id)
 
 	nv50->pipe.flush = nv50_flush;
 
+	nv50->pipe.is_texture_referenced = nv50_is_texture_referenced;
+	nv50->pipe.is_buffer_referenced = nv50_is_buffer_referenced;
+
 	nv50_init_surface_functions(nv50);
 	nv50_init_state_functions(nv50);
 	nv50_init_query_functions(nv50);
diff --git a/src/gallium/drivers/softpipe/sp_context.c b/src/gallium/drivers/softpipe/sp_context.c
index 06ace27..6ae4d1a 100644
--- a/src/gallium/drivers/softpipe/sp_context.c
+++ b/src/gallium/drivers/softpipe/sp_context.c
@@ -121,6 +121,21 @@ static void softpipe_destroy( struct pipe_context *pipe )
    FREE( softpipe );
 }
 
+static unsigned int
+softpipe_is_texture_referenced( struct pipe_context *pipe,
+				struct pipe_texture *texture,
+				unsigned face, unsigned level,
+				unsigned zslice)
+{
+   return PIPE_UNREFERENCED;
+}
+
+static unsigned int
+softpipe_is_buffer_referenced( struct pipe_context *pipe,
+			       struct pipe_buffer *buf)
+{
+   return PIPE_UNREFERENCED;
+}
 
 struct pipe_context *
 softpipe_create( struct pipe_screen *screen,
@@ -190,6 +205,9 @@ softpipe_create( struct pipe_screen *screen,
    softpipe->pipe.clear = softpipe_clear;
    softpipe->pipe.flush = softpipe_flush;
 
+   softpipe->pipe.is_texture_referenced = softpipe_is_texture_referenced;
+   softpipe->pipe.is_buffer_referenced = softpipe_is_buffer_referenced;
+
    softpipe_init_query_funcs( softpipe );
    softpipe_init_texture_funcs( softpipe );
 
diff --git a/src/gallium/drivers/trace/tr_context.c b/src/gallium/drivers/trace/tr_context.c
index d8d5821..556b5e0 100644
--- a/src/gallium/drivers/trace/tr_context.c
+++ b/src/gallium/drivers/trace/tr_context.c
@@ -1030,6 +1030,48 @@ trace_context_destroy(struct pipe_context *_pipe)
    FREE(tr_ctx);
 }
 
+static unsigned int
+trace_is_texture_referenced( struct pipe_context *_pipe,
+			    struct pipe_texture *texture,
+			    unsigned face, unsigned level)
+{
+   struct trace_context *tr_ctx = trace_context(_pipe);
+   struct pipe_context *pipe = tr_ctx->pipe;
+   unsigned int referenced;
+
+   trace_dump_call_begin("pipe_context", "is_texture_referenced");
+   trace_dump_arg(ptr, pipe);
+   trace_dump_arg(ptr, texture);
+   trace_dump_arg(uint, face);
+   trace_dump_arg(uint, level);
+
+   referenced = pipe->is_texture_referenced(pipe, texture, face, level);
+
+   trace_dump_ret(uint, referenced);
+   trace_dump_call_end();
+
+   return referenced;
+}
+
+static unsigned int
+trace_is_buffer_referenced( struct pipe_context *_pipe,
+			    struct pipe_buffer *buf)
+{
+   struct trace_context *tr_ctx = trace_context(_pipe);
+   struct pipe_context *pipe = tr_ctx->pipe;
+   unsigned int referenced;
+
+   trace_dump_call_begin("pipe_context", "is_buffer_referenced");
+   trace_dump_arg(ptr, pipe);
+   trace_dump_arg(ptr, buf);
+
+   referenced = pipe->is_buffer_referenced(pipe, buf);
+
+   trace_dump_ret(uint, referenced);
+   trace_dump_call_end();
+
+   return referenced;
+}
 
 struct pipe_context *
 trace_context_create(struct pipe_screen *_screen,
@@ -1096,6 +1138,8 @@ trace_context_create(struct pipe_screen *_screen,
    tr_ctx->base.surface_fill = trace_context_surface_fill;
    tr_ctx->base.clear = trace_context_clear;
    tr_ctx->base.flush = trace_context_flush;
+   tr_ctx->base.is_texture_referenced = trace_is_texture_referenced;
+   tr_ctx->base.is_buffer_referenced = trace_is_buffer_referenced;
 
    tr_ctx->pipe = pipe;
 
diff --git a/src/gallium/include/pipe/p_context.h b/src/gallium/include/pipe/p_context.h
index c5c8397..57e966a 100644
--- a/src/gallium/include/pipe/p_context.h
+++ b/src/gallium/include/pipe/p_context.h
@@ -42,7 +42,6 @@ struct pipe_state_cache;
 struct pipe_query;
 struct pipe_winsys;
 
-
 /**
  * Gallium rendering context.  Basically:
  *  - state setting functions
@@ -231,6 +230,34 @@ struct pipe_context {
    void (*flush)( struct pipe_context *pipe,
                   unsigned flags,
                   struct pipe_fence_handle **fence );
+
+   /**
+    * Check whether a texture is referenced by an unflushed hw command.
+    * The state-tracker uses this function to optimize away unnecessary
+    * flushes. It is safe (but wasteful) to always return.
+    * PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE.
+    * \param pipe  The pipe context whose unflushed hw commands will be
+    *              checked.
+    * \param level  mipmap level.
+    * \param texture  texture to check.
+    * \param face  cubemap face. Use 0 for non-cubemap texture.
+    */
+
+   unsigned int (*is_texture_referenced) (struct pipe_context *pipe,
+					  struct pipe_texture *texture,
+					  unsigned face, unsigned level);
+   /**
+    * Check whether a buffer is referenced by an unflushed hw command.
+    * The state-tracker uses this function to optimize away unnecessary
+    * flushes. It is safe (but wasteful) to always return
+    * PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE.
+    * \param pipe  The pipe context whose unflushed hw commands will be
+    *              checked.
+    * \param buf  Buffer to check.
+    */
+
+   unsigned int (*is_buffer_referenced) (struct pipe_context *pipe,
+					 struct pipe_buffer *buf);
 };
 
 
diff --git a/src/gallium/include/pipe/p_defines.h b/src/gallium/include/pipe/p_defines.h
index 1d2aa10..82e23c4 100644
--- a/src/gallium/include/pipe/p_defines.h
+++ b/src/gallium/include/pipe/p_defines.h
@@ -312,6 +312,13 @@ enum pipe_transfer_usage {
 #define PIPE_CAP_MAX_VERTEX_TEXTURE_UNITS 26
 
 
+/**
+ * Referenced query flags.
+ */
+
+#define PIPE_UNREFERENCED         0
+#define PIPE_REFERENCED_FOR_READ  (1 << 0)
+#define PIPE_REFERENCED_FOR_WRITE (1 << 1)
 
 #ifdef __cplusplus
 }
diff --git a/src/mesa/state_tracker/st_cb_accum.c b/src/mesa/state_tracker/st_cb_accum.c
index 3f9a825..1510a1e 100644
--- a/src/mesa/state_tracker/st_cb_accum.c
+++ b/src/mesa/state_tracker/st_cb_accum.c
@@ -40,6 +40,7 @@
 #include "st_draw.h"
 #include "st_public.h"
 #include "st_format.h"
+#include "st_texture.h"
 #include "pipe/p_context.h"
 #include "pipe/p_defines.h"
 #include "pipe/p_inlines.h"
@@ -118,6 +119,9 @@ st_clear_accum_buffer(GLcontext *ctx, struct gl_renderbuffer *rb)
    const GLint height = ctx->DrawBuffer->_Ymax - ypos;
    GLubyte *map;
 
+   st_teximage_flush_before_map(ctx->st, acc_strb->texture, 0, 0,
+				PIPE_TRANSFER_WRITE);
+
    acc_pt = screen->get_tex_transfer(screen, acc_strb->texture, 0, 0, 0,
                                      PIPE_TRANSFER_WRITE, xpos, ypos,
                                      width, height);
@@ -163,6 +167,9 @@ accum_mad(GLcontext *ctx, GLfloat scale, GLfloat bias,
    struct pipe_transfer *acc_pt;
    GLubyte *map;
 
+   st_teximage_flush_before_map(ctx->st, acc_strb->texture, 0, 0,
+				PIPE_TRANSFER_READ_WRITE);
+
    acc_pt = screen->get_tex_transfer(screen, acc_strb->texture, 0, 0, 0,
                                      PIPE_TRANSFER_READ_WRITE, xpos, ypos,
                                      width, height);
@@ -192,20 +199,27 @@ accum_mad(GLcontext *ctx, GLfloat scale, GLfloat bias,
 
 
 static void
-accum_accum(struct pipe_context *pipe, GLfloat value,
+accum_accum(struct st_context *st, GLfloat value,
             GLint xpos, GLint ypos, GLint width, GLint height,
             struct st_renderbuffer *acc_strb,
             struct st_renderbuffer *color_strb)
 {
+   struct pipe_context *pipe = st->pipe;
    struct pipe_screen *screen = pipe->screen;
    struct pipe_transfer *acc_trans, *color_trans;
    GLfloat *colorBuf, *accBuf;
    GLint i;
 
+   st_teximage_flush_before_map(st, acc_strb->texture, 0, 0,
+				PIPE_TRANSFER_READ);
+
    acc_trans = screen->get_tex_transfer(screen, acc_strb->texture, 0, 0, 0,
                                         PIPE_TRANSFER_READ, xpos, ypos,
                                         width, height);
 
+   st_teximage_flush_before_map(st, color_strb->texture, 0, 0,
+				PIPE_TRANSFER_READ);
+
    color_trans = screen->get_tex_transfer(screen, color_strb->texture, 0, 0, 0,
                                           PIPE_TRANSFER_READ, xpos, ypos,
                                           width, height);
@@ -235,20 +249,27 @@ accum_accum(struct pipe_context *pipe, GLfloat value,
 
 
 static void
-accum_load(struct pipe_context *pipe, GLfloat value,
+accum_load(struct st_context *st, GLfloat value,
            GLint xpos, GLint ypos, GLint width, GLint height,
            struct st_renderbuffer *acc_strb,
            struct st_renderbuffer *color_strb)
 {
+   struct pipe_context *pipe = st->pipe;
    struct pipe_screen *screen = pipe->screen;
    struct pipe_transfer *acc_trans, *color_trans;
    GLfloat *buf;
    GLint i;
 
+   st_teximage_flush_before_map(st, acc_strb->texture, 0, 0,
+				PIPE_TRANSFER_WRITE);
+
    acc_trans = screen->get_tex_transfer(screen, acc_strb->texture, 0, 0, 0,
                                         PIPE_TRANSFER_WRITE, xpos, ypos,
                                         width, height);
 
+   st_teximage_flush_before_map(st, color_strb->texture, 0, 0,
+				PIPE_TRANSFER_READ);
+
    color_trans = screen->get_tex_transfer(screen, color_strb->texture, 0, 0, 0,
                                         PIPE_TRANSFER_READ, xpos, ypos,
                                         width, height);
@@ -284,10 +305,16 @@ accum_return(GLcontext *ctx, GLfloat value,
 
    abuf = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
 
+   st_teximage_flush_before_map(ctx->st, acc_strb->texture, 0, 0,
+				PIPE_TRANSFER_READ);
+
    acc_trans = screen->get_tex_transfer(screen, acc_strb->texture, 0, 0, 0,
                                         PIPE_TRANSFER_READ, xpos, ypos,
                                         width, height);
 
+   st_teximage_flush_before_map(ctx->st, color_strb->texture, 0, 0,
+				PIPE_TRANSFER_READ_WRITE);
+
    color_trans = screen->get_tex_transfer(screen, color_strb->texture, 0, 0, 0,
                                           PIPE_TRANSFER_READ_WRITE, xpos, ypos,
                                           width, height);
@@ -325,7 +352,6 @@ static void
 st_Accum(GLcontext *ctx, GLenum op, GLfloat value)
 {
    struct st_context *st = ctx->st;
-   struct pipe_context *pipe = st->pipe;
    struct st_renderbuffer *acc_strb
      = st_renderbuffer(ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer);
    struct st_renderbuffer *color_strb
@@ -352,11 +378,11 @@ st_Accum(GLcontext *ctx, GLenum op, GLfloat value)
       break;
    case GL_ACCUM:
       if (value != 0.0F) {
-         accum_accum(pipe, value, xpos, ypos, width, height, acc_strb, color_strb);
+         accum_accum(st, value, xpos, ypos, width, height, acc_strb, color_strb);
       }
       break;
    case GL_LOAD:
-      accum_load(pipe, value, xpos, ypos, width, height, acc_strb, color_strb);
+      accum_load(st, value, xpos, ypos, width, height, acc_strb, color_strb);
       break;
    case GL_RETURN:
       accum_return(ctx, value, xpos, ypos, width, height, acc_strb, color_strb);
diff --git a/src/mesa/state_tracker/st_cb_bufferobjects.c b/src/mesa/state_tracker/st_cb_bufferobjects.c
index 3651e4a..fdb800f 100644
--- a/src/mesa/state_tracker/st_cb_bufferobjects.c
+++ b/src/mesa/state_tracker/st_cb_bufferobjects.c
@@ -32,6 +32,7 @@
 
 #include "st_context.h"
 #include "st_cb_bufferobjects.h"
+#include "st_public.h"
 
 #include "pipe/p_context.h"
 #include "pipe/p_defines.h"
@@ -103,6 +104,9 @@ st_bufferobj_subdata(GLcontext *ctx,
    if (offset >= st_obj->size || size > (st_obj->size - offset))
       return;
 
+   if (pipe->is_buffer_referenced(pipe, st_obj->buffer))
+      st_flush(st_context(ctx), PIPE_FLUSH_RENDER_CACHE, NULL);
+
    pipe_buffer_write(pipe->screen, st_obj->buffer, offset, size, data);
 }
 
@@ -123,6 +127,10 @@ st_bufferobj_get_subdata(GLcontext *ctx,
    if (offset >= st_obj->size || size > (st_obj->size - offset))
       return;
 
+   if (pipe->is_buffer_referenced(pipe, st_obj->buffer) &
+       PIPE_REFERENCED_FOR_WRITE)
+      st_flush(st_context(ctx), PIPE_FLUSH_RENDER_CACHE, NULL);
+
    pipe_buffer_read(pipe->screen, st_obj->buffer, offset, size, data);
 }
 
@@ -171,7 +179,7 @@ st_bufferobj_data(GLcontext *ctx,
    st_obj->size = size;
 
    if (data)
-      st_bufferobj_subdata(ctx, target, 0, size, data, obj);
+      pipe_buffer_write(pipe->screen, st_obj->buffer, 0, size, data);
 }
 
 
@@ -185,6 +193,7 @@ st_bufferobj_map(GLcontext *ctx, GLenum target, GLenum access,
    struct pipe_context *pipe = st_context(ctx)->pipe;
    struct st_buffer_object *st_obj = st_buffer_object(obj);
    GLuint flags;
+   unsigned referenced;
 
    switch (access) {
    case GL_WRITE_ONLY:
@@ -200,6 +209,11 @@ st_bufferobj_map(GLcontext *ctx, GLenum target, GLenum access,
       break;      
    }
 
+   referenced = pipe->is_buffer_referenced(pipe, st_obj->buffer);
+   if (referenced && ((referenced & PIPE_REFERENCED_FOR_WRITE) ||
+		      (flags & PIPE_BUFFER_USAGE_CPU_WRITE)))
+      st_flush(st_context(ctx), PIPE_FLUSH_RENDER_CACHE, NULL);
+
    obj->Pointer = pipe_buffer_map(pipe->screen, st_obj->buffer, flags);
    if(obj->Pointer) {
       obj->Offset = 0;
diff --git a/src/mesa/state_tracker/st_cb_drawpixels.c b/src/mesa/state_tracker/st_cb_drawpixels.c
index 0a44305..c67b026 100644
--- a/src/mesa/state_tracker/st_cb_drawpixels.c
+++ b/src/mesa/state_tracker/st_cb_drawpixels.c
@@ -631,8 +631,6 @@ draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
    GLint skipPixels;
    ubyte *stmap;
 
-   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
-
    strb = st_renderbuffer(ctx->DrawBuffer->
                           Attachment[BUFFER_STENCIL].Renderbuffer);
 
@@ -640,6 +638,9 @@ draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
       y = ctx->DrawBuffer->Height - y - height;
    }
 
+   st_teximage_flush_before_map(ctx->st, strb->texture, 0, 0,
+				PIPE_TRANSFER_WRITE);
+
    pt = screen->get_tex_transfer(screen, strb->texture, 0, 0, 0,
                                  PIPE_TRANSFER_WRITE, x, y,
                                  width, height);
@@ -825,6 +826,9 @@ copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
                           GL_STENCIL_INDEX, GL_UNSIGNED_BYTE,
                           &ctx->DefaultPacking, buffer);
 
+   st_teximage_flush_before_map(ctx->st, rbDraw->texture, 0, 0,
+				PIPE_TRANSFER_WRITE);
+
    ptDraw = screen->get_tex_transfer(screen, rbDraw->texture, 0, 0, 0,
                                      PIPE_TRANSFER_WRITE, dstx, dsty,
                                      width, height);
diff --git a/src/mesa/state_tracker/st_cb_readpixels.c b/src/mesa/state_tracker/st_cb_readpixels.c
index 9ce5f3f..519ad66 100644
--- a/src/mesa/state_tracker/st_cb_readpixels.c
+++ b/src/mesa/state_tracker/st_cb_readpixels.c
@@ -42,13 +42,14 @@
 #include "pipe/p_defines.h"
 #include "pipe/p_inlines.h"
 #include "util/u_tile.h"
+
 #include "st_context.h"
 #include "st_cb_bitmap.h"
 #include "st_cb_readpixels.h"
 #include "st_cb_fbo.h"
 #include "st_format.h"
 #include "st_public.h"
-
+#include "st_texture.h"
 
 /**
  * Special case for reading stencil buffer.
@@ -73,6 +74,10 @@ st_read_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
    }
 
    /* Create a read transfer from the renderbuffer's texture */
+
+   st_teximage_flush_before_map(ctx->st, strb->texture, 0, 0,
+				PIPE_TRANSFER_READ);
+
    pt = screen->get_tex_transfer(screen, strb->texture,  0, 0, 0,
                                  PIPE_TRANSFER_READ, x, y, width, height);
 
@@ -240,6 +245,9 @@ st_fast_readpixels(GLcontext *ctx, struct st_renderbuffer *strb,
          y = strb->texture->height[0] - y - height;
       }
 
+      st_teximage_flush_before_map(ctx->st, strb->texture, 0, 0,
+				   PIPE_TRANSFER_READ);
+
       trans = screen->get_tex_transfer(screen, strb->texture, 0, 0, 0,
                                        PIPE_TRANSFER_READ, x, y, width, height);
       if (!trans) {
diff --git a/src/mesa/state_tracker/st_cb_texture.c b/src/mesa/state_tracker/st_cb_texture.c
index 1f14b37..727432d 100644
--- a/src/mesa/state_tracker/st_cb_texture.c
+++ b/src/mesa/state_tracker/st_cb_texture.c
@@ -700,6 +700,10 @@ st_get_tex_image(GLcontext * ctx, GLenum target, GLint level,
       /* Image is stored in hardware format in a buffer managed by the
        * kernel.  Need to explicitly map and unmap it.
        */
+
+      st_teximage_flush_before_map(ctx->st, stImage->pt, 0, level,
+				   PIPE_TRANSFER_READ);
+
       texImage->Data = st_texture_image_map(ctx->st, stImage, 0,
                                             PIPE_TRANSFER_READ, 0, 0,
                                             stImage->base.Width,
@@ -808,6 +812,8 @@ st_TexSubimage(GLcontext *ctx, GLint dims, GLenum target, GLint level,
     * from uploading the buffer under us.
     */
    if (stImage->pt) {
+      st_teximage_flush_before_map(ctx->st, stImage->pt, 0, level,
+				   PIPE_TRANSFER_WRITE);
       texImage->Data = st_texture_image_map(ctx->st, stImage, zoffset, 
                                             PIPE_TRANSFER_WRITE,
                                             xoffset, yoffset,
@@ -932,6 +938,9 @@ fallback_copy_texsubimage(GLcontext *ctx, GLenum target, GLint level,
       srcY = strb->Base.Height - srcY - height;
    }
 
+   st_teximage_flush_before_map(ctx->st, strb->texture, 0, 0,
+				PIPE_TRANSFER_READ);
+
    src_trans = screen->get_tex_transfer( screen,
                                          strb->texture,
                                          0, 0, 0,
@@ -939,6 +948,9 @@ fallback_copy_texsubimage(GLcontext *ctx, GLenum target, GLint level,
                                          srcX, srcY,
                                          width, height);
 
+   st_teximage_flush_before_map(ctx->st, stImage->pt, 0, 0,
+				PIPE_TRANSFER_WRITE);
+
    texDest = st_texture_image_map(ctx->st, stImage, 0, PIPE_TRANSFER_WRITE,
                                   destX, destY, width, height);
 
@@ -1318,6 +1330,11 @@ copy_image_data_to_texture(struct st_context *st,
 
       /* More straightforward upload.  
        */
+
+      st_teximage_flush_before_map(st, stObj->pt, stImage->face, dstLevel,
+				   PIPE_TRANSFER_WRITE);
+
+
       st_texture_image_data(st->pipe,
                             stObj->pt,
                             stImage->face,
diff --git a/src/mesa/state_tracker/st_gen_mipmap.c b/src/mesa/state_tracker/st_gen_mipmap.c
index 9cc2176..6e9aa52 100644
--- a/src/mesa/state_tracker/st_gen_mipmap.c
+++ b/src/mesa/state_tracker/st_gen_mipmap.c
@@ -123,10 +123,17 @@ fallback_generate_mipmap(GLcontext *ctx, GLenum target,
       const ubyte *srcData;
       ubyte *dstData;
 
+      st_teximage_flush_before_map(ctx->st, pt, face, srcLevel,
+				   PIPE_TRANSFER_READ);
+
       srcTrans = screen->get_tex_transfer(screen, pt, face, srcLevel, zslice,
                                           PIPE_TRANSFER_READ, 0, 0,
                                           pt->width[srcLevel],
                                           pt->height[srcLevel]);
+
+      st_teximage_flush_before_map(ctx->st, pt, face, dstLevel,
+				   PIPE_TRANSFER_WRITE);
+
       dstTrans = screen->get_tex_transfer(screen, pt, face, dstLevel, zslice,
                                           PIPE_TRANSFER_WRITE, 0, 0,
                                           pt->width[dstLevel],
diff --git a/src/mesa/state_tracker/st_texture.c b/src/mesa/state_tracker/st_texture.c
index 19eb7e2..fcbaeb6 100644
--- a/src/mesa/state_tracker/st_texture.c
+++ b/src/mesa/state_tracker/st_texture.c
@@ -188,8 +188,10 @@ st_texture_image_map(struct st_context *st, struct st_texture_image *stImage,
 		     GLuint zoffset, enum pipe_transfer_usage usage,
                      GLuint x, GLuint y, GLuint w, GLuint h)
 {
-   struct pipe_screen *screen = st->pipe->screen;
+   struct pipe_context *pipe = st->pipe;
+   struct pipe_screen *screen = pipe->screen;
    struct pipe_texture *pt = stImage->pt;
+
    DBG("%s \n", __FUNCTION__);
 
    stImage->transfer = screen->get_tex_transfer(screen, pt, stImage->face,
@@ -265,6 +267,7 @@ st_texture_image_data(struct pipe_context *pipe,
    struct pipe_transfer *dst_transfer;
 
    DBG("%s\n", __FUNCTION__);
+
    for (i = 0; i < depth; i++) {
       dst_transfer = screen->get_tex_transfer(screen, dst, face, level, i,
                                               PIPE_TRANSFER_WRITE, 0, 0,
@@ -481,3 +484,20 @@ st_release_teximage(struct st_framebuffer *stfb, uint surfIndex,
 
    return 1;
 }
+
+void
+st_teximage_flush_before_map(struct st_context *st,
+			     struct pipe_texture *pt,
+			     unsigned int face,
+			     unsigned int level,
+			     enum pipe_transfer_usage usage)
+{
+   struct pipe_context *pipe = st->pipe;
+   unsigned referenced =
+      pipe->is_texture_referenced(pipe, pt, face, level);
+
+   if (referenced && ((referenced & PIPE_REFERENCED_FOR_WRITE) ||
+		      usage == PIPE_TRANSFER_WRITE ||
+		      usage == PIPE_TRANSFER_READ_WRITE))
+      st_flush(st, PIPE_FLUSH_RENDER_CACHE, NULL);
+}
diff --git a/src/mesa/state_tracker/st_texture.h b/src/mesa/state_tracker/st_texture.h
index 60c0001..a392e3d 100644
--- a/src/mesa/state_tracker/st_texture.h
+++ b/src/mesa/state_tracker/st_texture.h
@@ -170,5 +170,10 @@ st_texture_image_copy(struct pipe_context *pipe,
                       struct pipe_texture *src,
                       GLuint face);
 
-
+extern void
+st_teximage_flush_before_map(struct st_context *st,
+			     struct pipe_texture *pt,
+			     unsigned int face,
+			     unsigned int level,
+			     enum pipe_transfer_usage usage);
 #endif




More information about the mesa-commit mailing list