svga: Performance fixes
[mesa.git] / src / gallium / drivers / svga / svga_state_constants.c
index 9d9f8934ec4a88c3d5b8eae3f24abd1903de042b..7e245baf22c4e01559eac84e897c049e6b4f2976 100644 (file)
@@ -219,6 +219,17 @@ svga_get_extra_vs_constants(const struct svga_context *svga, float *dest)
       count += 1;
    }
 
+   /* Bias to be added to VertexID */
+   if (variant->key.vs.need_vertex_id_bias) {
+      uint32_t *dest_u = (uint32_t *) dest;  // uint version of dest
+      dest_u[0] = svga->curr.vertex_id_bias;
+      dest_u[1] = 1;
+      dest_u[2] = 1;
+      dest_u[3] = 1;
+      dest+=4;
+      count++;
+   }
+
    /* SVGA_NEW_CLIP */
    count += svga_get_clip_plane_constants(svga, variant, &dest);
 
@@ -560,22 +571,170 @@ emit_consts_vgpu9(struct svga_context *svga, enum pipe_shader_type shader)
 }
 
 
-
+/**
+ * A helper function to emit a constant buffer binding at the
+ * specified slot for the specified shader type
+ */
 static enum pipe_error
-emit_constbuf_vgpu10(struct svga_context *svga, enum pipe_shader_type shader)
+emit_constbuf(struct svga_context *svga,
+              unsigned slot,
+              enum pipe_shader_type shader,
+              unsigned buffer_offset,
+              unsigned buffer_size,
+              const void *buffer,
+              unsigned extra_buffer_offset,
+              unsigned extra_buffer_size,
+              const void *extra_buffer)
 {
-   const struct pipe_constant_buffer *cbuf;
+   struct svga_buffer *sbuf = svga_buffer((struct pipe_resource *)buffer);
    struct pipe_resource *dst_buffer = NULL;
    enum pipe_error ret = PIPE_OK;
    struct pipe_transfer *src_transfer;
-   struct svga_winsys_surface *dst_handle;
+   struct svga_winsys_surface *dst_handle = NULL;
+   unsigned new_buf_size = 0;
+   unsigned alloc_buf_size;
+   unsigned offset = 0;;
+   void *src_map = NULL, *dst_map;
+
+   if ((sbuf && sbuf->swbuf) || extra_buffer) {
+
+      /* buffer here is a user-space buffer so mapping it is really cheap. */
+      if (buffer_size > 0) {
+         src_map = pipe_buffer_map_range(&svga->pipe,
+                                         (struct pipe_resource *)buffer,
+                                         buffer_offset, buffer_size,
+                                         PIPE_TRANSFER_READ, &src_transfer);
+         assert(src_map);
+         if (!src_map) {
+            return PIPE_ERROR_OUT_OF_MEMORY;
+         }
+      }
+
+      new_buf_size = MAX2(buffer_size, extra_buffer_offset) + extra_buffer_size;
+
+      /* According to the DX10 spec, the constant buffer size must be
+       * in multiples of 16.
+       */
+      new_buf_size = align(new_buf_size, 16);
+
+      /* Constant buffer size in the upload buffer must be in multiples of 256.
+       * In order to maximize the chance of merging the upload buffer chunks
+       * when svga_buffer_add_range() is called,
+       * the allocate buffer size needs to be in multiples of 256 as well.
+       * Otherwise, since there is gap between each dirty range of the upload buffer,
+       * each dirty range will end up in its own UPDATE_GB_IMAGE command.
+       */
+      alloc_buf_size = align(new_buf_size, CONST0_UPLOAD_ALIGNMENT);
+
+      u_upload_alloc(svga->const0_upload, 0, alloc_buf_size,
+                     CONST0_UPLOAD_ALIGNMENT, &offset,
+                     &dst_buffer, &dst_map);
+
+      if (!dst_map) {
+         if (src_map)
+            pipe_buffer_unmap(&svga->pipe, src_transfer);
+         return PIPE_ERROR_OUT_OF_MEMORY;
+      }
+
+      /* Initialize the allocated buffer slot to 0 to ensure the padding is
+       * filled with 0.
+       */
+      memset(dst_map, 0, alloc_buf_size);
+
+      if (src_map) {
+         memcpy(dst_map, src_map, buffer_size);
+         pipe_buffer_unmap(&svga->pipe, src_transfer);
+      }
+
+      if (extra_buffer_size) {
+         assert(extra_buffer_offset + extra_buffer_size <= new_buf_size);
+         memcpy((char *) dst_map + extra_buffer_offset, extra_buffer,
+                extra_buffer_size);
+      }
+
+      /* Get winsys handle for the constant buffer */
+      if (svga->state.hw_draw.const0_buffer == dst_buffer &&
+          svga->state.hw_draw.const0_handle) {
+         /* re-reference already mapped buffer */
+         dst_handle = svga->state.hw_draw.const0_handle;
+      }
+      else {
+         /* we must unmap the buffer before getting the winsys handle */
+         u_upload_unmap(svga->const0_upload);
+
+         dst_handle = svga_buffer_handle(svga, dst_buffer,
+                                         PIPE_BIND_CONSTANT_BUFFER);
+         if (!dst_handle) {
+            pipe_resource_reference(&dst_buffer, NULL);
+            return PIPE_ERROR_OUT_OF_MEMORY;
+         }
+      }
+   }
+   else if (sbuf) {
+      dst_handle = svga_buffer_handle(svga, &sbuf->b.b, PIPE_BIND_CONSTANT_BUFFER);
+      new_buf_size = align(buffer_size, 16);
+      offset = buffer_offset;
+   }
+
+   assert(new_buf_size % 16 == 0);
+
+   const struct svga_screen *screen = svga_screen(svga->pipe.screen);
+   const struct svga_winsys_screen *sws = screen->sws;
+
+   /* Issue the SetSingleConstantBuffer command */
+   if (!sws->have_constant_buffer_offset_cmd ||
+       svga->state.hw_draw.constbufoffsets[shader][slot].handle != dst_handle ||
+       svga->state.hw_draw.constbufoffsets[shader][slot].size != new_buf_size) {
+      ret = SVGA3D_vgpu10_SetSingleConstantBuffer(svga->swc,
+                                                  slot, /* index */
+                                                  svga_shader_type(shader),
+                                                  dst_handle,
+                                                  offset,
+                                                  new_buf_size);
+   }
+   else if (dst_handle){
+      unsigned command = SVGA_3D_CMD_DX_SET_VS_CONSTANT_BUFFER_OFFSET + shader;
+      ret = SVGA3D_vgpu10_SetConstantBufferOffset(svga->swc,
+                                                  command,
+                                                  slot, /* index */
+                                                  offset);
+   }
+
+   if (ret != PIPE_OK) {
+      pipe_resource_reference(&dst_buffer, NULL);
+      return ret;
+   }
+
+   /* save the upload buffer / handle for next time */
+   if (dst_buffer != buffer && dst_buffer) {
+      pipe_resource_reference(&svga->state.hw_draw.const0_buffer, dst_buffer);
+      svga->state.hw_draw.const0_handle = dst_handle;
+   }
+
+   /* Save this const buffer until it's replaced in the future.
+    * Otherwise, all references to the buffer will go away after the
+    * command buffer is submitted, it'll get recycled and we will have
+    * incorrect constant buffer bindings.
+    */
+   pipe_resource_reference(&svga->state.hw_draw.constbuf[shader][slot], dst_buffer);
+   svga->state.hw_draw.constbufoffsets[shader][slot].handle = dst_handle;
+   svga->state.hw_draw.constbufoffsets[shader][slot].size = new_buf_size;
+
+   pipe_resource_reference(&dst_buffer, NULL);
+
+   return PIPE_OK;
+}
+
+
+/* For constbuf 0 */
+static enum pipe_error
+emit_consts_vgpu10(struct svga_context *svga, enum pipe_shader_type shader)
+{
+   const struct pipe_constant_buffer *cbuf;
+   enum pipe_error ret = PIPE_OK;
    float extras[MAX_EXTRA_CONSTS][4];
    unsigned extra_count, extra_size, extra_offset;
-   unsigned new_buf_size;
-   void *src_map = NULL, *dst_map;
-   unsigned offset;
    const struct svga_shader_variant *variant;
-   unsigned alloc_buf_size;
 
    assert(shader == PIPE_SHADER_VERTEX ||
           shader == PIPE_SHADER_GEOMETRY ||
@@ -630,131 +789,30 @@ emit_constbuf_vgpu10(struct svga_context *svga, enum pipe_shader_type shader)
    if (cbuf->buffer_size + extra_size == 0)
       return PIPE_OK;  /* nothing to do */
 
-   /* Typically, the cbuf->buffer here is a user-space buffer so mapping
-    * it is really cheap.  If we ever get real HW buffers for constants
-    * we should void mapping and instead use a ResourceCopy command.
-    */
-   if (cbuf->buffer_size > 0) {
-      src_map = pipe_buffer_map_range(&svga->pipe, cbuf->buffer,
-                                      cbuf->buffer_offset, cbuf->buffer_size,
-                                      PIPE_TRANSFER_READ, &src_transfer);
-      assert(src_map);
-      if (!src_map) {
-         return PIPE_ERROR_OUT_OF_MEMORY;
-      }
-   }
-
-   /* The new/dest buffer's size must be large enough to hold the original,
-    * user-specified constants, plus the extra constants.
-    * The size of the original constant buffer _should_ agree with what the
-    * shader is expecting, but it might not (it's not enforced anywhere by
-    * gallium).
-    */
-   new_buf_size = MAX2(cbuf->buffer_size, extra_offset) + extra_size;
-
-   /* According to the DX10 spec, the constant buffer size must be
-    * in multiples of 16.
-    */
-   new_buf_size = align(new_buf_size, 16);
-
-   /* Constant buffer size in the upload buffer must be in multiples of 256.
-    * In order to maximize the chance of merging the upload buffer chunks
-    * when svga_buffer_add_range() is called,
-    * the allocate buffer size needs to be in multiples of 256 as well.
-    * Otherwise, since there is gap between each dirty range of the upload buffer,
-    * each dirty range will end up in its own UPDATE_GB_IMAGE command.
-    */
-   alloc_buf_size = align(new_buf_size, CONST0_UPLOAD_ALIGNMENT);
-
-   u_upload_alloc(svga->const0_upload, 0, alloc_buf_size,
-                  CONST0_UPLOAD_ALIGNMENT, &offset,
-                  &dst_buffer, &dst_map);
-   if (!dst_map) {
-      if (src_map)
-         pipe_buffer_unmap(&svga->pipe, src_transfer);
-      return PIPE_ERROR_OUT_OF_MEMORY;
-   }
-
-   if (src_map) {
-      memcpy(dst_map, src_map, cbuf->buffer_size);
-      pipe_buffer_unmap(&svga->pipe, src_transfer);
-   }
-
-   if (extra_size) {
-      assert(extra_offset + extra_size <= new_buf_size);
-      memcpy((char *) dst_map + extra_offset, extras, extra_size);
-   }
-
-   /* Get winsys handle for the constant buffer */
-   if (svga->state.hw_draw.const0_buffer == dst_buffer &&
-       svga->state.hw_draw.const0_handle) {
-      /* re-reference already mapped buffer */
-      dst_handle = svga->state.hw_draw.const0_handle;
-   }
-   else {
-      /* we must unmap the buffer before getting the winsys handle */
-      u_upload_unmap(svga->const0_upload);
-
-      dst_handle = svga_buffer_handle(svga, dst_buffer,
-                                      PIPE_BIND_CONSTANT_BUFFER);
-      if (!dst_handle) {
-         pipe_resource_reference(&dst_buffer, NULL);
-         return PIPE_ERROR_OUT_OF_MEMORY;
-      }
-
-      /* save the buffer / handle for next time */
-      pipe_resource_reference(&svga->state.hw_draw.const0_buffer, dst_buffer);
-      svga->state.hw_draw.const0_handle = dst_handle;
-   }
-
-   /* Issue the SetSingleConstantBuffer command */
-   assert(new_buf_size % 16 == 0);
-   ret = SVGA3D_vgpu10_SetSingleConstantBuffer(svga->swc,
-                                               0, /* index */
-                                               svga_shader_type(shader),
-                                               dst_handle,
-                                               offset,
-                                               new_buf_size);
-
-   if (ret != PIPE_OK) {
-      pipe_resource_reference(&dst_buffer, NULL);
+   ret = emit_constbuf(svga, 0, shader,
+                       cbuf->buffer_offset, cbuf->buffer_size, cbuf->buffer,
+                       extra_offset, extra_size, extras);
+   if (ret != PIPE_OK)
       return ret;
-   }
-
-   /* Save this const buffer until it's replaced in the future.
-    * Otherwise, all references to the buffer will go away after the
-    * command buffer is submitted, it'll get recycled and we will have
-    * incorrect constant buffer bindings.
-    */
-   pipe_resource_reference(&svga->state.hw_draw.constbuf[shader], dst_buffer);
 
-   svga->state.hw_draw.default_constbuf_size[shader] = new_buf_size;
+   svga->state.hw_draw.default_constbuf_size[shader] =
+      svga->state.hw_draw.constbufoffsets[shader][0].size;
 
-   pipe_resource_reference(&dst_buffer, NULL);
-
-   svga->hud.num_const_buf_updates++;
+   svga->hud.num_const_updates++;
 
    return ret;
 }
 
 
 static enum pipe_error
-emit_consts_vgpu10(struct svga_context *svga, enum pipe_shader_type shader)
+emit_constbuf_vgpu10(struct svga_context *svga, enum pipe_shader_type shader)
 {
-   enum pipe_error ret;
+   enum pipe_error ret = PIPE_OK;
    unsigned dirty_constbufs;
    unsigned enabled_constbufs;
 
-   /* Emit 0th constant buffer (with extra constants) */
-   ret = emit_constbuf_vgpu10(svga, shader);
-   if (ret != PIPE_OK) {
-      return ret;
-   }
-
    enabled_constbufs = svga->state.hw_draw.enabled_constbufs[shader] | 1u;
-
-   /* Emit other constant buffers (UBOs) */
-   dirty_constbufs = svga->state.dirty_constbufs[shader] & ~1u;
+   dirty_constbufs = (svga->state.dirty_constbufs[shader]|enabled_constbufs) & ~1u;
 
    while (dirty_constbufs) {
       unsigned index = u_bit_scan(&dirty_constbufs);
@@ -762,15 +820,11 @@ emit_consts_vgpu10(struct svga_context *svga, enum pipe_shader_type shader)
       unsigned size = svga->curr.constbufs[shader][index].buffer_size;
       struct svga_buffer *buffer =
          svga_buffer(svga->curr.constbufs[shader][index].buffer);
-      struct svga_winsys_surface *handle;
 
       if (buffer) {
-         handle = svga_buffer_handle(svga, &buffer->b.b,
-                                     PIPE_BIND_CONSTANT_BUFFER);
          enabled_constbufs |= 1 << index;
       }
       else {
-         handle = NULL;
          enabled_constbufs &= ~(1 << index);
          assert(offset == 0);
          assert(size == 0);
@@ -795,12 +849,9 @@ emit_consts_vgpu10(struct svga_context *svga, enum pipe_shader_type shader)
       }
 
       assert(size % 16 == 0);
-      ret = SVGA3D_vgpu10_SetSingleConstantBuffer(svga->swc,
-                                                  index,
-                                                  svga_shader_type(shader),
-                                                  handle,
-                                                  offset,
-                                                  size);
+
+      ret = emit_constbuf(svga, index, shader, offset, size, buffer,
+                          0, 0, NULL);
       if (ret != PIPE_OK)
          return ret;
 
@@ -824,7 +875,7 @@ emit_fs_consts(struct svga_context *svga, uint64_t dirty)
    if (!variant)
       return PIPE_OK;
 
-   /* SVGA_NEW_FS_CONST_BUFFER
+   /* SVGA_NEW_FS_CONSTS
     */
    if (svga_have_vgpu10(svga)) {
       ret = emit_consts_vgpu10(svga, PIPE_SHADER_FRAGMENT);
@@ -836,17 +887,42 @@ emit_fs_consts(struct svga_context *svga, uint64_t dirty)
    return ret;
 }
 
+static enum pipe_error
+emit_fs_constbuf(struct svga_context *svga, uint64_t dirty)
+{
+   const struct svga_shader_variant *variant = svga->state.hw_draw.fs;
+   enum pipe_error ret = PIPE_OK;
+
+   /* SVGA_NEW_FS_VARIANT
+    */
+   if (!variant)
+      return PIPE_OK;
+
+   /* SVGA_NEW_FS_CONSTBUF
+    */
+   assert(svga_have_vgpu10(svga));
+   ret = emit_constbuf_vgpu10(svga, PIPE_SHADER_FRAGMENT);
+
+   return ret;
+}
 
 struct svga_tracked_state svga_hw_fs_constants =
 {
    "hw fs params",
-   (SVGA_NEW_FS_CONST_BUFFER |
+   (SVGA_NEW_FS_CONSTS |
     SVGA_NEW_FS_VARIANT |
     SVGA_NEW_TEXTURE_CONSTS),
    emit_fs_consts
 };
 
 
+struct svga_tracked_state svga_hw_fs_constbufs =
+{
+   "hw fs params",
+   SVGA_NEW_FS_CONST_BUFFER,
+   emit_fs_constbuf
+};
+
 
 static enum pipe_error
 emit_vs_consts(struct svga_context *svga, uint64_t dirty)
@@ -872,17 +948,45 @@ emit_vs_consts(struct svga_context *svga, uint64_t dirty)
 }
 
 
+static enum pipe_error
+emit_vs_constbuf(struct svga_context *svga, uint64_t dirty)
+{
+   const struct svga_shader_variant *variant = svga->state.hw_draw.vs;
+   enum pipe_error ret = PIPE_OK;
+
+   /* SVGA_NEW_FS_VARIANT
+    */
+   if (!variant)
+      return PIPE_OK;
+
+   /* SVGA_NEW_FS_CONSTBUF
+    */
+   assert(svga_have_vgpu10(svga));
+   ret = emit_constbuf_vgpu10(svga, PIPE_SHADER_VERTEX);
+
+   return ret;
+}
+
+
 struct svga_tracked_state svga_hw_vs_constants =
 {
    "hw vs params",
    (SVGA_NEW_PRESCALE |
-    SVGA_NEW_VS_CONST_BUFFER |
+    SVGA_NEW_VS_CONSTS |
     SVGA_NEW_VS_VARIANT |
     SVGA_NEW_TEXTURE_CONSTS),
    emit_vs_consts
 };
 
 
+struct svga_tracked_state svga_hw_vs_constbufs =
+{
+   "hw vs params",
+   SVGA_NEW_VS_CONST_BUFFER,
+   emit_vs_constbuf
+};
+
+
 static enum pipe_error
 emit_gs_consts(struct svga_context *svga, uint64_t dirty)
 {
@@ -912,11 +1016,31 @@ emit_gs_consts(struct svga_context *svga, uint64_t dirty)
 }
 
 
+static enum pipe_error
+emit_gs_constbuf(struct svga_context *svga, uint64_t dirty)
+{
+   const struct svga_shader_variant *variant = svga->state.hw_draw.gs;
+   enum pipe_error ret = PIPE_OK;
+
+   /* SVGA_NEW_GS_VARIANT
+    */
+   if (!variant)
+      return PIPE_OK;
+
+   /* SVGA_NEW_GS_CONSTBUF
+    */
+   assert(svga_have_vgpu10(svga));
+   ret = emit_constbuf_vgpu10(svga, PIPE_SHADER_GEOMETRY);
+
+   return ret;
+}
+
+
 struct svga_tracked_state svga_hw_gs_constants =
 {
    "hw gs params",
    (SVGA_NEW_PRESCALE |
-    SVGA_NEW_GS_CONST_BUFFER |
+    SVGA_NEW_GS_CONSTS |
     SVGA_NEW_RAST |
     SVGA_NEW_GS_VARIANT |
     SVGA_NEW_TEXTURE_CONSTS),
@@ -924,6 +1048,14 @@ struct svga_tracked_state svga_hw_gs_constants =
 };
 
 
+struct svga_tracked_state svga_hw_gs_constbufs =
+{
+   "hw gs params",
+   SVGA_NEW_GS_CONST_BUFFER,
+   emit_gs_constbuf
+};
+
+
 /**
  * Emit constant buffer for tessellation control shader
  */
@@ -947,15 +1079,43 @@ emit_tcs_consts(struct svga_context *svga, uint64_t dirty)
 }
 
 
+static enum pipe_error
+emit_tcs_constbuf(struct svga_context *svga, uint64_t dirty)
+{
+   const struct svga_shader_variant *variant = svga->state.hw_draw.tcs;
+   enum pipe_error ret = PIPE_OK;
+
+   /* SVGA_NEW_TCS_VARIANT
+    */
+   if (!variant)
+      return PIPE_OK;
+
+   /* SVGA_NEW_TCS_CONSTBUF
+    */
+   assert(svga_have_vgpu10(svga));
+   ret = emit_constbuf_vgpu10(svga, PIPE_SHADER_TESS_CTRL);
+
+   return ret;
+}
+
+
 struct svga_tracked_state svga_hw_tcs_constants =
 {
    "hw tcs params",
-   (SVGA_NEW_TCS_CONST_BUFFER |
+   (SVGA_NEW_TCS_CONSTS |
     SVGA_NEW_TCS_VARIANT),
    emit_tcs_consts
 };
 
 
+struct svga_tracked_state svga_hw_tcs_constbufs =
+{
+   "hw tcs params",
+   SVGA_NEW_TCS_CONST_BUFFER,
+   emit_tcs_constbuf
+};
+
+
 /**
  * Emit constant buffer for tessellation evaluation shader
  */
@@ -977,11 +1137,39 @@ emit_tes_consts(struct svga_context *svga, uint64_t dirty)
 }
 
 
+static enum pipe_error
+emit_tes_constbuf(struct svga_context *svga, uint64_t dirty)
+{
+   const struct svga_shader_variant *variant = svga->state.hw_draw.tes;
+   enum pipe_error ret = PIPE_OK;
+
+   /* SVGA_NEW_TES_VARIANT
+    */
+   if (!variant)
+      return PIPE_OK;
+
+   /* SVGA_NEW_TES_CONSTBUF
+    */
+   assert(svga_have_vgpu10(svga));
+   ret = emit_constbuf_vgpu10(svga, PIPE_SHADER_TESS_EVAL);
+
+   return ret;
+}
+
+
 struct svga_tracked_state svga_hw_tes_constants =
 {
    "hw tes params",
    (SVGA_NEW_PRESCALE |
-    SVGA_NEW_TES_CONST_BUFFER |
+    SVGA_NEW_TES_CONSTS |
     SVGA_NEW_TES_VARIANT),
    emit_tes_consts
 };
+
+
+struct svga_tracked_state svga_hw_tes_constbufs =
+{
+   "hw gs params",
+   SVGA_NEW_TES_CONST_BUFFER,
+   emit_tes_constbuf
+};