14a49301eSmrg/**********************************************************
24a49301eSmrg * Copyright 2008-2009 VMware, Inc.  All rights reserved.
34a49301eSmrg *
44a49301eSmrg * Permission is hereby granted, free of charge, to any person
54a49301eSmrg * obtaining a copy of this software and associated documentation
64a49301eSmrg * files (the "Software"), to deal in the Software without
74a49301eSmrg * restriction, including without limitation the rights to use, copy,
84a49301eSmrg * modify, merge, publish, distribute, sublicense, and/or sell copies
94a49301eSmrg * of the Software, and to permit persons to whom the Software is
104a49301eSmrg * furnished to do so, subject to the following conditions:
114a49301eSmrg *
124a49301eSmrg * The above copyright notice and this permission notice shall be
134a49301eSmrg * included in all copies or substantial portions of the Software.
144a49301eSmrg *
154a49301eSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
164a49301eSmrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
174a49301eSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
184a49301eSmrg * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
194a49301eSmrg * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
204a49301eSmrg * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
214a49301eSmrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
224a49301eSmrg * SOFTWARE.
234a49301eSmrg *
244a49301eSmrg **********************************************************/
254a49301eSmrg
264a49301eSmrg#include "pipe/p_compiler.h"
27cdc920a0Smrg#include "util/u_inlines.h"
284a49301eSmrg#include "pipe/p_defines.h"
2901e04c3fSmrg#include "util/u_helpers.h"
304a49301eSmrg#include "util/u_memory.h"
314a49301eSmrg#include "util/u_math.h"
324a49301eSmrg
334a49301eSmrg#include "svga_context.h"
344a49301eSmrg#include "svga_draw.h"
354a49301eSmrg#include "svga_draw_private.h"
364a49301eSmrg#include "svga_debug.h"
374a49301eSmrg#include "svga_screen.h"
3801e04c3fSmrg#include "svga_resource.h"
393464ebd5Sriastradh#include "svga_resource_buffer.h"
403464ebd5Sriastradh#include "svga_resource_texture.h"
4101e04c3fSmrg#include "svga_sampler_view.h"
4201e04c3fSmrg#include "svga_shader.h"
433464ebd5Sriastradh#include "svga_surface.h"
444a49301eSmrg#include "svga_winsys.h"
454a49301eSmrg#include "svga_cmd.h"
464a49301eSmrg
474a49301eSmrg
48af69d88dSmrgstruct svga_hwtnl *
49af69d88dSmrgsvga_hwtnl_create(struct svga_context *svga)
504a49301eSmrg{
514a49301eSmrg   struct svga_hwtnl *hwtnl = CALLOC_STRUCT(svga_hwtnl);
5201e04c3fSmrg   if (!hwtnl)
534a49301eSmrg      goto fail;
544a49301eSmrg
554a49301eSmrg   hwtnl->svga = svga;
56af69d88dSmrg
57af69d88dSmrg   hwtnl->cmd.swc = svga->swc;
584a49301eSmrg
594a49301eSmrg   return hwtnl;
604a49301eSmrg
614a49301eSmrgfail:
624a49301eSmrg   return NULL;
634a49301eSmrg}
644a49301eSmrg
65af69d88dSmrg
66af69d88dSmrgvoid
67af69d88dSmrgsvga_hwtnl_destroy(struct svga_hwtnl *hwtnl)
684a49301eSmrg{
69af69d88dSmrg   unsigned i, j;
704a49301eSmrg
714a49301eSmrg   for (i = 0; i < PIPE_PRIM_MAX; i++) {
724a49301eSmrg      for (j = 0; j < IDX_CACHE_MAX; j++) {
73af69d88dSmrg         pipe_resource_reference(&hwtnl->index_cache[i][j].buffer, NULL);
744a49301eSmrg      }
754a49301eSmrg   }
764a49301eSmrg
7701e04c3fSmrg   for (i = 0; i < hwtnl->cmd.vbuf_count; i++)
7801e04c3fSmrg      pipe_vertex_buffer_unreference(&hwtnl->cmd.vbufs[i]);
794a49301eSmrg
804a49301eSmrg   for (i = 0; i < hwtnl->cmd.prim_count; i++)
813464ebd5Sriastradh      pipe_resource_reference(&hwtnl->cmd.prim_ib[i], NULL);
824a49301eSmrg
834a49301eSmrg   FREE(hwtnl);
844a49301eSmrg}
854a49301eSmrg
864a49301eSmrg
87af69d88dSmrgvoid
88af69d88dSmrgsvga_hwtnl_set_flatshade(struct svga_hwtnl *hwtnl,
89af69d88dSmrg                         boolean flatshade, boolean flatshade_first)
904a49301eSmrg{
9101e04c3fSmrg   struct svga_screen *svgascreen = svga_screen(hwtnl->svga->pipe.screen);
9201e04c3fSmrg
9301e04c3fSmrg   /* User-specified PV */
944a49301eSmrg   hwtnl->api_pv = (flatshade && !flatshade_first) ? PV_LAST : PV_FIRST;
9501e04c3fSmrg
9601e04c3fSmrg   /* Device supported PV */
9701e04c3fSmrg   if (svgascreen->haveProvokingVertex) {
9801e04c3fSmrg      /* use the mode specified by the user */
9901e04c3fSmrg      hwtnl->hw_pv = hwtnl->api_pv;
10001e04c3fSmrg   }
10101e04c3fSmrg   else {
10201e04c3fSmrg      /* the device only support first provoking vertex */
10301e04c3fSmrg      hwtnl->hw_pv = PV_FIRST;
10401e04c3fSmrg   }
105af69d88dSmrg}
106af69d88dSmrg
1074a49301eSmrg
108af69d88dSmrgvoid
10901e04c3fSmrgsvga_hwtnl_set_fillmode(struct svga_hwtnl *hwtnl, unsigned mode)
1104a49301eSmrg{
1114a49301eSmrg   hwtnl->api_fillmode = mode;
112af69d88dSmrg}
113af69d88dSmrg
1144a49301eSmrg
115af69d88dSmrgvoid
11601e04c3fSmrgsvga_hwtnl_vertex_decls(struct svga_hwtnl *hwtnl,
11701e04c3fSmrg                        unsigned count,
11801e04c3fSmrg                        const SVGA3dVertexDecl * decls,
11901e04c3fSmrg                        const unsigned *buffer_indexes,
12001e04c3fSmrg                        SVGA3dElementLayoutId layout_id)
1214a49301eSmrg{
1224a49301eSmrg   assert(hwtnl->cmd.prim_count == 0);
1234a49301eSmrg   hwtnl->cmd.vdecl_count = count;
12401e04c3fSmrg   hwtnl->cmd.vdecl_layout_id = layout_id;
12501e04c3fSmrg   memcpy(hwtnl->cmd.vdecl, decls, count * sizeof(*decls));
12601e04c3fSmrg   memcpy(hwtnl->cmd.vdecl_buffer_index, buffer_indexes,
12701e04c3fSmrg          count * sizeof(unsigned));
1284a49301eSmrg}
1294a49301eSmrg
1304a49301eSmrg
13101e04c3fSmrg/**
13201e04c3fSmrg * Specify vertex buffers for hardware drawing.
13301e04c3fSmrg */
134af69d88dSmrgvoid
13501e04c3fSmrgsvga_hwtnl_vertex_buffers(struct svga_hwtnl *hwtnl,
13601e04c3fSmrg                          unsigned count, struct pipe_vertex_buffer *buffers)
1374a49301eSmrg{
13801e04c3fSmrg   struct pipe_vertex_buffer *dst = hwtnl->cmd.vbufs;
13901e04c3fSmrg   const struct pipe_vertex_buffer *src = buffers;
14001e04c3fSmrg   unsigned i;
1414a49301eSmrg
14201e04c3fSmrg   for (i = 0; i < count; i++) {
14301e04c3fSmrg      pipe_vertex_buffer_reference(&dst[i], &src[i]);
14401e04c3fSmrg   }
1454a49301eSmrg
14601e04c3fSmrg   /* release old buffer references */
14701e04c3fSmrg   for ( ; i < hwtnl->cmd.vbuf_count; i++) {
14801e04c3fSmrg      pipe_vertex_buffer_unreference(&dst[i]);
14901e04c3fSmrg      /* don't bother zeroing stride/offset fields */
15001e04c3fSmrg   }
1514a49301eSmrg
15201e04c3fSmrg   hwtnl->cmd.vbuf_count = count;
1534a49301eSmrg}
1544a49301eSmrg
1554a49301eSmrg
156af69d88dSmrg/**
157af69d88dSmrg * Determine whether the specified buffer is referred in the primitive queue,
158af69d88dSmrg * for which no commands have been written yet.
159af69d88dSmrg */
160af69d88dSmrgboolean
161af69d88dSmrgsvga_hwtnl_is_buffer_referred(struct svga_hwtnl *hwtnl,
162af69d88dSmrg                              struct pipe_resource *buffer)
163af69d88dSmrg{
164af69d88dSmrg   unsigned i;
165af69d88dSmrg
166af69d88dSmrg   if (svga_buffer_is_user_buffer(buffer)) {
167af69d88dSmrg      return FALSE;
168af69d88dSmrg   }
169af69d88dSmrg
170af69d88dSmrg   if (!hwtnl->cmd.prim_count) {
171af69d88dSmrg      return FALSE;
172af69d88dSmrg   }
173af69d88dSmrg
17401e04c3fSmrg   for (i = 0; i < hwtnl->cmd.vbuf_count; ++i) {
17501e04c3fSmrg      if (hwtnl->cmd.vbufs[i].buffer.resource == buffer) {
176af69d88dSmrg         return TRUE;
177af69d88dSmrg      }
178af69d88dSmrg   }
179af69d88dSmrg
180af69d88dSmrg   for (i = 0; i < hwtnl->cmd.prim_count; ++i) {
181af69d88dSmrg      if (hwtnl->cmd.prim_ib[i] == buffer) {
182af69d88dSmrg         return TRUE;
183af69d88dSmrg      }
184af69d88dSmrg   }
185af69d88dSmrg
186af69d88dSmrg   return FALSE;
187af69d88dSmrg}
188af69d88dSmrg
1894a49301eSmrg
19001e04c3fSmrgstatic enum pipe_error
19101e04c3fSmrgdraw_vgpu9(struct svga_hwtnl *hwtnl)
1924a49301eSmrg{
1934a49301eSmrg   struct svga_winsys_context *swc = hwtnl->cmd.swc;
1944a49301eSmrg   struct svga_context *svga = hwtnl->svga;
1954a49301eSmrg   enum pipe_error ret;
19601e04c3fSmrg   struct svga_winsys_surface *vb_handle[SVGA3D_INPUTREG_MAX];
19701e04c3fSmrg   struct svga_winsys_surface *ib_handle[QSZ];
19801e04c3fSmrg   struct svga_winsys_surface *handle;
19901e04c3fSmrg   SVGA3dVertexDecl *vdecl;
20001e04c3fSmrg   SVGA3dPrimitiveRange *prim;
20101e04c3fSmrg   unsigned i;
2024a49301eSmrg
20301e04c3fSmrg   /* Re-validate those sampler views with backing copy
20401e04c3fSmrg    * of texture whose original copy has been updated.
20501e04c3fSmrg    * This is done here at draw time because the texture binding might not
20601e04c3fSmrg    * have modified, hence validation is not triggered at state update time,
20701e04c3fSmrg    * and yet the texture might have been updated in another context, so
20801e04c3fSmrg    * we need to re-validate the sampler view in order to update the backing
20901e04c3fSmrg    * copy of the updated texture.
21001e04c3fSmrg    */
21101e04c3fSmrg   if (svga->state.hw_draw.num_backed_views) {
21201e04c3fSmrg      for (i = 0; i < svga->state.hw_draw.num_views; i++) {
21301e04c3fSmrg         struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];
21401e04c3fSmrg         struct svga_texture *tex = svga_texture(view->texture);
21501e04c3fSmrg         struct svga_sampler_view *sv = view->v;
21601e04c3fSmrg         if (sv && tex && sv->handle != tex->handle && sv->age < tex->age)
21701e04c3fSmrg            svga_validate_sampler_view(svga, view->v);
21801e04c3fSmrg      }
21901e04c3fSmrg   }
22001e04c3fSmrg
22101e04c3fSmrg   for (i = 0; i < hwtnl->cmd.vdecl_count; i++) {
22201e04c3fSmrg      unsigned j = hwtnl->cmd.vdecl_buffer_index[i];
22301e04c3fSmrg      handle = svga_buffer_handle(svga, hwtnl->cmd.vbufs[j].buffer.resource,
22401e04c3fSmrg                                  PIPE_BIND_VERTEX_BUFFER);
22501e04c3fSmrg      if (!handle)
22601e04c3fSmrg         return PIPE_ERROR_OUT_OF_MEMORY;
2274a49301eSmrg
22801e04c3fSmrg      vb_handle[i] = handle;
22901e04c3fSmrg   }
23001e04c3fSmrg
23101e04c3fSmrg   for (i = 0; i < hwtnl->cmd.prim_count; i++) {
23201e04c3fSmrg      if (hwtnl->cmd.prim_ib[i]) {
23301e04c3fSmrg         handle = svga_buffer_handle(svga, hwtnl->cmd.prim_ib[i],
23401e04c3fSmrg                                     PIPE_BIND_INDEX_BUFFER);
23501e04c3fSmrg         if (!handle)
2364a49301eSmrg            return PIPE_ERROR_OUT_OF_MEMORY;
23701e04c3fSmrg      }
23801e04c3fSmrg      else
23901e04c3fSmrg         handle = NULL;
2404a49301eSmrg
24101e04c3fSmrg      ib_handle[i] = handle;
24201e04c3fSmrg   }
24301e04c3fSmrg
24401e04c3fSmrg   if (svga->rebind.flags.rendertargets) {
24501e04c3fSmrg      ret = svga_reemit_framebuffer_bindings(svga);
24601e04c3fSmrg      if (ret != PIPE_OK) {
24701e04c3fSmrg         return ret;
24801e04c3fSmrg      }
24901e04c3fSmrg   }
25001e04c3fSmrg
25101e04c3fSmrg   if (svga->rebind.flags.texture_samplers) {
25201e04c3fSmrg      ret = svga_reemit_tss_bindings(svga);
25301e04c3fSmrg      if (ret != PIPE_OK) {
25401e04c3fSmrg         return ret;
25501e04c3fSmrg      }
25601e04c3fSmrg   }
25701e04c3fSmrg
25801e04c3fSmrg   if (svga->rebind.flags.vs) {
25901e04c3fSmrg      ret = svga_reemit_vs_bindings(svga);
26001e04c3fSmrg      if (ret != PIPE_OK) {
26101e04c3fSmrg         return ret;
26201e04c3fSmrg      }
26301e04c3fSmrg   }
26401e04c3fSmrg
26501e04c3fSmrg   if (svga->rebind.flags.fs) {
26601e04c3fSmrg      ret = svga_reemit_fs_bindings(svga);
26701e04c3fSmrg      if (ret != PIPE_OK) {
26801e04c3fSmrg         return ret;
2694a49301eSmrg      }
27001e04c3fSmrg   }
27101e04c3fSmrg
27201e04c3fSmrg   SVGA_DBG(DEBUG_DMA, "draw to sid %p, %d prims\n",
27301e04c3fSmrg            svga->curr.framebuffer.cbufs[0] ?
27401e04c3fSmrg            svga_surface(svga->curr.framebuffer.cbufs[0])->handle : NULL,
27501e04c3fSmrg            hwtnl->cmd.prim_count);
27601e04c3fSmrg
27701e04c3fSmrg   ret = SVGA3D_BeginDrawPrimitives(swc,
27801e04c3fSmrg                                    &vdecl,
27901e04c3fSmrg                                    hwtnl->cmd.vdecl_count,
28001e04c3fSmrg                                    &prim, hwtnl->cmd.prim_count);
28101e04c3fSmrg   if (ret != PIPE_OK)
28201e04c3fSmrg      return ret;
28301e04c3fSmrg
28401e04c3fSmrg   memcpy(vdecl,
28501e04c3fSmrg          hwtnl->cmd.vdecl,
28601e04c3fSmrg          hwtnl->cmd.vdecl_count * sizeof hwtnl->cmd.vdecl[0]);
28701e04c3fSmrg
28801e04c3fSmrg   for (i = 0; i < hwtnl->cmd.vdecl_count; i++) {
28901e04c3fSmrg      /* check for 4-byte alignment */
29001e04c3fSmrg      assert(vdecl[i].array.offset % 4 == 0);
29101e04c3fSmrg      assert(vdecl[i].array.stride % 4 == 0);
29201e04c3fSmrg
29301e04c3fSmrg      /* Given rangeHint is considered to be relative to indexBias, and
29401e04c3fSmrg       * indexBias varies per primitive, we cannot accurately supply an
29501e04c3fSmrg       * rangeHint when emitting more than one primitive per draw command.
29601e04c3fSmrg       */
29701e04c3fSmrg      if (hwtnl->cmd.prim_count == 1) {
29801e04c3fSmrg         vdecl[i].rangeHint.first = hwtnl->cmd.min_index[0];
29901e04c3fSmrg         vdecl[i].rangeHint.last = hwtnl->cmd.max_index[0] + 1;
30001e04c3fSmrg      }
30101e04c3fSmrg      else {
30201e04c3fSmrg         vdecl[i].rangeHint.first = 0;
30301e04c3fSmrg         vdecl[i].rangeHint.last = 0;
30401e04c3fSmrg      }
30501e04c3fSmrg
30601e04c3fSmrg      swc->surface_relocation(swc,
30701e04c3fSmrg                              &vdecl[i].array.surfaceId,
30801e04c3fSmrg                              NULL, vb_handle[i], SVGA_RELOC_READ);
30901e04c3fSmrg   }
31001e04c3fSmrg
31101e04c3fSmrg   memcpy(prim,
31201e04c3fSmrg          hwtnl->cmd.prim, hwtnl->cmd.prim_count * sizeof hwtnl->cmd.prim[0]);
31301e04c3fSmrg
31401e04c3fSmrg   for (i = 0; i < hwtnl->cmd.prim_count; i++) {
31501e04c3fSmrg      swc->surface_relocation(swc,
31601e04c3fSmrg                              &prim[i].indexArray.surfaceId,
31701e04c3fSmrg                              NULL, ib_handle[i], SVGA_RELOC_READ);
31801e04c3fSmrg      pipe_resource_reference(&hwtnl->cmd.prim_ib[i], NULL);
31901e04c3fSmrg   }
32001e04c3fSmrg
32101e04c3fSmrg   SVGA_FIFOCommitAll(swc);
32201e04c3fSmrg
32301e04c3fSmrg   hwtnl->cmd.prim_count = 0;
3244a49301eSmrg
32501e04c3fSmrg   return PIPE_OK;
32601e04c3fSmrg}
32701e04c3fSmrg
32801e04c3fSmrg
32901e04c3fSmrgstatic SVGA3dSurfaceFormat
33001e04c3fSmrgxlate_index_format(unsigned indexWidth)
33101e04c3fSmrg{
33201e04c3fSmrg   if (indexWidth == 2) {
33301e04c3fSmrg      return SVGA3D_R16_UINT;
33401e04c3fSmrg   }
33501e04c3fSmrg   else if (indexWidth == 4) {
33601e04c3fSmrg      return SVGA3D_R32_UINT;
33701e04c3fSmrg   }
33801e04c3fSmrg   else {
33901e04c3fSmrg      assert(!"Bad indexWidth");
34001e04c3fSmrg      return SVGA3D_R32_UINT;
34101e04c3fSmrg   }
34201e04c3fSmrg}
34301e04c3fSmrg
34401e04c3fSmrg
34501e04c3fSmrgstatic enum pipe_error
34601e04c3fSmrgvalidate_sampler_resources(struct svga_context *svga)
34701e04c3fSmrg{
34801e04c3fSmrg   enum pipe_shader_type shader;
34901e04c3fSmrg
35001e04c3fSmrg   assert(svga_have_vgpu10(svga));
35101e04c3fSmrg
3527ec681f3Smrg   for (shader = PIPE_SHADER_VERTEX; shader <= PIPE_SHADER_COMPUTE; shader++) {
35301e04c3fSmrg      unsigned count = svga->curr.num_sampler_views[shader];
35401e04c3fSmrg      unsigned i;
35501e04c3fSmrg      struct svga_winsys_surface *surfaces[PIPE_MAX_SAMPLERS];
35601e04c3fSmrg      enum pipe_error ret;
35701e04c3fSmrg
35801e04c3fSmrg      /*
35901e04c3fSmrg       * Reference bound sampler resources to ensure pending updates are
36001e04c3fSmrg       * noticed by the device.
36101e04c3fSmrg       */
36201e04c3fSmrg      for (i = 0; i < count; i++) {
36301e04c3fSmrg         struct svga_pipe_sampler_view *sv =
36401e04c3fSmrg            svga_pipe_sampler_view(svga->curr.sampler_views[shader][i]);
36501e04c3fSmrg
36601e04c3fSmrg         if (sv) {
36701e04c3fSmrg            if (sv->base.texture->target == PIPE_BUFFER) {
36801e04c3fSmrg               surfaces[i] = svga_buffer_handle(svga, sv->base.texture,
36901e04c3fSmrg                                                PIPE_BIND_SAMPLER_VIEW);
37001e04c3fSmrg            }
37101e04c3fSmrg            else {
37201e04c3fSmrg               surfaces[i] = svga_texture(sv->base.texture)->handle;
37301e04c3fSmrg            }
3744a49301eSmrg         }
375af69d88dSmrg         else {
37601e04c3fSmrg            surfaces[i] = NULL;
377af69d88dSmrg         }
37801e04c3fSmrg      }
37901e04c3fSmrg
38001e04c3fSmrg      if (shader == PIPE_SHADER_FRAGMENT &&
38101e04c3fSmrg          svga->curr.rast->templ.poly_stipple_enable) {
3827ec681f3Smrg         const unsigned unit =
3837ec681f3Smrg            svga_fs_variant(svga->state.hw_draw.fs)->pstipple_sampler_unit;
38401e04c3fSmrg         struct svga_pipe_sampler_view *sv =
38501e04c3fSmrg            svga->polygon_stipple.sampler_view;
3864a49301eSmrg
38701e04c3fSmrg         assert(sv);
38801e04c3fSmrg         surfaces[unit] = svga_texture(sv->base.texture)->handle;
38901e04c3fSmrg         count = MAX2(count, unit+1);
3904a49301eSmrg      }
3914a49301eSmrg
39201e04c3fSmrg      /* rebind the shader resources if needed */
39301e04c3fSmrg      if (svga->rebind.flags.texture_samplers) {
39401e04c3fSmrg         for (i = 0; i < count; i++) {
39501e04c3fSmrg            if (surfaces[i]) {
39601e04c3fSmrg               ret = svga->swc->resource_rebind(svga->swc,
39701e04c3fSmrg                                                surfaces[i],
39801e04c3fSmrg                                                NULL,
39901e04c3fSmrg                                                SVGA_RELOC_READ);
40001e04c3fSmrg               if (ret != PIPE_OK)
40101e04c3fSmrg                  return ret;
40201e04c3fSmrg            }
4033464ebd5Sriastradh         }
4043464ebd5Sriastradh      }
40501e04c3fSmrg   }
40601e04c3fSmrg   svga->rebind.flags.texture_samplers = FALSE;
4073464ebd5Sriastradh
40801e04c3fSmrg   return PIPE_OK;
40901e04c3fSmrg}
41001e04c3fSmrg
41101e04c3fSmrg
41201e04c3fSmrgstatic enum pipe_error
41301e04c3fSmrgvalidate_constant_buffers(struct svga_context *svga)
41401e04c3fSmrg{
41501e04c3fSmrg   enum pipe_shader_type shader;
41601e04c3fSmrg
41701e04c3fSmrg   assert(svga_have_vgpu10(svga));
41801e04c3fSmrg
4197ec681f3Smrg   for (shader = PIPE_SHADER_VERTEX; shader <= PIPE_SHADER_COMPUTE; shader++) {
42001e04c3fSmrg      enum pipe_error ret;
42101e04c3fSmrg      struct svga_buffer *buffer;
42201e04c3fSmrg
42301e04c3fSmrg      /* Rebind the default constant buffer if needed */
42401e04c3fSmrg      if (svga->rebind.flags.constbufs) {
4257ec681f3Smrg         buffer = svga_buffer(svga->state.hw_draw.constbuf[shader][0]);
42601e04c3fSmrg         if (buffer) {
42701e04c3fSmrg            ret = svga->swc->resource_rebind(svga->swc,
42801e04c3fSmrg                                             buffer->handle,
42901e04c3fSmrg                                             NULL,
43001e04c3fSmrg                                             SVGA_RELOC_READ);
43101e04c3fSmrg            if (ret != PIPE_OK)
43201e04c3fSmrg               return ret;
4333464ebd5Sriastradh         }
4343464ebd5Sriastradh      }
4353464ebd5Sriastradh
4367ec681f3Smrg      struct svga_winsys_surface *handle;
4377ec681f3Smrg      unsigned enabled_constbufs;
4387ec681f3Smrg
43901e04c3fSmrg      /*
44001e04c3fSmrg       * Reference other bound constant buffers to ensure pending updates are
44101e04c3fSmrg       * noticed by the device.
44201e04c3fSmrg       */
44301e04c3fSmrg      enabled_constbufs = svga->state.hw_draw.enabled_constbufs[shader] & ~1u;
44401e04c3fSmrg      while (enabled_constbufs) {
44501e04c3fSmrg         unsigned i = u_bit_scan(&enabled_constbufs);
44601e04c3fSmrg         buffer = svga_buffer(svga->curr.constbufs[shader][i].buffer);
4477ec681f3Smrg
4487ec681f3Smrg         /* If the constant buffer has hw storage, get the buffer winsys handle.
4497ec681f3Smrg          * Rebind the resource if needed.
4507ec681f3Smrg          */
4517ec681f3Smrg         if (buffer && !buffer->use_swbuf)
4527ec681f3Smrg            handle = svga_buffer_handle(svga, &buffer->b,
45301e04c3fSmrg                                        PIPE_BIND_CONSTANT_BUFFER);
4547ec681f3Smrg         else
4557ec681f3Smrg            handle = svga->state.hw_draw.constbufoffsets[shader][i].handle;
45601e04c3fSmrg
4577ec681f3Smrg         if (svga->rebind.flags.constbufs && handle) {
4587ec681f3Smrg            ret = svga->swc->resource_rebind(svga->swc,
4597ec681f3Smrg                                             handle,
4607ec681f3Smrg                                             NULL,
4617ec681f3Smrg                                             SVGA_RELOC_READ);
4627ec681f3Smrg            if (ret != PIPE_OK)
4637ec681f3Smrg               return ret;
464af69d88dSmrg         }
465af69d88dSmrg      }
46601e04c3fSmrg   }
46701e04c3fSmrg   svga->rebind.flags.constbufs = FALSE;
468af69d88dSmrg
46901e04c3fSmrg   return PIPE_OK;
47001e04c3fSmrg}
47101e04c3fSmrg
47201e04c3fSmrg
47301e04c3fSmrg/**
47401e04c3fSmrg * Was the last command put into the command buffer a drawing command?
47501e04c3fSmrg * We use this to determine if we can skip emitting buffer re-bind
47601e04c3fSmrg * commands when we have a sequence of drawing commands that use the
47701e04c3fSmrg * same vertex/index buffers with no intervening commands.
47801e04c3fSmrg *
47901e04c3fSmrg * The first drawing command will bind the vertex/index buffers.  If
48001e04c3fSmrg * the immediately following command is also a drawing command using the
48101e04c3fSmrg * same buffers, we shouldn't have to rebind them.
48201e04c3fSmrg */
48301e04c3fSmrgstatic bool
48401e04c3fSmrglast_command_was_draw(const struct svga_context *svga)
48501e04c3fSmrg{
48601e04c3fSmrg   switch (SVGA3D_GetLastCommand(svga->swc)) {
48701e04c3fSmrg   case SVGA_3D_CMD_DX_DRAW:
48801e04c3fSmrg   case SVGA_3D_CMD_DX_DRAW_INDEXED:
48901e04c3fSmrg   case SVGA_3D_CMD_DX_DRAW_INSTANCED:
49001e04c3fSmrg   case SVGA_3D_CMD_DX_DRAW_INDEXED_INSTANCED:
49101e04c3fSmrg   case SVGA_3D_CMD_DX_DRAW_AUTO:
4927ec681f3Smrg   case SVGA_3D_CMD_DX_DRAW_INDEXED_INSTANCED_INDIRECT:
4937ec681f3Smrg   case SVGA_3D_CMD_DX_DRAW_INSTANCED_INDIRECT:
49401e04c3fSmrg      return true;
49501e04c3fSmrg   default:
49601e04c3fSmrg      return false;
49701e04c3fSmrg   }
49801e04c3fSmrg}
49901e04c3fSmrg
50001e04c3fSmrg
50101e04c3fSmrg/**
50201e04c3fSmrg * A helper function to compare vertex buffers.
50301e04c3fSmrg * They are equal if the vertex buffer attributes and the vertex buffer
50401e04c3fSmrg * resources are identical.
50501e04c3fSmrg */
50601e04c3fSmrgstatic boolean
50701e04c3fSmrgvertex_buffers_equal(unsigned count,
50801e04c3fSmrg                     SVGA3dVertexBuffer *pVBufAttr1,
50901e04c3fSmrg                     struct pipe_resource **pVBuf1,
51001e04c3fSmrg                     SVGA3dVertexBuffer *pVBufAttr2,
51101e04c3fSmrg                     struct pipe_resource **pVBuf2)
51201e04c3fSmrg{
51301e04c3fSmrg   return (memcmp(pVBufAttr1, pVBufAttr2,
51401e04c3fSmrg                  count * sizeof(*pVBufAttr1)) == 0) &&
51501e04c3fSmrg          (memcmp(pVBuf1, pVBuf2, count * sizeof(*pVBuf1)) == 0);
51601e04c3fSmrg}
51701e04c3fSmrg
51801e04c3fSmrg
5199f464c52Smaya/*
5209f464c52Smaya * Prepare the vertex buffers for a drawing command.
5219f464c52Smaya */
52201e04c3fSmrgstatic enum pipe_error
5237ec681f3Smrgvalidate_vertex_buffers(struct svga_hwtnl *hwtnl,
5247ec681f3Smrg                   const struct pipe_stream_output_target *so_vertex_count)
52501e04c3fSmrg{
52601e04c3fSmrg   struct svga_context *svga = hwtnl->svga;
52701e04c3fSmrg   struct pipe_resource *vbuffers[SVGA3D_INPUTREG_MAX];
52801e04c3fSmrg   struct svga_winsys_surface *vbuffer_handles[SVGA3D_INPUTREG_MAX];
5297ec681f3Smrg   struct svga_winsys_surface *so_vertex_count_handle;
5307ec681f3Smrg   const unsigned vbuf_count = so_vertex_count ? 1 : hwtnl->cmd.vbuf_count;
53101e04c3fSmrg   int last_vbuf = -1;
53201e04c3fSmrg   unsigned i;
53301e04c3fSmrg
53401e04c3fSmrg   assert(svga_have_vgpu10(svga));
53501e04c3fSmrg
5367ec681f3Smrg   /* Get handle for each referenced vertex buffer, unless we're using a
5377ec681f3Smrg    * stream-out buffer to specify the drawing information (DrawAuto).
5387ec681f3Smrg    */
5397ec681f3Smrg   if (so_vertex_count) {
5407ec681f3Smrg      i = 0;
5417ec681f3Smrg   }
5427ec681f3Smrg   else {
5437ec681f3Smrg      for (i = 0; i < vbuf_count; i++) {
5447ec681f3Smrg         struct svga_buffer *sbuf =
5457ec681f3Smrg            svga_buffer(hwtnl->cmd.vbufs[i].buffer.resource);
5467ec681f3Smrg
5477ec681f3Smrg         if (sbuf) {
5487ec681f3Smrg            vbuffer_handles[i] = svga_buffer_handle(svga, &sbuf->b,
5497ec681f3Smrg                                                    PIPE_BIND_VERTEX_BUFFER);
5507ec681f3Smrg            assert(sbuf->key.flags & SVGA3D_SURFACE_BIND_VERTEX_BUFFER);
5517ec681f3Smrg            if (vbuffer_handles[i] == NULL)
5527ec681f3Smrg               return PIPE_ERROR_OUT_OF_MEMORY;
5537ec681f3Smrg            vbuffers[i] = &sbuf->b;
5547ec681f3Smrg            last_vbuf = i;
5557ec681f3Smrg         }
5567ec681f3Smrg         else {
5577ec681f3Smrg            vbuffers[i] = NULL;
5587ec681f3Smrg            vbuffer_handles[i] = NULL;
5597ec681f3Smrg         }
5607ec681f3Smrg      }
5617ec681f3Smrg   }
5627ec681f3Smrg
5637ec681f3Smrg   for (; i < svga->state.hw_draw.num_vbuffers; i++) {
5647ec681f3Smrg      vbuffers[i] = NULL;
5657ec681f3Smrg      vbuffer_handles[i] = NULL;
5667ec681f3Smrg   }
5677ec681f3Smrg
56801e04c3fSmrg   /* Get handle for each referenced vertex buffer */
56901e04c3fSmrg   for (i = 0; i < vbuf_count; i++) {
5709f464c52Smaya      struct svga_buffer *sbuf =
5719f464c52Smaya         svga_buffer(hwtnl->cmd.vbufs[i].buffer.resource);
57201e04c3fSmrg
57301e04c3fSmrg      if (sbuf) {
5747ec681f3Smrg         vbuffer_handles[i] = svga_buffer_handle(svga, &sbuf->b,
57501e04c3fSmrg                                                 PIPE_BIND_VERTEX_BUFFER);
57601e04c3fSmrg         assert(sbuf->key.flags & SVGA3D_SURFACE_BIND_VERTEX_BUFFER);
57701e04c3fSmrg         if (vbuffer_handles[i] == NULL)
57801e04c3fSmrg            return PIPE_ERROR_OUT_OF_MEMORY;
5797ec681f3Smrg         vbuffers[i] = &sbuf->b;
58001e04c3fSmrg         last_vbuf = i;
58101e04c3fSmrg      }
58201e04c3fSmrg      else {
58301e04c3fSmrg         vbuffers[i] = NULL;
58401e04c3fSmrg         vbuffer_handles[i] = NULL;
585af69d88dSmrg      }
58601e04c3fSmrg   }
587af69d88dSmrg
58801e04c3fSmrg   for (; i < svga->state.hw_draw.num_vbuffers; i++) {
58901e04c3fSmrg      vbuffers[i] = NULL;
59001e04c3fSmrg      vbuffer_handles[i] = NULL;
59101e04c3fSmrg   }
59201e04c3fSmrg
59301e04c3fSmrg   /* setup vertex attribute input layout */
59401e04c3fSmrg   if (svga->state.hw_draw.layout_id != hwtnl->cmd.vdecl_layout_id) {
5959f464c52Smaya      enum pipe_error ret =
5969f464c52Smaya         SVGA3D_vgpu10_SetInputLayout(svga->swc,
5979f464c52Smaya                                      hwtnl->cmd.vdecl_layout_id);
598af69d88dSmrg      if (ret != PIPE_OK)
5994a49301eSmrg         return ret;
6004a49301eSmrg
60101e04c3fSmrg      svga->state.hw_draw.layout_id = hwtnl->cmd.vdecl_layout_id;
60201e04c3fSmrg   }
60301e04c3fSmrg
6047ec681f3Smrg   /* Get handle for the stream out buffer */
6057ec681f3Smrg   if (so_vertex_count) {
6067ec681f3Smrg      so_vertex_count_handle = svga_buffer_handle(svga,
6077ec681f3Smrg                                                  so_vertex_count->buffer,
6087ec681f3Smrg                                                  (PIPE_BIND_VERTEX_BUFFER |
6097ec681f3Smrg                                                   PIPE_BIND_STREAM_OUTPUT));
6107ec681f3Smrg      if (!so_vertex_count_handle)
6117ec681f3Smrg         return PIPE_ERROR_OUT_OF_MEMORY;
6127ec681f3Smrg   }
6137ec681f3Smrg   else {
6147ec681f3Smrg      so_vertex_count_handle = NULL;
6157ec681f3Smrg   }
6167ec681f3Smrg
61701e04c3fSmrg   /* setup vertex buffers */
61801e04c3fSmrg   {
61901e04c3fSmrg      SVGA3dVertexBuffer vbuffer_attrs[PIPE_MAX_ATTRIBS];
6204a49301eSmrg
6217ec681f3Smrg      if (so_vertex_count) {
6227ec681f3Smrg         /* Set IA slot0 input buffer to the SO buffer */
6237ec681f3Smrg         assert(vbuf_count == 1);
6247ec681f3Smrg         vbuffer_attrs[0].stride = hwtnl->cmd.vbufs[0].stride;
6257ec681f3Smrg         vbuffer_attrs[0].offset = hwtnl->cmd.vbufs[0].buffer_offset;
6267ec681f3Smrg         vbuffer_attrs[0].sid = 0;
6277ec681f3Smrg         vbuffers[0] = so_vertex_count->buffer;
6287ec681f3Smrg         vbuffer_handles[0] = so_vertex_count_handle;
6297ec681f3Smrg      }
6307ec681f3Smrg      else {
6317ec681f3Smrg         for (i = 0; i < vbuf_count; i++) {
6327ec681f3Smrg            vbuffer_attrs[i].stride = hwtnl->cmd.vbufs[i].stride;
6337ec681f3Smrg            vbuffer_attrs[i].offset = hwtnl->cmd.vbufs[i].buffer_offset;
6347ec681f3Smrg            vbuffer_attrs[i].sid = 0;
6357ec681f3Smrg         }
63601e04c3fSmrg      }
63701e04c3fSmrg
6389f464c52Smaya      /* If any of the vertex buffer state has changed, issue
6399f464c52Smaya       * the SetVertexBuffers command. Otherwise, we will just
6409f464c52Smaya       * need to rebind the resources.
64101e04c3fSmrg       */
6429f464c52Smaya      if (vbuf_count != svga->state.hw_draw.num_vbuffers ||
64301e04c3fSmrg          !vertex_buffers_equal(vbuf_count,
64401e04c3fSmrg                                vbuffer_attrs,
64501e04c3fSmrg                                vbuffers,
64601e04c3fSmrg                                svga->state.hw_draw.vbuffer_attrs,
64701e04c3fSmrg                                svga->state.hw_draw.vbuffers)) {
64801e04c3fSmrg
64901e04c3fSmrg         unsigned num_vbuffers;
65001e04c3fSmrg
65101e04c3fSmrg         /* get the max of the current bound vertex buffers count and
65201e04c3fSmrg          * the to-be-bound vertex buffers count, so as to unbind
65301e04c3fSmrg          * the unused vertex buffers.
6544a49301eSmrg          */
65501e04c3fSmrg         num_vbuffers = MAX2(vbuf_count, svga->state.hw_draw.num_vbuffers);
65601e04c3fSmrg
65701e04c3fSmrg         /* Zero-out the old buffers we want to unbind (the number of loop
65801e04c3fSmrg          * iterations here is typically very small, and often zero.)
65901e04c3fSmrg          */
66001e04c3fSmrg         for (i = vbuf_count; i < num_vbuffers; i++) {
66101e04c3fSmrg            vbuffer_attrs[i].sid = 0;
66201e04c3fSmrg            vbuffer_attrs[i].stride = 0;
66301e04c3fSmrg            vbuffer_attrs[i].offset = 0;
66401e04c3fSmrg            vbuffer_handles[i] = NULL;
6654a49301eSmrg         }
6664a49301eSmrg
66701e04c3fSmrg         if (num_vbuffers > 0) {
66801e04c3fSmrg            SVGA3dVertexBuffer *pbufAttrs = vbuffer_attrs;
66901e04c3fSmrg            struct svga_winsys_surface **pbufHandles = vbuffer_handles;
67001e04c3fSmrg            unsigned numVBuf = 0;
67101e04c3fSmrg
67201e04c3fSmrg            /* Loop through the vertex buffer lists to only emit
67301e04c3fSmrg             * those vertex buffers that are not already in the
67401e04c3fSmrg             * corresponding entries in the device's vertex buffer list.
67501e04c3fSmrg             */
67601e04c3fSmrg            for (i = 0; i < num_vbuffers; i++) {
6779f464c52Smaya               boolean emit =
6789f464c52Smaya                  vertex_buffers_equal(1,
6799f464c52Smaya                                       &vbuffer_attrs[i],
6809f464c52Smaya                                       &vbuffers[i],
6819f464c52Smaya                                       &svga->state.hw_draw.vbuffer_attrs[i],
6829f464c52Smaya                                       &svga->state.hw_draw.vbuffers[i]);
6839f464c52Smaya
68401e04c3fSmrg               if (!emit && i == num_vbuffers-1) {
68501e04c3fSmrg                  /* Include the last vertex buffer in the next emit
68601e04c3fSmrg                   * if it is different.
68701e04c3fSmrg                   */
68801e04c3fSmrg                  emit = TRUE;
68901e04c3fSmrg                  numVBuf++;
69001e04c3fSmrg                  i++;
69101e04c3fSmrg               }
69201e04c3fSmrg
69301e04c3fSmrg               if (emit) {
69401e04c3fSmrg                  /* numVBuf can only be 0 if the first vertex buffer
69501e04c3fSmrg                   * is the same as the one in the device's list.
69601e04c3fSmrg                   * In this case, there is nothing to send yet.
69701e04c3fSmrg                   */
69801e04c3fSmrg                  if (numVBuf) {
6999f464c52Smaya                     enum pipe_error ret =
7009f464c52Smaya                        SVGA3D_vgpu10_SetVertexBuffers(svga->swc,
7019f464c52Smaya                                                       numVBuf,
7029f464c52Smaya                                                       i - numVBuf,
7039f464c52Smaya                                                       pbufAttrs, pbufHandles);
70401e04c3fSmrg                     if (ret != PIPE_OK)
70501e04c3fSmrg                        return ret;
70601e04c3fSmrg                  }
70701e04c3fSmrg                  pbufAttrs += (numVBuf + 1);
70801e04c3fSmrg                  pbufHandles += (numVBuf + 1);
70901e04c3fSmrg                  numVBuf = 0;
71001e04c3fSmrg               }
71101e04c3fSmrg               else
71201e04c3fSmrg                  numVBuf++;
71301e04c3fSmrg            }
71401e04c3fSmrg
71501e04c3fSmrg            /* save the number of vertex buffers sent to the device, not
71601e04c3fSmrg             * including trailing unbound vertex buffers.
71701e04c3fSmrg             */
71801e04c3fSmrg            svga->state.hw_draw.num_vbuffers = last_vbuf + 1;
71901e04c3fSmrg            memcpy(svga->state.hw_draw.vbuffer_attrs, vbuffer_attrs,
72001e04c3fSmrg                   num_vbuffers * sizeof(vbuffer_attrs[0]));
72101e04c3fSmrg            for (i = 0; i < num_vbuffers; i++) {
72201e04c3fSmrg               pipe_resource_reference(&svga->state.hw_draw.vbuffers[i],
72301e04c3fSmrg                                       vbuffers[i]);
72401e04c3fSmrg            }
72501e04c3fSmrg         }
72601e04c3fSmrg      }
72701e04c3fSmrg      else {
72801e04c3fSmrg         /* Even though we can avoid emitting the redundant SetVertexBuffers
72901e04c3fSmrg          * command, we still need to reference the vertex buffers surfaces.
73001e04c3fSmrg          */
73101e04c3fSmrg         for (i = 0; i < vbuf_count; i++) {
73201e04c3fSmrg            if (vbuffer_handles[i] && !last_command_was_draw(svga)) {
7339f464c52Smaya               enum pipe_error ret =
7349f464c52Smaya                  svga->swc->resource_rebind(svga->swc, vbuffer_handles[i],
7359f464c52Smaya                                             NULL, SVGA_RELOC_READ);
73601e04c3fSmrg               if (ret != PIPE_OK)
73701e04c3fSmrg                  return ret;
73801e04c3fSmrg            }
73901e04c3fSmrg         }
7404a49301eSmrg      }
74101e04c3fSmrg   }
74201e04c3fSmrg
7439f464c52Smaya   return PIPE_OK;
7449f464c52Smaya}
7459f464c52Smaya
7469f464c52Smaya
7479f464c52Smaya/*
7489f464c52Smaya * Prepare the index buffer for a drawing command.
7499f464c52Smaya */
7509f464c52Smayastatic enum pipe_error
7519f464c52Smayavalidate_index_buffer(struct svga_hwtnl *hwtnl,
7529f464c52Smaya                      const SVGA3dPrimitiveRange *range,
7539f464c52Smaya                      struct pipe_resource *ib)
7549f464c52Smaya{
7559f464c52Smaya   struct svga_context *svga = hwtnl->svga;
7569f464c52Smaya   struct svga_winsys_surface *ib_handle =
7579f464c52Smaya      svga_buffer_handle(svga, ib, PIPE_BIND_INDEX_BUFFER);
7589f464c52Smaya
7599f464c52Smaya   if (!ib_handle)
7609f464c52Smaya      return PIPE_ERROR_OUT_OF_MEMORY;
7619f464c52Smaya
7629f464c52Smaya   struct svga_buffer *sbuf = svga_buffer(ib);
7639f464c52Smaya   assert(sbuf->key.flags & SVGA3D_SURFACE_BIND_INDEX_BUFFER);
7649f464c52Smaya   (void) sbuf; /* silence unused var warning */
7659f464c52Smaya
7669f464c52Smaya   SVGA3dSurfaceFormat indexFormat = xlate_index_format(range->indexWidth);
7679f464c52Smaya
7689f464c52Smaya   if (ib != svga->state.hw_draw.ib ||
7699f464c52Smaya       indexFormat != svga->state.hw_draw.ib_format ||
7709f464c52Smaya       range->indexArray.offset != svga->state.hw_draw.ib_offset) {
7719f464c52Smaya
7729f464c52Smaya      assert(indexFormat != SVGA3D_FORMAT_INVALID);
7739f464c52Smaya      enum pipe_error ret =
7749f464c52Smaya         SVGA3D_vgpu10_SetIndexBuffer(svga->swc, ib_handle,
7759f464c52Smaya                                      indexFormat,
7769f464c52Smaya                                      range->indexArray.offset);
7779f464c52Smaya      if (ret != PIPE_OK)
7789f464c52Smaya         return ret;
7799f464c52Smaya
7809f464c52Smaya      pipe_resource_reference(&svga->state.hw_draw.ib, ib);
7819f464c52Smaya      svga->state.hw_draw.ib_format = indexFormat;
7829f464c52Smaya      svga->state.hw_draw.ib_offset = range->indexArray.offset;
7839f464c52Smaya   }
7849f464c52Smaya   else {
7859f464c52Smaya      /* Even though we can avoid emitting the redundant SetIndexBuffer
7869f464c52Smaya       * command, we still need to reference the index buffer surface.
7879f464c52Smaya       */
7889f464c52Smaya      if (!last_command_was_draw(svga)) {
7899f464c52Smaya         enum pipe_error ret = svga->swc->resource_rebind(svga->swc,
7909f464c52Smaya                                                          ib_handle,
7919f464c52Smaya                                                          NULL,
7929f464c52Smaya                                                          SVGA_RELOC_READ);
7939f464c52Smaya         if (ret != PIPE_OK)
7949f464c52Smaya            return ret;
7959f464c52Smaya      }
7969f464c52Smaya   }
7979f464c52Smaya
7989f464c52Smaya   return PIPE_OK;
7999f464c52Smaya}
8009f464c52Smaya
8019f464c52Smaya
8029f464c52Smayastatic enum pipe_error
8039f464c52Smayadraw_vgpu10(struct svga_hwtnl *hwtnl,
8049f464c52Smaya            const SVGA3dPrimitiveRange *range,
8059f464c52Smaya            unsigned vcount,
8067ec681f3Smrg            unsigned min_index, unsigned max_index,
8079f464c52Smaya            struct pipe_resource *ib,
8087ec681f3Smrg            unsigned start_instance, unsigned instance_count,
8097ec681f3Smrg            const struct pipe_draw_indirect_info *indirect,
8107ec681f3Smrg            const struct pipe_stream_output_target *so_vertex_count)
8119f464c52Smaya{
8129f464c52Smaya   struct svga_context *svga = hwtnl->svga;
8137ec681f3Smrg   struct svga_winsys_surface *indirect_handle;
8149f464c52Smaya   enum pipe_error ret;
8159f464c52Smaya
8169f464c52Smaya   assert(svga_have_vgpu10(svga));
8179f464c52Smaya   assert(hwtnl->cmd.prim_count == 0);
8189f464c52Smaya
8199f464c52Smaya   /* We need to reemit all the current resource bindings along with the Draw
8209f464c52Smaya    * command to be sure that the referenced resources are available for the
8219f464c52Smaya    * Draw command, just in case the surfaces associated with the resources
8229f464c52Smaya    * are paged out.
8239f464c52Smaya    */
8249f464c52Smaya   if (svga->rebind.val) {
8259f464c52Smaya      ret = svga_rebind_framebuffer_bindings(svga);
8269f464c52Smaya      if (ret != PIPE_OK)
8279f464c52Smaya         return ret;
8289f464c52Smaya
8299f464c52Smaya      ret = svga_rebind_shaders(svga);
8309f464c52Smaya      if (ret != PIPE_OK)
8319f464c52Smaya         return ret;
8329f464c52Smaya
8339f464c52Smaya      /* Rebind stream output targets */
8349f464c52Smaya      ret = svga_rebind_stream_output_targets(svga);
8359f464c52Smaya      if (ret != PIPE_OK)
8369f464c52Smaya         return ret;
8379f464c52Smaya
8389f464c52Smaya      /* No need to explicitly rebind index buffer and vertex buffers here.
8399f464c52Smaya       * Even if the same index buffer or vertex buffers are referenced for this
8409f464c52Smaya       * draw and we skip emitting the redundant set command, we will still
8419f464c52Smaya       * reference the associated resources.
8429f464c52Smaya       */
8439f464c52Smaya   }
8449f464c52Smaya
8459f464c52Smaya   ret = validate_sampler_resources(svga);
8469f464c52Smaya   if (ret != PIPE_OK)
8479f464c52Smaya      return ret;
8489f464c52Smaya
8499f464c52Smaya   ret = validate_constant_buffers(svga);
8509f464c52Smaya   if (ret != PIPE_OK)
8519f464c52Smaya      return ret;
8529f464c52Smaya
8537ec681f3Smrg   ret = validate_vertex_buffers(hwtnl, so_vertex_count);
8549f464c52Smaya   if (ret != PIPE_OK)
8559f464c52Smaya      return ret;
8569f464c52Smaya
8579f464c52Smaya   if (ib) {
8589f464c52Smaya      ret = validate_index_buffer(hwtnl, range, ib);
8599f464c52Smaya      if (ret != PIPE_OK)
8609f464c52Smaya         return ret;
8619f464c52Smaya   }
8629f464c52Smaya
8637ec681f3Smrg   if (indirect) {
8647ec681f3Smrg      indirect_handle = svga_buffer_handle(svga, indirect->buffer,
8657ec681f3Smrg                                           PIPE_BIND_COMMAND_ARGS_BUFFER);
8667ec681f3Smrg      if (!indirect_handle)
8677ec681f3Smrg         return PIPE_ERROR_OUT_OF_MEMORY;
8687ec681f3Smrg   }
8697ec681f3Smrg   else {
8707ec681f3Smrg      indirect_handle = NULL;
8717ec681f3Smrg   }
8727ec681f3Smrg
87301e04c3fSmrg   /* Set primitive type (line, tri, etc) */
87401e04c3fSmrg   if (svga->state.hw_draw.topology != range->primType) {
87501e04c3fSmrg      ret = SVGA3D_vgpu10_SetTopology(svga->swc, range->primType);
87601e04c3fSmrg      if (ret != PIPE_OK)
87701e04c3fSmrg         return ret;
87801e04c3fSmrg
87901e04c3fSmrg      svga->state.hw_draw.topology = range->primType;
88001e04c3fSmrg   }
8814a49301eSmrg
8829f464c52Smaya   if (ib) {
88301e04c3fSmrg      /* indexed drawing */
8847ec681f3Smrg      if (indirect) {
8857ec681f3Smrg         ret = SVGA3D_sm5_DrawIndexedInstancedIndirect(svga->swc,
8867ec681f3Smrg                                                       indirect_handle,
8877ec681f3Smrg                                                       indirect->offset);
8887ec681f3Smrg      }
8897ec681f3Smrg      else if (instance_count > 1) {
89001e04c3fSmrg         ret = SVGA3D_vgpu10_DrawIndexedInstanced(svga->swc,
89101e04c3fSmrg                                                  vcount,
89201e04c3fSmrg                                                  instance_count,
89301e04c3fSmrg                                                  0, /* startIndexLocation */
89401e04c3fSmrg                                                  range->indexBias,
89501e04c3fSmrg                                                  start_instance);
89601e04c3fSmrg      }
89701e04c3fSmrg      else {
89801e04c3fSmrg         /* non-instanced drawing */
89901e04c3fSmrg         ret = SVGA3D_vgpu10_DrawIndexed(svga->swc,
90001e04c3fSmrg                                         vcount,
90101e04c3fSmrg                                         0,      /* startIndexLocation */
90201e04c3fSmrg                                         range->indexBias);
9037ec681f3Smrg      }
9047ec681f3Smrg      if (ret != PIPE_OK) {
9057ec681f3Smrg         return ret;
90601e04c3fSmrg      }
9074a49301eSmrg   }
90801e04c3fSmrg   else {
90901e04c3fSmrg      /* non-indexed drawing */
91001e04c3fSmrg      if (svga->state.hw_draw.ib_format != SVGA3D_FORMAT_INVALID ||
91101e04c3fSmrg          svga->state.hw_draw.ib != NULL) {
91201e04c3fSmrg         /* Unbind previously bound index buffer */
91301e04c3fSmrg         ret = SVGA3D_vgpu10_SetIndexBuffer(svga->swc, NULL,
91401e04c3fSmrg                                            SVGA3D_FORMAT_INVALID, 0);
91501e04c3fSmrg         if (ret != PIPE_OK)
91601e04c3fSmrg            return ret;
91701e04c3fSmrg         pipe_resource_reference(&svga->state.hw_draw.ib, NULL);
91801e04c3fSmrg         svga->state.hw_draw.ib_format = SVGA3D_FORMAT_INVALID;
91901e04c3fSmrg      }
92001e04c3fSmrg
92101e04c3fSmrg      assert(svga->state.hw_draw.ib == NULL);
92201e04c3fSmrg
9237ec681f3Smrg      if (so_vertex_count) {
9247ec681f3Smrg         /* Stream-output drawing */
9257ec681f3Smrg         ret = SVGA3D_vgpu10_DrawAuto(svga->swc);
9267ec681f3Smrg      }
9277ec681f3Smrg      else if (indirect) {
9287ec681f3Smrg         ret = SVGA3D_sm5_DrawInstancedIndirect(svga->swc,
9297ec681f3Smrg                                                indirect_handle,
9307ec681f3Smrg                                                indirect->offset);
9317ec681f3Smrg      }
9327ec681f3Smrg      else if (instance_count > 1) {
93301e04c3fSmrg         ret = SVGA3D_vgpu10_DrawInstanced(svga->swc,
93401e04c3fSmrg                                           vcount,
93501e04c3fSmrg                                           instance_count,
93601e04c3fSmrg                                           range->indexBias,
93701e04c3fSmrg                                           start_instance);
93801e04c3fSmrg      }
93901e04c3fSmrg      else {
94001e04c3fSmrg         /* non-instanced */
94101e04c3fSmrg         ret = SVGA3D_vgpu10_Draw(svga->swc,
94201e04c3fSmrg                                  vcount,
94301e04c3fSmrg                                  range->indexBias);
9447ec681f3Smrg      }
9457ec681f3Smrg      if (ret != PIPE_OK) {
9467ec681f3Smrg         return ret;
94701e04c3fSmrg      }
94801e04c3fSmrg   }
94901e04c3fSmrg
95001e04c3fSmrg   hwtnl->cmd.prim_count = 0;
9514a49301eSmrg
9524a49301eSmrg   return PIPE_OK;
9534a49301eSmrg}
9544a49301eSmrg
9554a49301eSmrg
95601e04c3fSmrg
95701e04c3fSmrg/**
95801e04c3fSmrg * Emit any pending drawing commands to the command buffer.
95901e04c3fSmrg * When we receive VGPU9 drawing commands we accumulate them and don't
96001e04c3fSmrg * immediately emit them into the command buffer.
96101e04c3fSmrg * This function needs to be called before we change state that could
96201e04c3fSmrg * effect those pending draws.
96301e04c3fSmrg */
96401e04c3fSmrgenum pipe_error
96501e04c3fSmrgsvga_hwtnl_flush(struct svga_hwtnl *hwtnl)
96601e04c3fSmrg{
96701e04c3fSmrg   enum pipe_error ret = PIPE_OK;
96801e04c3fSmrg
96901e04c3fSmrg   SVGA_STATS_TIME_PUSH(svga_sws(hwtnl->svga), SVGA_STATS_TIME_HWTNLFLUSH);
97001e04c3fSmrg
97101e04c3fSmrg   if (!svga_have_vgpu10(hwtnl->svga) && hwtnl->cmd.prim_count) {
97201e04c3fSmrg      /* we only queue up primitive for VGPU9 */
97301e04c3fSmrg      ret = draw_vgpu9(hwtnl);
97401e04c3fSmrg   }
97501e04c3fSmrg
97601e04c3fSmrg   SVGA_STATS_TIME_POP(svga_screen(hwtnl->svga->pipe.screen)->sws);
97701e04c3fSmrg   return ret;
97801e04c3fSmrg}
97901e04c3fSmrg
98001e04c3fSmrg
981af69d88dSmrgvoid
982af69d88dSmrgsvga_hwtnl_set_index_bias(struct svga_hwtnl *hwtnl, int index_bias)
983af69d88dSmrg{
984af69d88dSmrg   hwtnl->index_bias = index_bias;
985af69d88dSmrg}
9864a49301eSmrg
9874a49301eSmrg
9884a49301eSmrg
9894a49301eSmrg/***********************************************************************
9904a49301eSmrg * Internal functions:
9914a49301eSmrg */
9924a49301eSmrg
993af69d88dSmrg/**
994af69d88dSmrg * For debugging only.
995af69d88dSmrg */
996af69d88dSmrgstatic void
997af69d88dSmrgcheck_draw_params(struct svga_hwtnl *hwtnl,
998af69d88dSmrg                  const SVGA3dPrimitiveRange *range,
999af69d88dSmrg                  unsigned min_index, unsigned max_index,
1000af69d88dSmrg                  struct pipe_resource *ib)
10014a49301eSmrg{
1002af69d88dSmrg   unsigned i;
10034a49301eSmrg
100401e04c3fSmrg   assert(!svga_have_vgpu10(hwtnl->svga));
100501e04c3fSmrg
1006af69d88dSmrg   for (i = 0; i < hwtnl->cmd.vdecl_count; i++) {
100701e04c3fSmrg      unsigned j = hwtnl->cmd.vdecl_buffer_index[i];
100801e04c3fSmrg      const struct pipe_vertex_buffer *vb = &hwtnl->cmd.vbufs[j];
100901e04c3fSmrg      unsigned size = vb->buffer.resource ? vb->buffer.resource->width0 : 0;
1010af69d88dSmrg      unsigned offset = hwtnl->cmd.vdecl[i].array.offset;
1011af69d88dSmrg      unsigned stride = hwtnl->cmd.vdecl[i].array.stride;
1012af69d88dSmrg      int index_bias = (int) range->indexBias + hwtnl->index_bias;
1013af69d88dSmrg      unsigned width;
1014af69d88dSmrg
101501e04c3fSmrg      if (size == 0)
101601e04c3fSmrg         continue;
101701e04c3fSmrg
1018af69d88dSmrg      assert(vb);
1019af69d88dSmrg      assert(size);
1020af69d88dSmrg      assert(offset < size);
1021af69d88dSmrg      assert(min_index <= max_index);
102201e04c3fSmrg      (void) width;
102301e04c3fSmrg      (void) stride;
102401e04c3fSmrg      (void) offset;
102501e04c3fSmrg      (void) size;
1026af69d88dSmrg
1027af69d88dSmrg      switch (hwtnl->cmd.vdecl[i].identity.type) {
1028af69d88dSmrg      case SVGA3D_DECLTYPE_FLOAT1:
1029af69d88dSmrg         width = 4;
1030af69d88dSmrg         break;
1031af69d88dSmrg      case SVGA3D_DECLTYPE_FLOAT2:
1032af69d88dSmrg         width = 4 * 2;
1033af69d88dSmrg         break;
1034af69d88dSmrg      case SVGA3D_DECLTYPE_FLOAT3:
1035af69d88dSmrg         width = 4 * 3;
1036af69d88dSmrg         break;
1037af69d88dSmrg      case SVGA3D_DECLTYPE_FLOAT4:
1038af69d88dSmrg         width = 4 * 4;
1039af69d88dSmrg         break;
1040af69d88dSmrg      case SVGA3D_DECLTYPE_D3DCOLOR:
1041af69d88dSmrg         width = 4;
1042af69d88dSmrg         break;
1043af69d88dSmrg      case SVGA3D_DECLTYPE_UBYTE4:
1044af69d88dSmrg         width = 1 * 4;
1045af69d88dSmrg         break;
1046af69d88dSmrg      case SVGA3D_DECLTYPE_SHORT2:
1047af69d88dSmrg         width = 2 * 2;
1048af69d88dSmrg         break;
1049af69d88dSmrg      case SVGA3D_DECLTYPE_SHORT4:
1050af69d88dSmrg         width = 2 * 4;
1051af69d88dSmrg         break;
1052af69d88dSmrg      case SVGA3D_DECLTYPE_UBYTE4N:
1053af69d88dSmrg         width = 1 * 4;
1054af69d88dSmrg         break;
1055af69d88dSmrg      case SVGA3D_DECLTYPE_SHORT2N:
1056af69d88dSmrg         width = 2 * 2;
1057af69d88dSmrg         break;
1058af69d88dSmrg      case SVGA3D_DECLTYPE_SHORT4N:
1059af69d88dSmrg         width = 2 * 4;
1060af69d88dSmrg         break;
1061af69d88dSmrg      case SVGA3D_DECLTYPE_USHORT2N:
1062af69d88dSmrg         width = 2 * 2;
1063af69d88dSmrg         break;
1064af69d88dSmrg      case SVGA3D_DECLTYPE_USHORT4N:
1065af69d88dSmrg         width = 2 * 4;
1066af69d88dSmrg         break;
1067af69d88dSmrg      case SVGA3D_DECLTYPE_UDEC3:
1068af69d88dSmrg         width = 4;
1069af69d88dSmrg         break;
1070af69d88dSmrg      case SVGA3D_DECLTYPE_DEC3N:
1071af69d88dSmrg         width = 4;
1072af69d88dSmrg         break;
1073af69d88dSmrg      case SVGA3D_DECLTYPE_FLOAT16_2:
1074af69d88dSmrg         width = 2 * 2;
1075af69d88dSmrg         break;
1076af69d88dSmrg      case SVGA3D_DECLTYPE_FLOAT16_4:
1077af69d88dSmrg         width = 2 * 4;
1078af69d88dSmrg         break;
1079af69d88dSmrg      default:
1080af69d88dSmrg         assert(0);
1081af69d88dSmrg         width = 0;
1082af69d88dSmrg         break;
1083af69d88dSmrg      }
10844a49301eSmrg
1085af69d88dSmrg      if (index_bias >= 0) {
1086af69d88dSmrg         assert(offset + index_bias * stride + width <= size);
10874a49301eSmrg      }
10884a49301eSmrg
1089af69d88dSmrg      /*
1090af69d88dSmrg       * min_index/max_index are merely conservative guesses, so we can't
1091af69d88dSmrg       * make buffer overflow detection based on their values.
1092af69d88dSmrg       */
1093af69d88dSmrg   }
10944a49301eSmrg
1095af69d88dSmrg   assert(range->indexWidth == range->indexArray.stride);
1096af69d88dSmrg
1097af69d88dSmrg   if (ib) {
10987ec681f3Smrg      ASSERTED unsigned size = ib->width0;
10997ec681f3Smrg      ASSERTED unsigned offset = range->indexArray.offset;
11007ec681f3Smrg      ASSERTED unsigned stride = range->indexArray.stride;
11017ec681f3Smrg      ASSERTED unsigned count;
1102af69d88dSmrg
1103af69d88dSmrg      assert(size);
1104af69d88dSmrg      assert(offset < size);
1105af69d88dSmrg      assert(stride);
1106af69d88dSmrg
1107af69d88dSmrg      switch (range->primType) {
1108af69d88dSmrg      case SVGA3D_PRIMITIVE_POINTLIST:
1109af69d88dSmrg         count = range->primitiveCount;
1110af69d88dSmrg         break;
1111af69d88dSmrg      case SVGA3D_PRIMITIVE_LINELIST:
1112af69d88dSmrg         count = range->primitiveCount * 2;
1113af69d88dSmrg         break;
1114af69d88dSmrg      case SVGA3D_PRIMITIVE_LINESTRIP:
1115af69d88dSmrg         count = range->primitiveCount + 1;
1116af69d88dSmrg         break;
1117af69d88dSmrg      case SVGA3D_PRIMITIVE_TRIANGLELIST:
1118af69d88dSmrg         count = range->primitiveCount * 3;
1119af69d88dSmrg         break;
1120af69d88dSmrg      case SVGA3D_PRIMITIVE_TRIANGLESTRIP:
1121af69d88dSmrg         count = range->primitiveCount + 2;
1122af69d88dSmrg         break;
1123af69d88dSmrg      case SVGA3D_PRIMITIVE_TRIANGLEFAN:
1124af69d88dSmrg         count = range->primitiveCount + 2;
1125af69d88dSmrg         break;
1126af69d88dSmrg      default:
1127af69d88dSmrg         assert(0);
1128af69d88dSmrg         count = 0;
1129af69d88dSmrg         break;
11304a49301eSmrg      }
1131af69d88dSmrg
1132af69d88dSmrg      assert(offset + count * stride <= size);
11334a49301eSmrg   }
1134af69d88dSmrg}
1135af69d88dSmrg
1136af69d88dSmrg
113701e04c3fSmrg/**
113801e04c3fSmrg * All drawing filters down into this function, either directly
113901e04c3fSmrg * on the hardware path or after doing software vertex processing.
11407ec681f3Smrg * \param indirect  if non-null, get the vertex count, first vertex, etc.
11417ec681f3Smrg *                  from a buffer.
11427ec681f3Smrg * \param so_vertex_count  if non-null, get the vertex count from a
11437ec681f3Smrg *                         stream-output target.
114401e04c3fSmrg */
1145af69d88dSmrgenum pipe_error
1146af69d88dSmrgsvga_hwtnl_prim(struct svga_hwtnl *hwtnl,
11477ec681f3Smrg                const SVGA3dPrimitiveRange *range,
114801e04c3fSmrg                unsigned vcount,
11497ec681f3Smrg                unsigned min_index, unsigned max_index,
11507ec681f3Smrg                struct pipe_resource *ib,
11517ec681f3Smrg                unsigned start_instance, unsigned instance_count,
11527ec681f3Smrg                const struct pipe_draw_indirect_info *indirect,
11537ec681f3Smrg                const struct pipe_stream_output_target *so_vertex_count)
1154af69d88dSmrg{
1155af69d88dSmrg   enum pipe_error ret = PIPE_OK;
1156af69d88dSmrg
115701e04c3fSmrg   SVGA_STATS_TIME_PUSH(svga_sws(hwtnl->svga), SVGA_STATS_TIME_HWTNLPRIM);
115801e04c3fSmrg
115901e04c3fSmrg   if (svga_have_vgpu10(hwtnl->svga)) {
116001e04c3fSmrg      /* draw immediately */
11617ec681f3Smrg      SVGA_RETRY(hwtnl->svga, draw_vgpu10(hwtnl, range, vcount, min_index,
11627ec681f3Smrg                                          max_index, ib, start_instance,
11637ec681f3Smrg                                          instance_count, indirect,
11647ec681f3Smrg                                          so_vertex_count));
116501e04c3fSmrg   }
116601e04c3fSmrg   else {
116701e04c3fSmrg      /* batch up drawing commands */
11687ec681f3Smrg      assert(indirect == NULL);
1169af69d88dSmrg#ifdef DEBUG
117001e04c3fSmrg      check_draw_params(hwtnl, range, min_index, max_index, ib);
117101e04c3fSmrg      assert(start_instance == 0);
117201e04c3fSmrg      assert(instance_count <= 1);
117301e04c3fSmrg#else
117401e04c3fSmrg      (void) check_draw_params;
11754a49301eSmrg#endif
11764a49301eSmrg
117701e04c3fSmrg      if (hwtnl->cmd.prim_count + 1 >= QSZ) {
117801e04c3fSmrg         ret = svga_hwtnl_flush(hwtnl);
117901e04c3fSmrg         if (ret != PIPE_OK)
118001e04c3fSmrg            goto done;
118101e04c3fSmrg      }
1182af69d88dSmrg
118301e04c3fSmrg      /* min/max indices are relative to bias */
118401e04c3fSmrg      hwtnl->cmd.min_index[hwtnl->cmd.prim_count] = min_index;
118501e04c3fSmrg      hwtnl->cmd.max_index[hwtnl->cmd.prim_count] = max_index;
11864a49301eSmrg
118701e04c3fSmrg      hwtnl->cmd.prim[hwtnl->cmd.prim_count] = *range;
118801e04c3fSmrg      hwtnl->cmd.prim[hwtnl->cmd.prim_count].indexBias += hwtnl->index_bias;
11894a49301eSmrg
119001e04c3fSmrg      pipe_resource_reference(&hwtnl->cmd.prim_ib[hwtnl->cmd.prim_count], ib);
119101e04c3fSmrg      hwtnl->cmd.prim_count++;
119201e04c3fSmrg   }
11934a49301eSmrg
119401e04c3fSmrgdone:
119501e04c3fSmrg   SVGA_STATS_TIME_POP(svga_screen(hwtnl->svga->pipe.screen)->sws);
11964a49301eSmrg   return ret;
11974a49301eSmrg}
11987ec681f3Smrg
11997ec681f3Smrg
12007ec681f3Smrg/**
12017ec681f3Smrg * Return TRUE if there are pending primitives.
12027ec681f3Smrg */
12037ec681f3Smrgboolean
12047ec681f3Smrgsvga_hwtnl_has_pending_prim(struct svga_hwtnl *hwtnl)
12057ec681f3Smrg{
12067ec681f3Smrg   return hwtnl->cmd.prim_count > 0;
12077ec681f3Smrg}
1208