u_blitter: add a msaa parameter to util_blitter_clear
[mesa.git] / src / gallium / drivers / svga / svga_pipe_draw.c
index d53edcb23c534de320e9f880a5cf1c823e7e3a8d..5ebd17cf0eabc5c50685467353883625beefdd9e 100644 (file)
  *
  **********************************************************/
 
-#include "svga_cmd.h"
 
-#include "util/u_format.h"
+#include "util/u_helpers.h"
 #include "util/u_inlines.h"
 #include "util/u_prim.h"
-#include "util/u_time.h"
-#include "indices/u_indices.h"
+#include "util/u_prim_restart.h"
 
-#include "svga_hw_reg.h"
 #include "svga_context.h"
-#include "svga_screen.h"
 #include "svga_draw.h"
-#include "svga_state.h"
+#include "svga_shader.h"
+#include "svga_surface.h"
 #include "svga_swtnl.h"
 #include "svga_debug.h"
 #include "svga_resource_buffer.h"
-#include "util/u_upload_mgr.h"
 
-/**
- * Determine the ranges to upload for the user-buffers referenced
- * by the next draw command.
- *
- * 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.
+/* Returns TRUE if we are currently using flat shading.
  */
-
-static void
-svga_user_buffer_range(struct svga_context *svga,
-                       unsigned start,
-                       unsigned count,
-                       unsigned instance_count)
+static boolean
+is_using_flat_shading(const struct svga_context *svga)
 {
-   const struct pipe_vertex_element *ve = svga->curr.velems->velem;
-   int 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 if (vb->stride) {
-            first = vb->stride * start + ve[i].src_offset;
-            size = vb->stride * (count - 1) + elemSize;
-         } else {
-            /* Only a single vertex!
-             * Upload with the largest vertex size the hw supports,
-             * if possible.
-             */
-            first = ve[i].src_offset;
-            size = MIN2(16, vb->buffer->width0);
-         }
-
-         buffer->uploaded.start = MIN2(buffer->uploaded.start, first);
-         buffer->uploaded.end = MAX2(buffer->uploaded.end, first + size);
-      }
-   }
+   return
+      svga->state.hw_draw.fs ? svga->state.hw_draw.fs->uses_flat_interp : FALSE;
 }
 
-/**
- * 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,
-                         unsigned count,
-                         unsigned instance_count)
+static enum pipe_error
+retry_draw_range_elements(struct svga_context *svga,
+                          const struct pipe_draw_info *info,
+                          unsigned count)
 {
-   const struct pipe_vertex_element *ve = svga->curr.velems->velem;
-   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];
+   enum pipe_error ret;
 
-      if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
-         struct svga_buffer *buffer = svga_buffer(vb->buffer);
-         boolean flushed;
+   SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_DRAWELEMENTS);
 
-         /*
-          * Check if already uploaded. Otherwise go ahead and upload.
-          */
-
-         if (buffer->uploaded.buffer)
-            continue;
-
-         ret = u_upload_buffer( svga->upload_vb,
-                                0,
-                                buffer->uploaded.start,
-                                buffer->uploaded.end - buffer->uploaded.start,
-                                &buffer->b.b,
-                                &buffer->uploaded.offset,
-                                &buffer->uploaded.buffer,
-                                &flushed);
-
-         if (ret)
-            return ret;
-
-         if (0)
-            debug_printf("%s: %d: orig buf %p upl buf %p ofs %d sofs %d"
-                         " sz %d\n",
-                         __FUNCTION__,
-                         i,
-                         buffer,
-                         buffer->uploaded.buffer,
-                         buffer->uploaded.offset,
-                         buffer->uploaded.start,
-                         buffer->uploaded.end - buffer->uploaded.start);
-
-         vb->buffer_offset = buffer->uploaded.offset;
-      }
+   ret = svga_hwtnl_draw_range_elements(svga->hwtnl, info, count);
+   if (ret != PIPE_OK) {
+      svga_context_flush(svga, NULL);
+      ret = svga_hwtnl_draw_range_elements(svga->hwtnl, info, count);
    }
 
-   return PIPE_OK;
-}
-
-/**
- * svga_release_user_upl_buffers - release uploaded parts of user buffers
- *
- * This function releases the hw copy of the uploaded fraction of the
- * user-buffer. It's important to do this as soon as all draw calls
- * affecting the uploaded fraction are issued, as this allows for
- * efficient reuse of the hardware surface backing the uploaded fraction.
- *
- * 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)
-{
-   unsigned i;
-   unsigned nr;
-
-   nr = svga->curr.num_vertex_buffers;
-
-   for (i = 0; i < nr; ++i) {
-      struct pipe_vertex_buffer *vb = &svga->curr.vb[i];
-
-      if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
-         struct svga_buffer *buffer = svga_buffer(vb->buffer);
-
-         buffer->uploaded.start = ~0;
-         buffer->uploaded.end = 0;
-         if (buffer->uploaded.buffer)
-            pipe_resource_reference(&buffer->uploaded.buffer, NULL);
-      }
-   }
+   assert (ret == PIPE_OK);
+   SVGA_STATS_TIME_POP(svga_sws(svga));
+   return ret;
 }
 
 
-
 static enum pipe_error
-retry_draw_range_elements( struct svga_context *svga,
-                           struct pipe_resource *index_buffer,
-                           unsigned index_size,
-                           int index_bias,
-                           unsigned min_index,
-                           unsigned max_index,
-                           unsigned prim, 
-                           unsigned start, 
-                           unsigned count,
-                           unsigned instance_count,
-                           boolean do_retry )
+retry_draw_arrays(struct svga_context *svga,
+                  enum pipe_prim_type prim, unsigned start, unsigned count,
+                  unsigned start_instance, unsigned instance_count)
 {
-   enum pipe_error ret = 0;
+   enum pipe_error ret;
+
+   SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_DRAWARRAYS);
 
-   svga_hwtnl_set_unfilled( svga->hwtnl,
-                            svga->curr.rast->hw_unfilled );
-
-   svga_hwtnl_set_flatshade( svga->hwtnl,
-                             svga->curr.rast->templ.flatshade,
-                             svga->curr.rast->templ.flatshade_first );
-
-   ret = svga_upload_user_buffers( svga, min_index + index_bias,
-                                   max_index - min_index + 1, instance_count );
-   if (ret != PIPE_OK)
-      goto retry;
-
-   ret = svga_update_state( svga, SVGA_STATE_HW_DRAW );
-   if (ret)
-      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)
-      goto retry;
-
-   return PIPE_OK;
-
-retry:
-   svga_context_flush( svga, NULL );
-
-   if (do_retry)
-   {
-      return retry_draw_range_elements( svga,
-                                        index_buffer, index_size, index_bias,
-                                        min_index, max_index,
-                                        prim, start, count,
-                                        instance_count, FALSE );
+   for (unsigned try = 0; try < 2; try++) {
+      ret = svga_hwtnl_draw_arrays(svga->hwtnl, prim, start, count,
+                                   start_instance, instance_count);
+      if (ret == PIPE_OK)
+         break;
+      svga_context_flush(svga, NULL);
    }
 
+   SVGA_STATS_TIME_POP(svga_sws(svga));
    return ret;
 }
 
 
-static enum pipe_error
-retry_draw_arrays( struct svga_context *svga,
-                   unsigned prim, 
-                   unsigned start, 
-                   unsigned count,
-                   unsigned instance_count,
-                   boolean do_retry )
+/**
+ * Determine if we need to implement primitive restart with a fallback
+ * path which breaks the original primitive into sub-primitive at the
+ * restart indexes.
+ */
+static boolean
+need_fallback_prim_restart(const struct svga_context *svga,
+                           const struct pipe_draw_info *info)
 {
-   enum pipe_error ret;
-
-   svga_hwtnl_set_unfilled( svga->hwtnl,
-                            svga->curr.rast->hw_unfilled );
-
-   svga_hwtnl_set_flatshade( svga->hwtnl,
-                             svga->curr.rast->templ.flatshade,
-                             svga->curr.rast->templ.flatshade_first );
-
-   ret = svga_upload_user_buffers( svga, start, count, instance_count );
-
-   if (ret != PIPE_OK)
-      goto retry;
-
-   ret = svga_update_state( svga, SVGA_STATE_HW_DRAW );
-   if (ret)
-      goto retry;
-
-   ret = svga_hwtnl_draw_arrays( svga->hwtnl, prim,
-                                 start, count );
-   if (ret)
-      goto retry;
-
-   return 0;
-
-retry:
-   if (ret == PIPE_ERROR_OUT_OF_MEMORY && do_retry) 
-   {
-      svga_context_flush( svga, NULL );
-
-      return retry_draw_arrays( svga,
-                                prim,
-                                start,
-                                count,
-                                instance_count,
-                                FALSE );
+   if (info->primitive_restart && info->index_size) {
+      if (!svga_have_vgpu10(svga))
+         return TRUE;
+      else if (!svga->state.sw.need_swtnl) {
+         if (info->index_size == 1)
+            return TRUE; /* no device support for 1-byte indexes */
+         else if (info->index_size == 2)
+            return info->restart_index != 0xffff;
+         else
+            return info->restart_index != 0xffffffff;
+      }
    }
 
-   return ret;
+   return FALSE;
 }
 
 
 static void
 svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
 {
-   struct svga_context *svga = svga_context( pipe );
-   unsigned reduced_prim = u_reduced_prim( info->mode );
+   struct svga_context *svga = svga_context(pipe);
+   enum pipe_prim_type reduced_prim = u_reduced_prim(info->mode);
    unsigned count = info->count;
    enum pipe_error ret = 0;
    boolean needed_swtnl;
 
-   if (!u_trim_pipe_prim( info->mode, &count ))
-      return;
+   SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_DRAWVBO);
+
+   svga->hud.num_draw_calls++;  /* for SVGA_QUERY_NUM_DRAW_CALLS */
+
+   if (u_reduced_prim(info->mode) == PIPE_PRIM_TRIANGLES &&
+       svga->curr.rast->templ.cull_face == PIPE_FACE_FRONT_AND_BACK)
+      goto done;
 
    /*
     * Mark currently bound target surfaces as dirty
@@ -344,18 +146,24 @@ 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 );
+   if (need_fallback_prim_restart(svga, info)) {
+      enum pipe_error r;
+      r = util_draw_vbo_without_prim_restart(pipe, info);
+      assert(r == PIPE_OK);
+      (void) r;
+      goto done;
+   }
 
-#ifdef DEBUG
-   if (svga->curr.vs->base.id == svga->debug.disable_shader ||
-       svga->curr.fs->base.id == svga->debug.disable_shader)
-      return;
-#endif
+   if (!u_trim_pipe_prim(info->mode, &count))
+      goto done;
+
+   needed_swtnl = svga->state.sw.need_swtnl;
+
+   svga_update_state_retry(svga, SVGA_STATE_NEED_SWTNL);
 
    if (svga->state.sw.need_swtnl) {
+      svga->hud.num_fallbacks++;  /* for SVGA_QUERY_NUM_FALLBACKS */
       if (!needed_swtnl) {
          /*
           * We're switching from HW to SW TNL.  SW TNL will require mapping all
@@ -369,48 +177,50 @@ svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
       }
 
       /* Avoid leaking the previous hwtnl bias to swtnl */
-      svga_hwtnl_set_index_bias( svga->hwtnl, 0 );
-      ret = svga_swtnl_draw_vbo( svga, info );
+      svga_hwtnl_set_index_bias(svga->hwtnl, 0);
+      ret = svga_swtnl_draw_vbo(svga, info);
    }
    else {
-      if (info->indexed && svga->curr.ib.buffer) {
-         unsigned offset;
-
-         assert(svga->curr.ib.offset % svga->curr.ib.index_size == 0);
-         offset = svga->curr.ib.offset / svga->curr.ib.index_size;
-
-         ret = retry_draw_range_elements( svga,
-                                          svga->curr.ib.buffer,
-                                          svga->curr.ib.index_size,
-                                          info->index_bias,
-                                          info->min_index,
-                                          info->max_index,
-                                          info->mode,
-                                          info->start + offset,
-                                          info->count,
-                                          info->instance_count,
-                                          TRUE );
+      if (!svga_update_state_retry(svga, SVGA_STATE_HW_DRAW)) {
+         static const char *msg = "State update failed, skipping draw call";
+         debug_printf("%s\n", msg);
+         pipe_debug_message(&svga->debug.callback, INFO, "%s", msg);
+         goto done;
+      }
+      svga_hwtnl_set_fillmode(svga->hwtnl, svga->curr.rast->hw_fillmode);
+
+      /** determine if flatshade is to be used after svga_update_state()
+       *  in case the fragment shader is changed.
+       */
+      svga_hwtnl_set_flatshade(svga->hwtnl,
+                               svga->curr.rast->templ.flatshade ||
+                               is_using_flat_shading(svga),
+                               svga->curr.rast->templ.flatshade_first);
+
+      if (info->index_size) {
+         ret = retry_draw_range_elements(svga, info, count);
       }
       else {
-         ret = retry_draw_arrays( svga,
-                                  info->mode,
-                                  info->start,
-                                  info->count,
-                                  info->instance_count,
-                                  TRUE );
+         ret = retry_draw_arrays(svga, info->mode, info->start, count,
+                                 info->start_instance, info->instance_count);
       }
    }
 
-   svga_release_user_upl_buffers( svga );
+   /* XXX: Silence warnings, do something sensible here? */
+   (void)ret;
 
    if (SVGA_DEBUG & DEBUG_FLUSH) {
-      svga_hwtnl_flush_retry( svga );
+      svga_hwtnl_flush_retry(svga);
       svga_context_flush(svga, NULL);
    }
+
+done:
+   SVGA_STATS_TIME_POP(svga_sws(svga));
 }
 
 
-void svga_init_draw_functions( struct svga_context *svga )
+void
+svga_init_draw_functions(struct svga_context *svga)
 {
    svga->pipe.draw_vbo = svga_draw_vbo;
 }