Example #1
0
static enum pipe_error
draw_vgpu10(struct svga_hwtnl *hwtnl,
            const SVGA3dPrimitiveRange *range,
            unsigned vcount,
            unsigned min_index,
            unsigned max_index, struct pipe_resource *ib,
            unsigned start_instance, unsigned instance_count)
{
   struct svga_context *svga = hwtnl->svga;
   struct svga_winsys_surface *vb_handle[SVGA3D_INPUTREG_MAX];
   struct svga_winsys_surface *ib_handle;
   const unsigned vbuf_count = hwtnl->cmd.vbuf_count;
   enum pipe_error ret;
   unsigned i;

   assert(svga_have_vgpu10(svga));
   assert(hwtnl->cmd.prim_count == 0);

   /* We need to reemit all the current resource bindings along with the Draw
    * command to be sure that the referenced resources are available for the
    * Draw command, just in case the surfaces associated with the resources
    * are paged out.
    */
   if (svga->rebind.val) {
      ret = svga_rebind_framebuffer_bindings(svga);
      if (ret != PIPE_OK)
         return ret;

      ret = svga_rebind_shaders(svga);
      if (ret != PIPE_OK)
         return ret;
   }

   ret = validate_sampler_resources(svga);
   if (ret != PIPE_OK)
      return ret;

   ret = validate_constant_buffers(svga);
   if (ret != PIPE_OK)
      return ret;

   /* Get handle for each referenced vertex buffer */
   for (i = 0; i < vbuf_count; i++) {
      struct svga_buffer *sbuf = svga_buffer(hwtnl->cmd.vbufs[i].buffer);

      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)
            return PIPE_ERROR_OUT_OF_MEMORY;
      }
      else {
         vb_handle[i] = NULL;
      }
   }

   /* Get handles for the index buffers */
   if (ib) {
      struct svga_buffer *sbuf = svga_buffer(ib);

      assert(sbuf->key.flags & SVGA3D_SURFACE_BIND_INDEX_BUFFER);
      (void) sbuf; /* silence unused var warning */

      ib_handle = svga_buffer_handle(svga, ib);
      if (ib_handle == NULL)
         return PIPE_ERROR_OUT_OF_MEMORY;
   }
   else {
      ib_handle = NULL;
   }

   /* setup vertex attribute input layout */
   if (svga->state.hw_draw.layout_id != hwtnl->cmd.vdecl_layout_id) {
      ret = SVGA3D_vgpu10_SetInputLayout(svga->swc,
                                         hwtnl->cmd.vdecl_layout_id);
      if (ret != PIPE_OK)
         return ret;

      svga->state.hw_draw.layout_id = hwtnl->cmd.vdecl_layout_id;
   }

   /* setup vertex buffers */
   {
      SVGA3dVertexBuffer buffers[PIPE_MAX_ATTRIBS];

      for (i = 0; i < vbuf_count; i++) {
         buffers[i].stride = hwtnl->cmd.vbufs[i].stride;
         buffers[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;
      }
   }

   /* Set primitive type (line, tri, etc) */
   if (svga->state.hw_draw.topology != range->primType) {
      ret = SVGA3D_vgpu10_SetTopology(svga->swc, range->primType);
      if (ret != PIPE_OK)
         return ret;

      svga->state.hw_draw.topology = range->primType;
   }

   if (ib_handle) {
      /* indexed drawing */
      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 (instance_count > 1) {
         ret = SVGA3D_vgpu10_DrawIndexedInstanced(svga->swc,
                                                  vcount,
                                                  instance_count,
                                                  0, /* startIndexLocation */
                                                  range->indexBias,
                                                  start_instance);
         if (ret != PIPE_OK)
            return ret;
      }
      else {
         /* non-instanced drawing */
         ret = SVGA3D_vgpu10_DrawIndexed(svga->swc,
                                         vcount,
                                         0,      /* startIndexLocation */
                                         range->indexBias);
         if (ret != PIPE_OK)
            return ret;
      }
   }
   else {
      /* non-indexed drawing */
      if (instance_count > 1) {
         ret = SVGA3D_vgpu10_DrawInstanced(svga->swc,
                                           vcount,
                                           instance_count,
                                           range->indexBias,
                                           start_instance);
         if (ret != PIPE_OK)
            return ret;
      }
      else {
         /* non-instanced */
         ret = SVGA3D_vgpu10_Draw(svga->swc,
                                  vcount,
                                  range->indexBias);
         if (ret != PIPE_OK)
            return ret;
      }
   }

   hwtnl->cmd.prim_count = 0;

   return PIPE_OK;
}
Example #2
0
static enum pipe_error
draw_vgpu10(struct svga_hwtnl *hwtnl,
            const SVGA3dPrimitiveRange *range,
            unsigned vcount,
            unsigned min_index,
            unsigned max_index, struct pipe_resource *ib,
            unsigned start_instance, unsigned instance_count)
{
   struct svga_context *svga = hwtnl->svga;
   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;
   int last_vbuf = -1;
   enum pipe_error ret;
   unsigned i;

   assert(svga_have_vgpu10(svga));
   assert(hwtnl->cmd.prim_count == 0);

   /* We need to reemit all the current resource bindings along with the Draw
    * command to be sure that the referenced resources are available for the
    * Draw command, just in case the surfaces associated with the resources
    * are paged out.
    */
   if (svga->rebind.val) {
      ret = svga_rebind_framebuffer_bindings(svga);
      if (ret != PIPE_OK)
         return ret;

      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;

      /* No need to explicitly rebind index buffer and vertex buffers here.
       * Even if the same index buffer or vertex buffers are referenced for this
       * draw and we skip emitting the redundant set command, we will still
       * reference the associated resources.
       */
   }

   ret = validate_sampler_resources(svga);
   if (ret != PIPE_OK)
      return ret;

   ret = validate_constant_buffers(svga);
   if (ret != PIPE_OK)
      return ret;

   /* Get handle for each referenced vertex buffer */
   for (i = 0; i < vbuf_count; i++) {
      struct svga_buffer *sbuf = svga_buffer(hwtnl->cmd.vbufs[i].buffer);

      if (sbuf) {
         assert(sbuf->key.flags & SVGA3D_SURFACE_BIND_VERTEX_BUFFER);
         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;
         last_vbuf = i;
      }
      else {
         vbuffers[i] = NULL;
         vbuffer_handles[i] = NULL;
      }
   }

   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);

      assert(sbuf->key.flags & SVGA3D_SURFACE_BIND_INDEX_BUFFER);
      (void) sbuf; /* silence unused var warning */

      ib_handle = svga_buffer_handle(svga, ib);
      if (!ib_handle)
         return PIPE_ERROR_OUT_OF_MEMORY;
   }
   else {
      ib_handle = NULL;
   }

   /* setup vertex attribute input layout */
   if (svga->state.hw_draw.layout_id != hwtnl->cmd.vdecl_layout_id) {
      ret = SVGA3D_vgpu10_SetInputLayout(svga->swc,
                                         hwtnl->cmd.vdecl_layout_id);
      if (ret != PIPE_OK)
         return ret;

      svga->state.hw_draw.layout_id = hwtnl->cmd.vdecl_layout_id;
   }

   /* setup vertex buffers */
   {
      SVGA3dVertexBuffer vbuffer_attrs[PIPE_MAX_ATTRIBS];

      for (i = 0; i < vbuf_count; i++) {
         vbuffer_attrs[i].stride = hwtnl->cmd.vbufs[i].stride;
         vbuffer_attrs[i].offset = hwtnl->cmd.vbufs[i].buffer_offset;
         vbuffer_attrs[i].sid = 0;
      }

      /* If we haven't yet emitted a drawing command or if any
       * vertex buffer state is changing, issue that state now.
       */
      if (((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;

            /* save the number of vertex buffers sent to the device, not
             * including trailing unbound vertex buffers.
             */
            svga->state.hw_draw.num_vbuffers = last_vbuf + 1;
            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++) {
            if (vbuffer_handles[i] && !last_command_was_draw(svga)) {
               ret = svga->swc->resource_rebind(svga->swc, vbuffer_handles[i],
                                                NULL, SVGA_RELOC_READ);
               if (ret != PIPE_OK)
                  return ret;
            }
         }
      }
   }

   /* Set primitive type (line, tri, etc) */
   if (svga->state.hw_draw.topology != range->primType) {
      ret = SVGA3D_vgpu10_SetTopology(svga->swc, range->primType);
      if (ret != PIPE_OK)
         return ret;

      svga->state.hw_draw.topology = range->primType;
   }

   if (ib_handle) {
      /* indexed drawing */
      SVGA3dSurfaceFormat indexFormat = xlate_index_format(range->indexWidth);

      /* setup index buffer */
      if (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.
          */
         if (!last_command_was_draw(svga)) {
            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,
                                                  vcount,
                                                  instance_count,
                                                  0, /* startIndexLocation */
                                                  range->indexBias,
                                                  start_instance);
         if (ret != PIPE_OK)
            return ret;
      }
      else {
         /* non-instanced drawing */
         ret = SVGA3D_vgpu10_DrawIndexed(svga->swc,
                                         vcount,
                                         0,      /* startIndexLocation */
                                         range->indexBias);
         if (ret != PIPE_OK)
            return ret;
      }
   }
   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,
                                           instance_count,
                                           range->indexBias,
                                           start_instance);
         if (ret != PIPE_OK)
            return ret;
      }
      else {
         /* non-instanced */
         ret = SVGA3D_vgpu10_Draw(svga->swc,
                                  vcount,
                                  range->indexBias);
         if (ret != PIPE_OK)
            return ret;
      }
   }

   hwtnl->cmd.prim_count = 0;

   return PIPE_OK;
}