svga: add, use SVGA3D_SURFACE_HINT_VOLUME flag
[mesa.git] / src / gallium / drivers / svga / svga_pipe_draw.c
index 8e1c764ef5f60f5024d8beafd6bd7ec081453bb3..e72032e685d6c7ac34b2f7ffa5c989f207018799 100644 (file)
  *
  **********************************************************/
 
-#include "svga_cmd.h"
 
+#include "util/u_format.h"
 #include "util/u_inlines.h"
 #include "util/u_prim.h"
 #include "util/u_time.h"
+#include "util/u_upload_mgr.h"
 #include "indices/u_indices.h"
 
 #include "svga_hw_reg.h"
+#include "svga_cmd.h"
 #include "svga_context.h"
 #include "svga_screen.h"
 #include "svga_draw.h"
 #include "svga_swtnl.h"
 #include "svga_debug.h"
 #include "svga_resource_buffer.h"
-#include "util/u_upload_mgr.h"
+
 
 /**
- * svga_upload_user_buffers - upload parts of user buffers
+ * Determine the ranges to upload for the user-buffers referenced
+ * by the next draw command.
  *
- * This function streams a part of a user buffer to hw and sets
- * svga_buffer::source_offset to the first byte uploaded. After upload
- * also svga_buffer::uploaded::buffer is set to !NULL
+ * TODO: It might be beneficial to support multiple ranges. In that case,
+ * the struct svga_buffer::uploaded member should be made an array or a
+ * list, since we need to account for the possibility that different ranges
+ * may be uploaded to different hardware buffers chosen by the utility
+ * upload manager.
  */
+static void
+svga_user_buffer_range(struct svga_context *svga,
+                       unsigned start,
+                       unsigned count,
+                       unsigned instance_count)
+{
+   const struct pipe_vertex_element *ve = svga->curr.velems->velem;
+   unsigned i;
 
+   /*
+    * Release old uploaded range (if not done already) and
+    * initialize new ranges.
+    */
+
+   for (i=0; i < svga->curr.velems->count; i++) {
+      struct pipe_vertex_buffer *vb =
+         &svga->curr.vb[ve[i].vertex_buffer_index];
+
+      if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
+         struct svga_buffer *buffer = svga_buffer(vb->buffer);
+
+         pipe_resource_reference(&buffer->uploaded.buffer, NULL);
+         buffer->uploaded.start = ~0;
+         buffer->uploaded.end = 0;
+      }
+   }
+
+   for (i=0; i < svga->curr.velems->count; i++) {
+      struct pipe_vertex_buffer *vb =
+         &svga->curr.vb[ve[i].vertex_buffer_index];
+
+      if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
+         struct svga_buffer *buffer = svga_buffer(vb->buffer);
+         unsigned first, size;
+         unsigned instance_div = ve[i].instance_divisor;
+         unsigned elemSize = util_format_get_blocksize(ve[i].src_format);
+
+         svga->dirty |= SVGA_NEW_VBUFFER;
+
+         if (instance_div) {
+            first = ve[i].src_offset;
+            count = (instance_count + instance_div - 1) / instance_div;
+            size = vb->stride * (count - 1) + elemSize;
+         } else {
+            first = vb->stride * start + ve[i].src_offset;
+            size = vb->stride * (count - 1) + elemSize;
+         }
+
+         buffer->uploaded.start = MIN2(buffer->uploaded.start, first);
+         buffer->uploaded.end = MAX2(buffer->uploaded.end, first + size);
+      }
+   }
+}
+
+
+/**
+ * svga_upload_user_buffers - upload parts of user buffers
+ *
+ * This function streams a part of a user buffer to hw and fills
+ * svga_buffer::uploaded with information on the upload.
+ */
 static int
 svga_upload_user_buffers(struct svga_context *svga,
                          unsigned start,
@@ -58,40 +123,29 @@ svga_upload_user_buffers(struct svga_context *svga,
    unsigned i;
    int ret;
 
+   svga_user_buffer_range(svga, start, count, instance_count);
+
    for (i=0; i < svga->curr.velems->count; i++) {
       struct pipe_vertex_buffer *vb =
          &svga->curr.vb[ve[i].vertex_buffer_index];
 
       if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
          struct svga_buffer *buffer = svga_buffer(vb->buffer);
-         unsigned first, size;
-         boolean flushed;
-         unsigned instance_div = ve[i].instance_divisor;
 
-         svga->dirty |= SVGA_NEW_VBUFFER;
+         /*
+          * Check if already uploaded. Otherwise go ahead and upload.
+          */
 
-         if (instance_div) {
-            first = 0;
-            size = vb->stride *
-               (instance_count + instance_div - 1) / instance_div;
-         } else if (vb->stride) {
-            first = vb->stride * start;
-            size = vb->stride * count;
-         } else {
-            /* Only a single vertex!
-             * Upload with the largest vertex size the hw supports,
-             * if possible.
-             */
-            first = 0;
-            size = MIN2(16, vb->buffer->width0);
-         }
+         if (buffer->uploaded.buffer)
+            continue;
 
          ret = u_upload_buffer( svga->upload_vb,
-                                0, first, size,
+                                0,
+                                buffer->uploaded.start,
+                                buffer->uploaded.end - buffer->uploaded.start,
                                 &buffer->b.b,
                                 &buffer->uploaded.offset,
-                                &buffer->uploaded.buffer,
-                                &flushed);
+                                &buffer->uploaded.buffer);
 
          if (ret)
             return ret;
@@ -104,17 +158,17 @@ svga_upload_user_buffers(struct svga_context *svga,
                          buffer,
                          buffer->uploaded.buffer,
                          buffer->uploaded.offset,
-                         first,
-                         size);
+                         buffer->uploaded.start,
+                         buffer->uploaded.end - buffer->uploaded.start);
 
          vb->buffer_offset = buffer->uploaded.offset;
-         buffer->source_offset = first;
       }
    }
 
    return PIPE_OK;
 }
 
+
 /**
  * svga_release_user_upl_buffers - release uploaded parts of user buffers
  *
@@ -126,7 +180,6 @@ svga_upload_user_buffers(struct svga_context *svga,
  * svga_buffer::source_offset is set to 0, and svga_buffer::uploaded::buffer
  * is set to 0.
  */
-
 static void
 svga_release_user_upl_buffers(struct svga_context *svga)
 {
@@ -141,7 +194,19 @@ svga_release_user_upl_buffers(struct svga_context *svga)
       if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
          struct svga_buffer *buffer = svga_buffer(vb->buffer);
 
-         buffer->source_offset = 0;
+         /* The buffer_offset is relative to the uploaded buffer.
+          * Since we're discarding that buffer we need to reset this offset
+          * so it's not inadvertantly applied to a subsequent draw.
+          *
+          * XXX a root problem here is that the svga->curr.vb[] information
+          * is getting set both by gallium API calls and by code in
+          * svga_upload_user_buffers().  We should instead have two copies
+          * of the vertex buffer information and choose between as needed.
+          */
+         vb->buffer_offset = 0;
+
+         buffer->uploaded.start = ~0;
+         buffer->uploaded.end = 0;
          if (buffer->uploaded.buffer)
             pipe_resource_reference(&buffer->uploaded.buffer, NULL);
       }
@@ -157,13 +222,13 @@ retry_draw_range_elements( struct svga_context *svga,
                            int index_bias,
                            unsigned min_index,
                            unsigned max_index,
-                           unsigned prim, 
-                           unsigned start, 
+                           unsigned prim,
+                           unsigned start,
                            unsigned count,
                            unsigned instance_count,
                            boolean do_retry )
 {
-   enum pipe_error ret = 0;
+   enum pipe_error ret = PIPE_OK;
 
    svga_hwtnl_set_unfilled( svga->hwtnl,
                             svga->curr.rast->hw_unfilled );
@@ -178,14 +243,14 @@ retry_draw_range_elements( struct svga_context *svga,
       goto retry;
 
    ret = svga_update_state( svga, SVGA_STATE_HW_DRAW );
-   if (ret)
+   if (ret != PIPE_OK)
       goto retry;
 
    ret = svga_hwtnl_draw_range_elements( svga->hwtnl,
                                          index_buffer, index_size, index_bias,
                                          min_index, max_index,
                                          prim, start, count );
-   if (ret)
+   if (ret != PIPE_OK)
       goto retry;
 
    return PIPE_OK;
@@ -208,8 +273,8 @@ retry:
 
 static enum pipe_error
 retry_draw_arrays( struct svga_context *svga,
-                   unsigned prim, 
-                   unsigned start, 
+                   unsigned prim,
+                   unsigned start,
                    unsigned count,
                    unsigned instance_count,
                    boolean do_retry )
@@ -229,18 +294,18 @@ retry_draw_arrays( struct svga_context *svga,
       goto retry;
 
    ret = svga_update_state( svga, SVGA_STATE_HW_DRAW );
-   if (ret)
+   if (ret != PIPE_OK)
       goto retry;
 
    ret = svga_hwtnl_draw_arrays( svga->hwtnl, prim,
                                  start, count );
-   if (ret)
+   if (ret != PIPE_OK)
       goto retry;
 
-   return 0;
+   return PIPE_OK;
 
 retry:
-   if (ret == PIPE_ERROR_OUT_OF_MEMORY && do_retry) 
+   if (ret == PIPE_ERROR_OUT_OF_MEMORY && do_retry)
    {
       svga_context_flush( svga, NULL );
 
@@ -281,7 +346,7 @@ svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
       svga->curr.reduced_prim = reduced_prim;
       svga->dirty |= SVGA_NEW_REDUCED_PRIMITIVE;
    }
-   
+
    needed_swtnl = svga->state.sw.need_swtnl;
 
    svga_update_state_retry( svga, SVGA_STATE_NEED_SWTNL );
@@ -338,6 +403,9 @@ svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
       }
    }
 
+   /* XXX: Silence warnings, do something sensible here? */
+   (void)ret;
+
    svga_release_user_upl_buffers( svga );
 
    if (SVGA_DEBUG & DEBUG_FLUSH) {