svga: fix use of provoking vertex control
[mesa.git] / src / gallium / drivers / svga / svga_draw.c
index 9b6451da2f950a6992e421580eb1be61f74ea790..600df89200661960485ef60ffdb8f02c3763bb59 100644 (file)
@@ -48,7 +48,7 @@ struct svga_hwtnl *
 svga_hwtnl_create(struct svga_context *svga)
 {
    struct svga_hwtnl *hwtnl = CALLOC_STRUCT(svga_hwtnl);
-   if (hwtnl == NULL)
+   if (!hwtnl)
       goto fail;
 
    hwtnl->svga = svga;
@@ -189,7 +189,7 @@ draw_vgpu9(struct svga_hwtnl *hwtnl)
    for (i = 0; i < hwtnl->cmd.vdecl_count; i++) {
       unsigned j = hwtnl->cmd.vdecl_buffer_index[i];
       handle = svga_buffer_handle(svga, hwtnl->cmd.vbufs[j].buffer);
-      if (handle == NULL)
+      if (!handle)
          return PIPE_ERROR_OUT_OF_MEMORY;
 
       vb_handle[i] = handle;
@@ -198,7 +198,7 @@ draw_vgpu9(struct svga_hwtnl *hwtnl)
    for (i = 0; i < hwtnl->cmd.prim_count; i++) {
       if (hwtnl->cmd.prim_ib[i]) {
          handle = svga_buffer_handle(svga, hwtnl->cmd.prim_ib[i]);
-         if (handle == NULL)
+         if (!handle)
             return PIPE_ERROR_OUT_OF_MEMORY;
       }
       else
@@ -436,11 +436,14 @@ draw_vgpu10(struct svga_hwtnl *hwtnl,
             unsigned start_instance, unsigned instance_count)
 {
    struct svga_context *svga = hwtnl->svga;
-   struct svga_winsys_surface *vb_handle[SVGA3D_INPUTREG_MAX];
+   struct pipe_resource *vbuffers[SVGA3D_INPUTREG_MAX];
+   struct svga_winsys_surface *vbuffer_handles[SVGA3D_INPUTREG_MAX];
    struct svga_winsys_surface *ib_handle;
    const unsigned vbuf_count = hwtnl->cmd.vbuf_count;
    enum pipe_error ret;
    unsigned i;
+   boolean rebind_ib = FALSE;
+   boolean rebind_vbuf = FALSE;
 
    assert(svga_have_vgpu10(svga));
    assert(hwtnl->cmd.prim_count == 0);
@@ -458,6 +461,17 @@ draw_vgpu10(struct svga_hwtnl *hwtnl,
       ret = svga_rebind_shaders(svga);
       if (ret != PIPE_OK)
          return ret;
+
+      /* Rebind stream output targets */
+      ret = svga_rebind_stream_output_targets(svga);
+      if (ret != PIPE_OK)
+         return ret;
+
+      /* Force rebinding the index buffer when needed */
+      rebind_ib = TRUE;
+
+      /* Force rebinding the vertex buffers */
+      rebind_vbuf = TRUE;
    }
 
    ret = validate_sampler_resources(svga);
@@ -474,16 +488,23 @@ draw_vgpu10(struct svga_hwtnl *hwtnl,
 
       if (sbuf) {
          assert(sbuf->key.flags & SVGA3D_SURFACE_BIND_VERTEX_BUFFER);
-         vb_handle[i] = svga_buffer_handle(svga, &sbuf->b.b);
-         if (vb_handle[i] == NULL)
+         vbuffer_handles[i] = svga_buffer_handle(svga, &sbuf->b.b);
+         if (vbuffer_handles[i] == NULL)
             return PIPE_ERROR_OUT_OF_MEMORY;
+         vbuffers[i] = &sbuf->b.b;
       }
       else {
-         vb_handle[i] = NULL;
+         vbuffers[i] = NULL;
+         vbuffer_handles[i] = NULL;
       }
    }
 
-   /* Get handles for the index buffers */
+   for (; i < svga->state.hw_draw.num_vbuffers; i++) {
+      vbuffers[i] = NULL;
+      vbuffer_handles[i] = NULL;
+   }
+
+   /* Get handle for the index buffer */
    if (ib) {
       struct svga_buffer *sbuf = svga_buffer(ib);
 
@@ -491,7 +512,7 @@ draw_vgpu10(struct svga_hwtnl *hwtnl,
       (void) sbuf; /* silence unused var warning */
 
       ib_handle = svga_buffer_handle(svga, ib);
-      if (ib_handle == NULL)
+      if (!ib_handle)
          return PIPE_ERROR_OUT_OF_MEMORY;
    }
    else {
@@ -510,18 +531,62 @@ draw_vgpu10(struct svga_hwtnl *hwtnl,
 
    /* setup vertex buffers */
    {
-      SVGA3dVertexBuffer buffers[PIPE_MAX_ATTRIBS];
+      SVGA3dVertexBuffer vbuffer_attrs[PIPE_MAX_ATTRIBS];
+
+      memset(vbuffer_attrs, 0, sizeof(vbuffer_attrs));
 
       for (i = 0; i < vbuf_count; i++) {
-         buffers[i].stride = hwtnl->cmd.vbufs[i].stride;
-         buffers[i].offset = hwtnl->cmd.vbufs[i].buffer_offset;
+         vbuffer_attrs[i].stride = hwtnl->cmd.vbufs[i].stride;
+         vbuffer_attrs[i].offset = hwtnl->cmd.vbufs[i].buffer_offset;
       }
-      if (vbuf_count > 0) {
-         ret = SVGA3D_vgpu10_SetVertexBuffers(svga->swc, vbuf_count,
-                                              0,    /* startBuffer */
-                                              buffers, vb_handle);
-         if (ret != PIPE_OK)
-            return ret;
+
+      /* If we haven't yet emitted a drawing command or if any
+       * vertex buffer state is changing, issue that state now.
+       */
+      if (rebind_vbuf ||
+          ((hwtnl->cmd.swc->hints & SVGA_HINT_FLAG_CAN_PRE_FLUSH) == 0) ||
+          vbuf_count != svga->state.hw_draw.num_vbuffers ||
+          memcmp(vbuffer_attrs, svga->state.hw_draw.vbuffer_attrs,
+                 vbuf_count * sizeof(vbuffer_attrs[0])) ||
+          memcmp(vbuffers, svga->state.hw_draw.vbuffers,
+                 vbuf_count * sizeof(vbuffers[0]))) {
+
+         unsigned num_vbuffers;
+
+         /* get the max of the current bound vertex buffers count and
+          * the to-be-bound vertex buffers count, so as to unbind
+          * the unused vertex buffers.
+          */
+         num_vbuffers = MAX2(vbuf_count, svga->state.hw_draw.num_vbuffers);
+
+         if (num_vbuffers > 0) {
+
+            ret = SVGA3D_vgpu10_SetVertexBuffers(svga->swc, num_vbuffers,
+                                                 0,    /* startBuffer */
+                                                 vbuffer_attrs,
+                                                 vbuffer_handles);
+            if (ret != PIPE_OK)
+               return ret;
+
+            svga->state.hw_draw.num_vbuffers = num_vbuffers;
+            memcpy(svga->state.hw_draw.vbuffer_attrs, vbuffer_attrs,
+                   num_vbuffers * sizeof(vbuffer_attrs[0]));
+            for (i = 0; i < num_vbuffers; i++) {
+               pipe_resource_reference(&svga->state.hw_draw.vbuffers[i],
+                                       vbuffers[i]);
+            }
+         }
+      }
+      else {
+         /* Even though we can avoid emitting the redundant SetVertexBuffers
+          * command, we still need to reference the vertex buffers surfaces.
+          */
+         for (i = 0; i < vbuf_count; i++) {
+            ret = svga->swc->resource_rebind(svga->swc, vbuffer_handles[i],
+                                             NULL, SVGA_RELOC_READ);
+            if (ret != PIPE_OK)
+               return ret;
+         }
       }
    }
 
@@ -539,11 +604,31 @@ draw_vgpu10(struct svga_hwtnl *hwtnl,
       SVGA3dSurfaceFormat indexFormat = xlate_index_format(range->indexWidth);
 
       /* setup index buffer */
-      ret = SVGA3D_vgpu10_SetIndexBuffer(svga->swc, ib_handle,
-                                         indexFormat,
-                                         range->indexArray.offset);
-      if (ret != PIPE_OK)
-         return ret;
+      if (rebind_ib ||
+          ib != svga->state.hw_draw.ib ||
+          indexFormat != svga->state.hw_draw.ib_format ||
+          range->indexArray.offset != svga->state.hw_draw.ib_offset) {
+
+         assert(indexFormat != SVGA3D_FORMAT_INVALID);
+         ret = SVGA3D_vgpu10_SetIndexBuffer(svga->swc, ib_handle,
+                                            indexFormat,
+                                            range->indexArray.offset);
+         if (ret != PIPE_OK)
+            return ret;
+
+         pipe_resource_reference(&svga->state.hw_draw.ib, ib);
+         svga->state.hw_draw.ib_format = indexFormat;
+         svga->state.hw_draw.ib_offset = range->indexArray.offset;
+      }
+      else {
+         /* Even though we can avoid emitting the redundant SetIndexBuffer
+          * command, we still need to reference the index buffer surface.
+          */
+         ret = svga->swc->resource_rebind(svga->swc, ib_handle,
+                                          NULL, SVGA_RELOC_READ);
+         if (ret != PIPE_OK)
+            return ret;
+      }
 
       if (instance_count > 1) {
          ret = SVGA3D_vgpu10_DrawIndexedInstanced(svga->swc,
@@ -567,6 +652,19 @@ draw_vgpu10(struct svga_hwtnl *hwtnl,
    }
    else {
       /* non-indexed drawing */
+      if (svga->state.hw_draw.ib_format != SVGA3D_FORMAT_INVALID ||
+          svga->state.hw_draw.ib != NULL) {
+         /* Unbind previously bound index buffer */
+         ret = SVGA3D_vgpu10_SetIndexBuffer(svga->swc, NULL,
+                                            SVGA3D_FORMAT_INVALID, 0);
+         if (ret != PIPE_OK)
+            return ret;
+         pipe_resource_reference(&svga->state.hw_draw.ib, NULL);
+         svga->state.hw_draw.ib_format = SVGA3D_FORMAT_INVALID;
+      }
+
+      assert(svga->state.hw_draw.ib == NULL);
+
       if (instance_count > 1) {
          ret = SVGA3D_vgpu10_DrawInstanced(svga->swc,
                                            vcount,
@@ -728,17 +826,14 @@ check_draw_params(struct svga_hwtnl *hwtnl,
    assert(range->indexWidth == range->indexArray.stride);
 
    if (ib) {
-      unsigned size = ib->width0;
-      unsigned offset = range->indexArray.offset;
-      unsigned stride = range->indexArray.stride;
-      unsigned count;
+      MAYBE_UNUSED unsigned size = ib->width0;
+      MAYBE_UNUSED unsigned offset = range->indexArray.offset;
+      MAYBE_UNUSED unsigned stride = range->indexArray.stride;
+      MAYBE_UNUSED unsigned count;
 
       assert(size);
       assert(offset < size);
       assert(stride);
-      (void) size;
-      (void) offset;
-      (void) stride;
 
       switch (range->primType) {
       case SVGA3D_PRIMITIVE_POINTLIST: