svga: Ensure rendertargets and textures are always rebound at every command buffer...
authorJosé Fonseca <jfonseca@vmware.com>
Wed, 23 Feb 2011 13:32:37 +0000 (13:32 +0000)
committerJosé Fonseca <jfonseca@vmware.com>
Thu, 24 Feb 2011 14:00:13 +0000 (14:00 +0000)
The svga_update_state() mechanism is inadequate as it will always end up
flushing the primitives before processing the SVGA_NEW_COMMAND_BUFFER
dirty state flag.

src/gallium/drivers/svga/svga_context.c
src/gallium/drivers/svga/svga_state.h
src/gallium/drivers/svga/svga_state_framebuffer.c
src/gallium/drivers/svga/svga_state_tss.c

index 9b737a1..f0f875b 100644 (file)
@@ -204,6 +204,7 @@ void svga_context_flush( struct svga_context *svga,
 {
    struct svga_screen *svgascreen = svga_screen(svga->pipe.screen);
    struct pipe_fence_handle *fence = NULL;
+   enum pipe_error ret;
 
    svga->curr.nr_fbs = 0;
 
@@ -223,6 +224,21 @@ void svga_context_flush( struct svga_context *svga,
     */
    svga->dirty |= SVGA_NEW_COMMAND_BUFFER;
 
+   /*
+    * We must reemit the surface bindings here, because svga_update_state
+    * will always flush the primitives before processing the
+    * SVGA_NEW_COMMAND_BUFFER state change.
+    *
+    * TODO: Refactor this.
+    */
+   ret = svga_reemit_framebuffer_bindings(svga);
+   assert(ret == PIPE_OK);
+
+   ret = svga_reemit_tss_bindings(svga);
+   assert(ret == PIPE_OK);
+
+   svga->dirty &= ~SVGA_NEW_COMMAND_BUFFER;
+
    if (SVGA_DEBUG & DEBUG_SYNC) {
       if (fence)
          svga->pipe.screen->fence_finish( svga->pipe.screen, fence, 0);
index 22d5a6d..7f239e7 100644 (file)
@@ -92,4 +92,8 @@ void svga_update_state_retry( struct svga_context *svga,
 
 enum pipe_error svga_emit_initial_state( struct svga_context *svga );
 
+enum pipe_error svga_reemit_framebuffer_bindings( struct svga_context *svga );
+
+enum pipe_error svga_reemit_tss_bindings( struct svga_context *svga );
+
 #endif
index fcbb35e..cdadb20 100644 (file)
@@ -93,6 +93,55 @@ static int emit_framebuffer( struct svga_context *svga,
 }
 
 
+/*
+ * Rebind rendertargets.
+ *
+ * Similar to emit_framebuffer, but without any state checking/update.
+ *
+ * Called at the beginning of every new command buffer to ensure that
+ * non-dirty rendertargets are properly paged-in.
+ */
+enum pipe_error
+svga_reemit_framebuffer_bindings(struct svga_context *svga)
+{
+   struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer;
+   unsigned i;
+   enum pipe_error ret;
+
+   for (i = 0; i < MIN2(PIPE_MAX_COLOR_BUFS, 8); ++i) {
+      if (hw->cbufs[i]) {
+         ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_COLOR0 + i, hw->cbufs[i]);
+         if (ret != PIPE_OK) {
+            return ret;
+         }
+      }
+   }
+
+   if (hw->zsbuf) {
+      ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_DEPTH, hw->zsbuf);
+      if (ret != PIPE_OK) {
+         return ret;
+      }
+
+      if (hw->zsbuf &&
+          hw->zsbuf->format == PIPE_FORMAT_S8_USCALED_Z24_UNORM) {
+         ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, hw->zsbuf);
+         if (ret != PIPE_OK) {
+            return ret;
+         }
+      }
+      else {
+         ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, NULL);
+         if (ret != PIPE_OK) {
+            return ret;
+         }
+      }
+   }
+
+   return PIPE_OK;
+}
+
+
 struct svga_tracked_state svga_hw_framebuffer = 
 {
    "hw framebuffer state",
index f8b269a..c502506 100644 (file)
@@ -52,6 +52,16 @@ void svga_cleanup_tss_binding(struct svga_context *svga)
 }
 
 
+struct bind_queue {
+   struct {
+      unsigned unit;
+      struct svga_hw_view_state *view;
+   } bind[PIPE_MAX_SAMPLERS];
+
+   unsigned bind_count;
+};
+
+
 static int
 update_tss_binding(struct svga_context *svga, 
                    unsigned dirty )
@@ -63,15 +73,7 @@ update_tss_binding(struct svga_context *svga,
    unsigned min_lod;
    unsigned max_lod;
 
-
-   struct {
-      struct {
-         unsigned unit;
-         struct svga_hw_view_state *view;
-      } bind[PIPE_MAX_SAMPLERS];
-
-      unsigned bind_count;
-   } queue;
+   struct bind_queue queue;
 
    queue.bind_count = 0;
    
@@ -164,6 +166,64 @@ fail:
 }
 
 
+/*
+ * Rebind textures.
+ *
+ * Similar to update_tss_binding, but without any state checking/update.
+ *
+ * Called at the beginning of every new command buffer to ensure that
+ * non-dirty textures are properly paged-in.
+ */
+enum pipe_error
+svga_reemit_tss_bindings(struct svga_context *svga)
+{
+   unsigned i;
+   enum pipe_error ret;
+   struct bind_queue queue;
+
+   queue.bind_count = 0;
+
+   for (i = 0; i < svga->state.hw_draw.num_views; i++) {
+      struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];
+
+      if (view->v) {
+         queue.bind[queue.bind_count].unit = i;
+         queue.bind[queue.bind_count].view = view;
+         queue.bind_count++;
+      }
+   }
+
+   if (queue.bind_count) {
+      SVGA3dTextureState *ts;
+
+      ret = SVGA3D_BeginSetTextureState(svga->swc,
+                                        &ts,
+                                        queue.bind_count);
+      if (ret != PIPE_OK) {
+         return ret;
+      }
+
+      for (i = 0; i < queue.bind_count; i++) {
+         struct svga_winsys_surface *handle;
+
+         ts[i].stage = queue.bind[i].unit;
+         ts[i].name = SVGA3D_TS_BIND_TEXTURE;
+
+         assert(queue.bind[i].view->v);
+         handle = queue.bind[i].view->v->handle;
+         svga->swc->surface_relocation(svga->swc,
+                                       &ts[i].value,
+                                       handle,
+                                       SVGA_RELOC_READ);
+      }
+
+      SVGA_FIFOCommitAll(svga->swc);
+   }
+
+   return PIPE_OK;
+}
+
+
 struct svga_tracked_state svga_hw_tss_binding = {
    "texture binding emit",
    SVGA_NEW_TEXTURE_BINDING |