r600g: Use the actual Evergreen functions to query format support on Evergreen.
[mesa.git] / src / gallium / auxiliary / util / u_vbuf_mgr.c
index 521ac07747cee92d07e6512aa2d0f56d4d3a25d6..374fc336b83a88f43667d3991299eedc393d0010 100644 (file)
@@ -53,9 +53,11 @@ struct u_vbuf_mgr_elements {
    unsigned count;
    struct pipe_vertex_element ve[PIPE_MAX_ATTRIBS];
 
-   /* If (velem[i].src_format != real_format[i]), the vertex buffer
+   unsigned src_format_size[PIPE_MAX_ATTRIBS];
+
+   /* If (velem[i].src_format != native_format[i]), the vertex buffer
     * referenced by the vertex element cannot be used for rendering and
-    * its vertex data must be translated to real_format[i]. */
+    * its vertex data must be translated to native_format[i]. */
    enum pipe_format native_format[PIPE_MAX_ATTRIBS];
    unsigned native_format_size[PIPE_MAX_ATTRIBS];
 
@@ -150,9 +152,9 @@ void u_vbuf_mgr_destroy(struct u_vbuf_mgr *mgrb)
 }
 
 
-static void u_vbuf_translate_begin(struct u_vbuf_mgr_priv *mgr,
-                                   int min_index, int max_index,
-                                   boolean *upload_flushed)
+static enum u_vbuf_return_flags
+u_vbuf_translate_begin(struct u_vbuf_mgr_priv *mgr,
+                       int min_index, int max_index)
 {
    struct translate_key key;
    struct translate_element *te;
@@ -164,6 +166,7 @@ static void u_vbuf_translate_begin(struct u_vbuf_mgr_priv *mgr,
    struct pipe_resource *out_buffer = NULL;
    unsigned i, num_verts, out_offset;
    struct pipe_vertex_element new_velems[PIPE_MAX_ATTRIBS];
+   boolean upload_flushed = FALSE;
 
    memset(&key, 0, sizeof(key));
    memset(tr_elem_index, 0xff, sizeof(tr_elem_index));
@@ -246,7 +249,7 @@ static void u_vbuf_translate_begin(struct u_vbuf_mgr_priv *mgr,
    u_upload_alloc(mgr->b.uploader,
                   key.output_stride * min_index,
                   key.output_stride * num_verts,
-                  &out_offset, &out_buffer, upload_flushed,
+                  &out_offset, &out_buffer, &upload_flushed,
                   (void**)&out_map);
 
    out_offset -= key.output_stride * min_index;
@@ -306,6 +309,8 @@ static void u_vbuf_translate_begin(struct u_vbuf_mgr_priv *mgr,
    }
 
    pipe_resource_reference(&out_buffer, NULL);
+
+   return upload_flushed ? U_VBUF_UPLOAD_FLUSHED : 0;
 }
 
 static void u_vbuf_translate_end(struct u_vbuf_mgr_priv *mgr)
@@ -353,6 +358,8 @@ u_vbuf_mgr_create_vertex_elements(struct u_vbuf_mgr *mgrb,
    for (i = 0; i < count; i++) {
       enum pipe_format format = ve->ve[i].src_format;
 
+      ve->src_format_size[i] = util_format_get_blocksize(format);
+
       /* Choose a native format.
        * For now we don't care about the alignment, that's going to
        * be sorted out later. */
@@ -460,7 +467,6 @@ void u_vbuf_mgr_set_vertex_buffers(struct u_vbuf_mgr *mgrb,
    struct u_vbuf_mgr_priv *mgr = (struct u_vbuf_mgr_priv*)mgrb;
    unsigned i;
 
-   mgr->b.max_index = ~0;
    mgr->any_user_vbs = FALSE;
    mgr->incompatible_vb_layout = FALSE;
 
@@ -483,23 +489,16 @@ void u_vbuf_mgr_set_vertex_buffers(struct u_vbuf_mgr *mgrb,
       pipe_resource_reference(&mgr->b.vertex_buffer[i].buffer, vb->buffer);
       pipe_resource_reference(&mgr->b.real_vertex_buffer[i], NULL);
 
-      if (u_vbuf_resource(vb->buffer)->user_ptr) {
-         mgr->any_user_vbs = TRUE;
+      if (!vb->buffer) {
          continue;
       }
 
-      pipe_resource_reference(&mgr->b.real_vertex_buffer[i], vb->buffer);
-
-      /* The stride of zero means we will be fetching only the first
-       * vertex, so don't care about max_index. */
-      if (!vb->stride) {
+      if (u_vbuf_resource(vb->buffer)->user_ptr) {
+         mgr->any_user_vbs = TRUE;
          continue;
       }
 
-      /* Update the maximum index. */
-      mgr->b.max_index =
-            MIN2(mgr->b.max_index,
-                 (vb->buffer->width0 - vb->buffer_offset) / vb->stride);
+      pipe_resource_reference(&mgr->b.real_vertex_buffer[i], vb->buffer);
    }
 
    for (; i < mgr->b.nr_real_vertex_buffers; i++) {
@@ -514,14 +513,15 @@ void u_vbuf_mgr_set_vertex_buffers(struct u_vbuf_mgr *mgrb,
    mgr->b.nr_real_vertex_buffers = count;
 }
 
-static void u_vbuf_upload_buffers(struct u_vbuf_mgr_priv *mgr,
-                                  int min_index, int max_index,
-                                  unsigned instance_count,
-                                  boolean *upload_flushed)
+static enum u_vbuf_return_flags
+u_vbuf_upload_buffers(struct u_vbuf_mgr_priv *mgr,
+                      int min_index, int max_index,
+                      unsigned instance_count)
 {
-   int i, nr = mgr->ve->count;
+   unsigned i, nr = mgr->ve->count;
    unsigned count = max_index + 1 - min_index;
    boolean uploaded[PIPE_MAX_ATTRIBS] = {0};
+   enum u_vbuf_return_flags retval = 0;
 
    for (i = 0; i < nr; i++) {
       unsigned index = mgr->ve->ve[i].vertex_buffer_index;
@@ -541,6 +541,11 @@ static void u_vbuf_upload_buffers(struct u_vbuf_mgr_priv *mgr,
          } else if (vb->stride) {
             first = vb->stride * min_index;
             size = vb->stride * count;
+
+            /* Unusual case when stride is smaller than the format size.
+             * XXX This won't work with interleaved arrays. */
+            if (mgr->ve->native_format_size[i] > vb->stride)
+               size += mgr->ve->native_format_size[i] - vb->stride;
          } else {
             first = 0;
             size = mgr->ve->native_format_size[i];
@@ -555,48 +560,88 @@ static void u_vbuf_upload_buffers(struct u_vbuf_mgr_priv *mgr,
          vb->buffer_offset -= first;
 
          uploaded[index] = TRUE;
-         *upload_flushed = *upload_flushed || flushed;
+         if (flushed)
+            retval |= U_VBUF_UPLOAD_FLUSHED;
       } else {
          assert(mgr->b.real_vertex_buffer[index]);
       }
    }
+
+   return retval;
+}
+
+static void u_vbuf_mgr_compute_max_index(struct u_vbuf_mgr_priv *mgr)
+{
+   unsigned i, nr = mgr->ve->count;
+
+   mgr->b.max_index = ~0;
+
+   for (i = 0; i < nr; i++) {
+      struct pipe_vertex_buffer *vb =
+            &mgr->b.vertex_buffer[mgr->ve->ve[i].vertex_buffer_index];
+      int unused;
+      unsigned max_index;
+
+      if (!vb->buffer ||
+          !vb->stride ||
+          u_vbuf_resource(vb->buffer)->user_ptr) {
+         continue;
+      }
+
+      /* How many bytes is unused after the last vertex.
+       * width0 may be "count*stride - unused" and we have to compensate
+       * for that when dividing by stride. */
+      unused = vb->stride -
+               (mgr->ve->ve[i].src_offset + mgr->ve->src_format_size[i]);
+
+      /* If src_offset is greater than stride (which means it's a buffer
+       * offset rather than a vertex offset)... */
+      if (unused < 0) {
+         unused = 0;
+      }
+
+      /* Compute the maximum index for this vertex element. */
+      max_index =
+         (vb->buffer->width0 - vb->buffer_offset + (unsigned)unused) /
+         vb->stride - 1;
+
+      mgr->b.max_index = MIN2(mgr->b.max_index, max_index);
+   }
 }
 
-void u_vbuf_mgr_draw_begin(struct u_vbuf_mgr *mgrb,
-                           const struct pipe_draw_info *info,
-                           boolean *buffers_updated,
-                           boolean *uploader_flushed)
+enum u_vbuf_return_flags
+u_vbuf_mgr_draw_begin(struct u_vbuf_mgr *mgrb,
+                      const struct pipe_draw_info *info)
 {
    struct u_vbuf_mgr_priv *mgr = (struct u_vbuf_mgr_priv*)mgrb;
-   boolean bufs_updated = FALSE, upload_flushed = FALSE;
    int min_index, max_index;
+   enum u_vbuf_return_flags retval = 0;
+
+   u_vbuf_mgr_compute_max_index(mgr);
 
    min_index = info->min_index - info->index_bias;
-   max_index = info->max_index - info->index_bias;
+   if (info->max_index == ~0) {
+      max_index = mgr->b.max_index;
+   } else {
+      max_index = MIN2(info->max_index - info->index_bias, mgr->b.max_index);
+   }
 
    /* Translate vertices with non-native layouts or formats. */
    if (mgr->incompatible_vb_layout || mgr->ve->incompatible_layout) {
-      u_vbuf_translate_begin(mgr, min_index, max_index, &upload_flushed);
+      retval |= u_vbuf_translate_begin(mgr, min_index, max_index);
 
       if (mgr->fallback_ve) {
-         bufs_updated = TRUE;
+         retval |= U_VBUF_BUFFERS_UPDATED;
       }
    }
 
    /* Upload user buffers. */
    if (mgr->any_user_vbs) {
-      u_vbuf_upload_buffers(mgr, min_index, max_index, info->instance_count,
-                            &upload_flushed);
-      bufs_updated = TRUE;
-   }
-
-   /* Set the return values. */
-   if (buffers_updated) {
-      *buffers_updated = bufs_updated;
-   }
-   if (uploader_flushed) {
-      *uploader_flushed = upload_flushed;
+      retval |= u_vbuf_upload_buffers(mgr, min_index, max_index,
+                                      info->instance_count);
+      retval |= U_VBUF_BUFFERS_UPDATED;
    }
+   return retval;
 }
 
 void u_vbuf_mgr_draw_end(struct u_vbuf_mgr *mgrb)