1bf215546Sopenharmony_ci/**********************************************************
2bf215546Sopenharmony_ci * Copyright 2008-2009 VMware, Inc.  All rights reserved.
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person
5bf215546Sopenharmony_ci * obtaining a copy of this software and associated documentation
6bf215546Sopenharmony_ci * files (the "Software"), to deal in the Software without
7bf215546Sopenharmony_ci * restriction, including without limitation the rights to use, copy,
8bf215546Sopenharmony_ci * modify, merge, publish, distribute, sublicense, and/or sell copies
9bf215546Sopenharmony_ci * of the Software, and to permit persons to whom the Software is
10bf215546Sopenharmony_ci * furnished to do so, subject to the following conditions:
11bf215546Sopenharmony_ci *
12bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be
13bf215546Sopenharmony_ci * included in all copies or substantial portions of the Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16bf215546Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18bf215546Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19bf215546Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20bf215546Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21bf215546Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22bf215546Sopenharmony_ci * SOFTWARE.
23bf215546Sopenharmony_ci *
24bf215546Sopenharmony_ci **********************************************************/
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci#include "svga_cmd.h"
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include "util/u_inlines.h"
29bf215546Sopenharmony_ci#include "util/u_prim.h"
30bf215546Sopenharmony_ci#include "indices/u_indices.h"
31bf215546Sopenharmony_ci
32bf215546Sopenharmony_ci#include "svga_hw_reg.h"
33bf215546Sopenharmony_ci#include "svga_draw.h"
34bf215546Sopenharmony_ci#include "svga_draw_private.h"
35bf215546Sopenharmony_ci#include "svga_context.h"
36bf215546Sopenharmony_ci#include "svga_shader.h"
37bf215546Sopenharmony_ci
38bf215546Sopenharmony_ci
39bf215546Sopenharmony_ci#define DBG 0
40bf215546Sopenharmony_ci
41bf215546Sopenharmony_ci
42bf215546Sopenharmony_cistatic enum pipe_error
43bf215546Sopenharmony_cigenerate_indices(struct svga_hwtnl *hwtnl,
44bf215546Sopenharmony_ci                 unsigned nr,
45bf215546Sopenharmony_ci                 unsigned index_size,
46bf215546Sopenharmony_ci                 u_generate_func generate, struct pipe_resource **out_buf)
47bf215546Sopenharmony_ci{
48bf215546Sopenharmony_ci   struct pipe_context *pipe = &hwtnl->svga->pipe;
49bf215546Sopenharmony_ci   struct pipe_transfer *transfer;
50bf215546Sopenharmony_ci   unsigned size = index_size * nr;
51bf215546Sopenharmony_ci   struct pipe_resource *dst = NULL;
52bf215546Sopenharmony_ci   void *dst_map = NULL;
53bf215546Sopenharmony_ci
54bf215546Sopenharmony_ci   dst = pipe_buffer_create(pipe->screen, PIPE_BIND_INDEX_BUFFER,
55bf215546Sopenharmony_ci                            PIPE_USAGE_IMMUTABLE, size);
56bf215546Sopenharmony_ci   if (!dst)
57bf215546Sopenharmony_ci      goto fail;
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci   dst_map = pipe_buffer_map(pipe, dst, PIPE_MAP_WRITE, &transfer);
60bf215546Sopenharmony_ci   if (!dst_map)
61bf215546Sopenharmony_ci      goto fail;
62bf215546Sopenharmony_ci
63bf215546Sopenharmony_ci   generate(0, nr, dst_map);
64bf215546Sopenharmony_ci
65bf215546Sopenharmony_ci   pipe_buffer_unmap(pipe, transfer);
66bf215546Sopenharmony_ci
67bf215546Sopenharmony_ci   *out_buf = dst;
68bf215546Sopenharmony_ci   return PIPE_OK;
69bf215546Sopenharmony_ci
70bf215546Sopenharmony_cifail:
71bf215546Sopenharmony_ci   if (dst_map)
72bf215546Sopenharmony_ci      pipe_buffer_unmap(pipe, transfer);
73bf215546Sopenharmony_ci
74bf215546Sopenharmony_ci   if (dst)
75bf215546Sopenharmony_ci      pipe->screen->resource_destroy(pipe->screen, dst);
76bf215546Sopenharmony_ci
77bf215546Sopenharmony_ci   return PIPE_ERROR_OUT_OF_MEMORY;
78bf215546Sopenharmony_ci}
79bf215546Sopenharmony_ci
80bf215546Sopenharmony_ci
81bf215546Sopenharmony_cistatic boolean
82bf215546Sopenharmony_cicompare(unsigned cached_nr, unsigned nr, unsigned type)
83bf215546Sopenharmony_ci{
84bf215546Sopenharmony_ci   if (type == U_GENERATE_REUSABLE)
85bf215546Sopenharmony_ci      return cached_nr >= nr;
86bf215546Sopenharmony_ci   else
87bf215546Sopenharmony_ci      return cached_nr == nr;
88bf215546Sopenharmony_ci}
89bf215546Sopenharmony_ci
90bf215546Sopenharmony_ci
91bf215546Sopenharmony_cistatic enum pipe_error
92bf215546Sopenharmony_ciretrieve_or_generate_indices(struct svga_hwtnl *hwtnl,
93bf215546Sopenharmony_ci                             enum pipe_prim_type prim,
94bf215546Sopenharmony_ci                             unsigned gen_type,
95bf215546Sopenharmony_ci                             unsigned gen_nr,
96bf215546Sopenharmony_ci                             unsigned gen_size,
97bf215546Sopenharmony_ci                             u_generate_func generate,
98bf215546Sopenharmony_ci                             struct pipe_resource **out_buf)
99bf215546Sopenharmony_ci{
100bf215546Sopenharmony_ci   enum pipe_error ret = PIPE_OK;
101bf215546Sopenharmony_ci   int i;
102bf215546Sopenharmony_ci
103bf215546Sopenharmony_ci   SVGA_STATS_TIME_PUSH(svga_sws(hwtnl->svga), SVGA_STATS_TIME_GENERATEINDICES);
104bf215546Sopenharmony_ci
105bf215546Sopenharmony_ci   for (i = 0; i < IDX_CACHE_MAX; i++) {
106bf215546Sopenharmony_ci      if (hwtnl->index_cache[prim][i].buffer != NULL &&
107bf215546Sopenharmony_ci          hwtnl->index_cache[prim][i].generate == generate) {
108bf215546Sopenharmony_ci         if (compare(hwtnl->index_cache[prim][i].gen_nr, gen_nr, gen_type)) {
109bf215546Sopenharmony_ci            pipe_resource_reference(out_buf,
110bf215546Sopenharmony_ci                                    hwtnl->index_cache[prim][i].buffer);
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_ci            if (DBG)
113bf215546Sopenharmony_ci               debug_printf("%s retrieve %d/%d\n", __FUNCTION__, i, gen_nr);
114bf215546Sopenharmony_ci
115bf215546Sopenharmony_ci            goto done;
116bf215546Sopenharmony_ci         }
117bf215546Sopenharmony_ci         else if (gen_type == U_GENERATE_REUSABLE) {
118bf215546Sopenharmony_ci            pipe_resource_reference(&hwtnl->index_cache[prim][i].buffer,
119bf215546Sopenharmony_ci                                    NULL);
120bf215546Sopenharmony_ci
121bf215546Sopenharmony_ci            if (DBG)
122bf215546Sopenharmony_ci               debug_printf("%s discard %d/%d\n", __FUNCTION__,
123bf215546Sopenharmony_ci                            i, hwtnl->index_cache[prim][i].gen_nr);
124bf215546Sopenharmony_ci
125bf215546Sopenharmony_ci            break;
126bf215546Sopenharmony_ci         }
127bf215546Sopenharmony_ci      }
128bf215546Sopenharmony_ci   }
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_ci   if (i == IDX_CACHE_MAX) {
131bf215546Sopenharmony_ci      unsigned smallest = 0;
132bf215546Sopenharmony_ci      unsigned smallest_size = ~0;
133bf215546Sopenharmony_ci
134bf215546Sopenharmony_ci      for (i = 0; i < IDX_CACHE_MAX && smallest_size; i++) {
135bf215546Sopenharmony_ci         if (hwtnl->index_cache[prim][i].buffer == NULL) {
136bf215546Sopenharmony_ci            smallest = i;
137bf215546Sopenharmony_ci            smallest_size = 0;
138bf215546Sopenharmony_ci         }
139bf215546Sopenharmony_ci         else if (hwtnl->index_cache[prim][i].gen_nr < smallest) {
140bf215546Sopenharmony_ci            smallest = i;
141bf215546Sopenharmony_ci            smallest_size = hwtnl->index_cache[prim][i].gen_nr;
142bf215546Sopenharmony_ci         }
143bf215546Sopenharmony_ci      }
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_ci      assert(smallest != IDX_CACHE_MAX);
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_ci      pipe_resource_reference(&hwtnl->index_cache[prim][smallest].buffer,
148bf215546Sopenharmony_ci                              NULL);
149bf215546Sopenharmony_ci
150bf215546Sopenharmony_ci      if (DBG)
151bf215546Sopenharmony_ci         debug_printf("%s discard smallest %d/%d\n", __FUNCTION__,
152bf215546Sopenharmony_ci                      smallest, smallest_size);
153bf215546Sopenharmony_ci
154bf215546Sopenharmony_ci      i = smallest;
155bf215546Sopenharmony_ci   }
156bf215546Sopenharmony_ci
157bf215546Sopenharmony_ci   ret = generate_indices(hwtnl, gen_nr, gen_size, generate, out_buf);
158bf215546Sopenharmony_ci   if (ret != PIPE_OK)
159bf215546Sopenharmony_ci      goto done;
160bf215546Sopenharmony_ci
161bf215546Sopenharmony_ci   hwtnl->index_cache[prim][i].generate = generate;
162bf215546Sopenharmony_ci   hwtnl->index_cache[prim][i].gen_nr = gen_nr;
163bf215546Sopenharmony_ci   pipe_resource_reference(&hwtnl->index_cache[prim][i].buffer, *out_buf);
164bf215546Sopenharmony_ci
165bf215546Sopenharmony_ci   if (DBG)
166bf215546Sopenharmony_ci      debug_printf("%s cache %d/%d\n", __FUNCTION__,
167bf215546Sopenharmony_ci                   i, hwtnl->index_cache[prim][i].gen_nr);
168bf215546Sopenharmony_ci
169bf215546Sopenharmony_cidone:
170bf215546Sopenharmony_ci   SVGA_STATS_TIME_POP(svga_sws(hwtnl->svga));
171bf215546Sopenharmony_ci   return ret;
172bf215546Sopenharmony_ci}
173bf215546Sopenharmony_ci
174bf215546Sopenharmony_ci
175bf215546Sopenharmony_cistatic enum pipe_error
176bf215546Sopenharmony_cisimple_draw_arrays(struct svga_hwtnl *hwtnl,
177bf215546Sopenharmony_ci                   enum pipe_prim_type prim, unsigned start, unsigned count,
178bf215546Sopenharmony_ci                   unsigned start_instance, unsigned instance_count,
179bf215546Sopenharmony_ci                   ubyte vertices_per_patch)
180bf215546Sopenharmony_ci{
181bf215546Sopenharmony_ci   SVGA3dPrimitiveRange range;
182bf215546Sopenharmony_ci   unsigned hw_prim;
183bf215546Sopenharmony_ci   unsigned hw_count;
184bf215546Sopenharmony_ci
185bf215546Sopenharmony_ci   hw_prim = svga_translate_prim(prim, count, &hw_count, vertices_per_patch);
186bf215546Sopenharmony_ci   if (hw_count == 0)
187bf215546Sopenharmony_ci      return PIPE_ERROR_BAD_INPUT;
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_ci   range.primType = hw_prim;
190bf215546Sopenharmony_ci   range.primitiveCount = hw_count;
191bf215546Sopenharmony_ci   range.indexArray.surfaceId = SVGA3D_INVALID_ID;
192bf215546Sopenharmony_ci   range.indexArray.offset = 0;
193bf215546Sopenharmony_ci   range.indexArray.stride = 0;
194bf215546Sopenharmony_ci   range.indexWidth = 0;
195bf215546Sopenharmony_ci   range.indexBias = start;
196bf215546Sopenharmony_ci
197bf215546Sopenharmony_ci   /* Min/max index should be calculated prior to applying bias, so we
198bf215546Sopenharmony_ci    * end up with min_index = 0, max_index = count - 1 and everybody
199bf215546Sopenharmony_ci    * looking at those numbers knows to adjust them by
200bf215546Sopenharmony_ci    * range.indexBias.
201bf215546Sopenharmony_ci    */
202bf215546Sopenharmony_ci   return svga_hwtnl_prim(hwtnl, &range, count,
203bf215546Sopenharmony_ci                          0, count - 1, NULL,
204bf215546Sopenharmony_ci                          start_instance, instance_count,
205bf215546Sopenharmony_ci                          NULL, NULL);
206bf215546Sopenharmony_ci}
207bf215546Sopenharmony_ci
208bf215546Sopenharmony_ci
209bf215546Sopenharmony_cienum pipe_error
210bf215546Sopenharmony_cisvga_hwtnl_draw_arrays(struct svga_hwtnl *hwtnl,
211bf215546Sopenharmony_ci                       enum pipe_prim_type prim, unsigned start, unsigned count,
212bf215546Sopenharmony_ci                       unsigned start_instance, unsigned instance_count,
213bf215546Sopenharmony_ci                       ubyte vertices_per_patch)
214bf215546Sopenharmony_ci{
215bf215546Sopenharmony_ci   enum pipe_prim_type gen_prim;
216bf215546Sopenharmony_ci   unsigned gen_size, gen_nr;
217bf215546Sopenharmony_ci   enum indices_mode gen_type;
218bf215546Sopenharmony_ci   u_generate_func gen_func;
219bf215546Sopenharmony_ci   enum pipe_error ret = PIPE_OK;
220bf215546Sopenharmony_ci   unsigned api_pv = hwtnl->api_pv;
221bf215546Sopenharmony_ci   struct svga_context *svga = hwtnl->svga;
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_ci   SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_HWTNLDRAWARRAYS);
224bf215546Sopenharmony_ci
225bf215546Sopenharmony_ci   if (svga->curr.rast->templ.fill_front !=
226bf215546Sopenharmony_ci       svga->curr.rast->templ.fill_back) {
227bf215546Sopenharmony_ci      assert(hwtnl->api_fillmode == PIPE_POLYGON_MODE_FILL);
228bf215546Sopenharmony_ci   }
229bf215546Sopenharmony_ci
230bf215546Sopenharmony_ci   if (svga->curr.rast->templ.flatshade &&
231bf215546Sopenharmony_ci         svga_fs_variant(svga->state.hw_draw.fs)->constant_color_output) {
232bf215546Sopenharmony_ci      /* The fragment color is a constant, not per-vertex so the whole
233bf215546Sopenharmony_ci       * primitive will be the same color (except for possible blending).
234bf215546Sopenharmony_ci       * We can ignore the current provoking vertex state and use whatever
235bf215546Sopenharmony_ci       * the hardware wants.
236bf215546Sopenharmony_ci       */
237bf215546Sopenharmony_ci      api_pv = hwtnl->hw_pv;
238bf215546Sopenharmony_ci
239bf215546Sopenharmony_ci      if (hwtnl->api_fillmode == PIPE_POLYGON_MODE_FILL) {
240bf215546Sopenharmony_ci         /* Do some simple primitive conversions to avoid index buffer
241bf215546Sopenharmony_ci          * generation below.  Note that polygons and quads are not directly
242bf215546Sopenharmony_ci          * supported by the svga device.  Also note, we can only do this
243bf215546Sopenharmony_ci          * for flat/constant-colored rendering because of provoking vertex.
244bf215546Sopenharmony_ci          */
245bf215546Sopenharmony_ci         if (prim == PIPE_PRIM_POLYGON) {
246bf215546Sopenharmony_ci            prim = PIPE_PRIM_TRIANGLE_FAN;
247bf215546Sopenharmony_ci         }
248bf215546Sopenharmony_ci         else if (prim == PIPE_PRIM_QUADS && count == 4) {
249bf215546Sopenharmony_ci            prim = PIPE_PRIM_TRIANGLE_FAN;
250bf215546Sopenharmony_ci         }
251bf215546Sopenharmony_ci      }
252bf215546Sopenharmony_ci   }
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_ci   if (svga_need_unfilled_fallback(hwtnl, prim)) {
255bf215546Sopenharmony_ci      /* Convert unfilled polygons into points, lines, triangles */
256bf215546Sopenharmony_ci      gen_type = u_unfilled_generator(prim,
257bf215546Sopenharmony_ci                                      start,
258bf215546Sopenharmony_ci                                      count,
259bf215546Sopenharmony_ci                                      hwtnl->api_fillmode,
260bf215546Sopenharmony_ci                                      &gen_prim,
261bf215546Sopenharmony_ci                                      &gen_size, &gen_nr, &gen_func);
262bf215546Sopenharmony_ci   }
263bf215546Sopenharmony_ci   else {
264bf215546Sopenharmony_ci      /* Convert PIPE_PRIM_LINE_LOOP to PIPE_PRIM_LINESTRIP,
265bf215546Sopenharmony_ci       * convert PIPE_PRIM_POLYGON to PIPE_PRIM_TRIANGLE_FAN,
266bf215546Sopenharmony_ci       * etc, if needed (as determined by svga_hw_prims mask).
267bf215546Sopenharmony_ci       */
268bf215546Sopenharmony_ci      gen_type = u_index_generator(svga_hw_prims,
269bf215546Sopenharmony_ci                                   prim,
270bf215546Sopenharmony_ci                                   start,
271bf215546Sopenharmony_ci                                   count,
272bf215546Sopenharmony_ci                                   api_pv,
273bf215546Sopenharmony_ci                                   hwtnl->hw_pv,
274bf215546Sopenharmony_ci                                   &gen_prim, &gen_size, &gen_nr, &gen_func);
275bf215546Sopenharmony_ci   }
276bf215546Sopenharmony_ci
277bf215546Sopenharmony_ci   if (gen_type == U_GENERATE_LINEAR) {
278bf215546Sopenharmony_ci      ret = simple_draw_arrays(hwtnl, gen_prim, start, count,
279bf215546Sopenharmony_ci                               start_instance, instance_count,
280bf215546Sopenharmony_ci                               vertices_per_patch);
281bf215546Sopenharmony_ci   }
282bf215546Sopenharmony_ci   else {
283bf215546Sopenharmony_ci      struct pipe_resource *gen_buf = NULL;
284bf215546Sopenharmony_ci
285bf215546Sopenharmony_ci      /* Need to draw as indexed primitive.
286bf215546Sopenharmony_ci       * Potentially need to run the gen func to build an index buffer.
287bf215546Sopenharmony_ci       */
288bf215546Sopenharmony_ci      ret = retrieve_or_generate_indices(hwtnl,
289bf215546Sopenharmony_ci                                         prim,
290bf215546Sopenharmony_ci                                         gen_type,
291bf215546Sopenharmony_ci                                         gen_nr,
292bf215546Sopenharmony_ci                                         gen_size, gen_func, &gen_buf);
293bf215546Sopenharmony_ci      if (ret == PIPE_OK) {
294bf215546Sopenharmony_ci         util_debug_message(&svga->debug.callback, PERF_INFO,
295bf215546Sopenharmony_ci                            "generating temporary index buffer for drawing %s",
296bf215546Sopenharmony_ci                            u_prim_name(prim));
297bf215546Sopenharmony_ci
298bf215546Sopenharmony_ci         ret = svga_hwtnl_simple_draw_range_elements(hwtnl,
299bf215546Sopenharmony_ci                                                     gen_buf,
300bf215546Sopenharmony_ci                                                     gen_size,
301bf215546Sopenharmony_ci                                                     start,
302bf215546Sopenharmony_ci                                                     0,
303bf215546Sopenharmony_ci                                                     count - 1,
304bf215546Sopenharmony_ci                                                     gen_prim, 0, gen_nr,
305bf215546Sopenharmony_ci                                                     start_instance,
306bf215546Sopenharmony_ci                                                     instance_count,
307bf215546Sopenharmony_ci                                                     vertices_per_patch);
308bf215546Sopenharmony_ci      }
309bf215546Sopenharmony_ci
310bf215546Sopenharmony_ci      if (gen_buf) {
311bf215546Sopenharmony_ci         pipe_resource_reference(&gen_buf, NULL);
312bf215546Sopenharmony_ci      }
313bf215546Sopenharmony_ci   }
314bf215546Sopenharmony_ci
315bf215546Sopenharmony_ci   SVGA_STATS_TIME_POP(svga_sws(svga));
316bf215546Sopenharmony_ci   return ret;
317bf215546Sopenharmony_ci}
318