svga: Coalesce multiple shader constants in a single command.
authorJosé Fonseca <jfonseca@vmware.com>
Wed, 23 Feb 2011 18:45:04 +0000 (18:45 +0000)
committerBrian Paul <brianp@vmware.com>
Fri, 23 Sep 2011 13:58:44 +0000 (07:58 -0600)
HWv8 feature.

Tested with GoogleEarth, Mesa demos.

src/gallium/drivers/svga/svga_cmd.c
src/gallium/drivers/svga/svga_cmd.h
src/gallium/drivers/svga/svga_state_constants.c

index ebcd4bcaf10865379f150ff6111a5466ff2609d7..d7611d4d0426d3dc2cc652356991460894b49596 100644 (file)
@@ -758,6 +758,59 @@ SVGA3D_SetShaderConst(struct svga_winsys_context *swc,
 }
 
 
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_SetShaderConsts --
+ *
+ *      Set the value of successive shader constants.
+ *
+ *      Shader constants are analogous to uniform variables in GLSL,
+ *      except that they belong to the render context rather than to
+ *      an individual shader.
+ *
+ *      Constants may have one of three types: A 4-vector of floats,
+ *      a 4-vector of integers, or a single boolean flag.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_SetShaderConsts(struct svga_winsys_context *swc,
+                        uint32 reg,                   // IN
+                        uint32 numRegs,               // IN
+                        SVGA3dShaderType type,        // IN
+                        SVGA3dShaderConstType ctype,  // IN
+                        const void *values)           // IN
+{
+   SVGA3dCmdSetShaderConst *cmd;
+
+   cmd = SVGA3D_FIFOReserve(swc,
+                            SVGA_3D_CMD_SET_SHADER_CONST,
+                            sizeof *cmd + (numRegs - 1) * sizeof cmd->values,
+                            0);
+   if(!cmd)
+      return PIPE_ERROR_OUT_OF_MEMORY;
+
+   cmd->cid = swc->cid;
+   cmd->reg = reg;
+   cmd->type = type;
+   cmd->ctype = ctype;
+
+   memcpy(&cmd->values, values, numRegs * sizeof cmd->values);
+
+   swc->commit(swc);
+
+   return PIPE_OK;
+}
+
+
 
 
 
index 223ab17df81763e4bf1464a1b53a339e0f618447..9bbe95f18b875b14049f04c289626147e57ef090 100644 (file)
@@ -210,6 +210,14 @@ SVGA3D_SetShaderConst(struct svga_winsys_context *swc,
                       uint32 reg, SVGA3dShaderType type,
                       SVGA3dShaderConstType ctype, const void *value);
 
+enum pipe_error
+SVGA3D_SetShaderConsts(struct svga_winsys_context *swc,
+                       uint32 reg,
+                       uint32 numRegs,
+                       SVGA3dShaderType type,
+                       SVGA3dShaderConstType ctype,
+                       const void *values);
+
 enum pipe_error
 SVGA3D_SetShader(struct svga_winsys_context *swc,
                  SVGA3dShaderType type, uint32 shid);
index 6c3275e74c05d0559f6a01a1a09848e97229bd1e..a28fcf9122587349ed1beae05a8fdc8630c39733 100644 (file)
@@ -26,6 +26,7 @@
 #include "util/u_inlines.h"
 #include "pipe/p_defines.h"
 
+#include "svga_screen.h"
 #include "svga_context.h"
 #include "svga_state.h"
 #include "svga_cmd.h"
 
 #include "svga_hw_reg.h"
 
+
+/*
+ * Don't try to send more than 4k of successive constants.
+ */
+#define MAX_CONST_REG_COUNT 256 /* 4k */
+
+
 /***********************************************************************
  * Hardware update 
  */
@@ -48,7 +56,9 @@ static int svga_shader_type( int shader )
    return shader + 1;
 }
 
-
+/*
+ * Check and emit one shader constant register.
+ */
 static int emit_const( struct svga_context *svga,
                        int unit,
                        int i,
@@ -56,6 +66,8 @@ static int emit_const( struct svga_context *svga,
 {
    int ret = PIPE_OK;
 
+   assert(i < CB_MAX);
+
    if (memcmp(svga->state.hw_draw.cb[unit][i], value, 4 * sizeof(float)) != 0) {
       if (SVGA_DEBUG & DEBUG_CONSTS)
          debug_printf("%s %s %d: %f %f %f %f\n",
@@ -81,10 +93,103 @@ static int emit_const( struct svga_context *svga,
    return ret;
 }
 
+/*
+ * Check and emit a range of shader constant registers, trying to coalesce
+ * successive shader constant updates in a single command in order to save
+ * space on the command buffer.  This is a HWv8 feature.
+ */
+static enum pipe_error emit_const_range( struct svga_context *svga,
+                                         unsigned unit,
+                                         unsigned offset,
+                                         unsigned count,
+                                         const float (*values)[4] )
+{
+   unsigned i, j;
+   enum pipe_error ret;
+
+   assert(offset + count < CB_MAX);
+
+   i = 0;
+   while (i < count) {
+      if (memcmp(svga->state.hw_draw.cb[unit][offset + i],
+                 values[i],
+                 4 * sizeof(float)) != 0) {
+
+         /*
+          * Found one dirty constant
+          */
+
+         if (SVGA_DEBUG & DEBUG_CONSTS)
+            debug_printf("%s %s %d: %f %f %f %f\n",
+                         __FUNCTION__,
+                         unit == PIPE_SHADER_VERTEX ? "VERT" : "FRAG",
+                         offset + i,
+                         values[i][0],
+                         values[i][1],
+                         values[i][2],
+                         values[i][3]);
+
+         /*
+          * Look for more consecutive dirty constants.
+          */
+
+         j = i + 1;
+         while (j < count &&
+                j < i + MAX_CONST_REG_COUNT &&
+                memcmp(svga->state.hw_draw.cb[unit][offset + j],
+                       values[j],
+                       4 * sizeof(float)) != 0) {
+
+            if (SVGA_DEBUG & DEBUG_CONSTS)
+               debug_printf("%s %s %d: %f %f %f %f\n",
+                            __FUNCTION__,
+                            unit == PIPE_SHADER_VERTEX ? "VERT" : "FRAG",
+                            offset + j,
+                            values[j][0],
+                            values[j][1],
+                            values[j][2],
+                            values[j][3]);
+
+            ++j;
+         }
+
+         assert(j >= i + 1);
+
+         /*
+          * Send them all together.
+          */
+
+         ret = SVGA3D_SetShaderConsts(svga->swc,
+                                      offset + i, j - i,
+                                      svga_shader_type(unit),
+                                      SVGA3D_CONST_TYPE_FLOAT,
+                                      values + i);
+         if (ret != PIPE_OK) {
+            return ret;
+         }
+
+         /*
+          * Local copy of the hardware state.
+          */
+
+         memcpy(svga->state.hw_draw.cb[unit][offset + i],
+                values[i],
+                (j - i) * 4 * sizeof(float));
+
+         i = j + 1;
+      } else {
+         ++i;
+      }
+   }
+
+   return PIPE_OK;
+}
+
 static int emit_consts( struct svga_context *svga,
                         int offset,
                         int unit )
 {
+   struct svga_screen *ss = svga_screen(svga->pipe.screen);
    struct pipe_transfer *transfer = NULL;
    unsigned count;
    const float (*data)[4] = NULL;
@@ -105,10 +210,18 @@ static int emit_consts( struct svga_context *svga,
       goto done;
    }
 
-   for (i = 0; i < count; i++) {
-      ret = emit_const( svga, unit, offset + i, data[i] );
-      if (ret)
+   if (ss->hw_version >= SVGA3D_HWVERSION_WS8_B1) {
+      ret = emit_const_range( svga, unit, offset, count, data );
+      if (ret != PIPE_OK) {
          goto done;
+      }
+   } else {
+      for (i = 0; i < count; i++) {
+         ret = emit_const( svga, unit, offset + i, data[i] );
+         if (ret != PIPE_OK) {
+            goto done;
+         }
+      }
    }
 
 done: