1848b8605Smrg/*
2848b8605Smrg * Copyright 2009 VMware, Inc.
3848b8605Smrg * All Rights Reserved.
4848b8605Smrg *
5848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
6848b8605Smrg * copy of this software and associated documentation files (the "Software"),
7848b8605Smrg * to deal in the Software without restriction, including without limitation
8848b8605Smrg * on the rights to use, copy, modify, merge, publish, distribute, sub
9848b8605Smrg * license, and/or sell copies of the Software, and to permit persons to whom
10848b8605Smrg * the Software is furnished to do so, subject to the following conditions:
11848b8605Smrg *
12848b8605Smrg * The above copyright notice and this permission notice (including the next
13848b8605Smrg * paragraph) shall be included in all copies or substantial portions of the
14848b8605Smrg * Software.
15848b8605Smrg *
16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17848b8605Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
19848b8605Smrg * VMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
20848b8605Smrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21848b8605Smrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
22848b8605Smrg * USE OR OTHER DEALINGS IN THE SOFTWARE.
23848b8605Smrg */
24848b8605Smrg
25848b8605Smrg#include "u_indices.h"
26848b8605Smrg#include "u_indices_priv.h"
27848b8605Smrg
28848b8605Smrgstatic void translate_memcpy_ushort( const void *in,
29848b8605Smrg                                     unsigned start,
30b8e80941Smrg                                     unsigned in_nr,
31b8e80941Smrg                                     unsigned out_nr,
32b8e80941Smrg                                     unsigned restart_index,
33848b8605Smrg                                     void *out )
34848b8605Smrg{
35b8e80941Smrg   memcpy(out, &((short *)in)[start], out_nr*sizeof(short));
36848b8605Smrg}
37848b8605Smrg
38848b8605Smrgstatic void translate_memcpy_uint( const void *in,
39848b8605Smrg                                   unsigned start,
40b8e80941Smrg                                   unsigned in_nr,
41b8e80941Smrg                                   unsigned out_nr,
42b8e80941Smrg                                   unsigned restart_index,
43848b8605Smrg                                   void *out )
44848b8605Smrg{
45b8e80941Smrg   memcpy(out, &((int *)in)[start], out_nr*sizeof(int));
46848b8605Smrg}
47848b8605Smrg
48848b8605Smrg
49848b8605Smrg/**
50848b8605Smrg * Translate indexes when a driver can't support certain types
51848b8605Smrg * of drawing.  Example include:
52848b8605Smrg * - Translate 1-byte indexes into 2-byte indexes
53848b8605Smrg * - Translate PIPE_PRIM_QUADS into PIPE_PRIM_TRIANGLES when the hardware
54848b8605Smrg *   doesn't support the former.
55848b8605Smrg * - Translate from first provoking vertex to last provoking vertex and
56848b8605Smrg *   vice versa.
57848b8605Smrg *
58b8e80941Smrg * Note that this function is used for indexed primitives.
59b8e80941Smrg *
60848b8605Smrg * \param hw_mask  mask of (1 << PIPE_PRIM_x) flags indicating which types
61848b8605Smrg *                 of primitives are supported by the hardware.
62848b8605Smrg * \param prim  incoming PIPE_PRIM_x
63848b8605Smrg * \param in_index_size  bytes per index value (1, 2 or 4)
64848b8605Smrg * \param nr  number of incoming vertices
65848b8605Smrg * \param in_pv  incoming provoking vertex convention (PV_FIRST or PV_LAST)
66848b8605Smrg * \param out_pv  desired provoking vertex convention (PV_FIRST or PV_LAST)
67b8e80941Smrg * \param prim_restart  whether primitive restart is disable or enabled
68848b8605Smrg * \param out_prim  returns new PIPE_PRIM_x we'll translate to
69848b8605Smrg * \param out_index_size  returns bytes per new index value (2 or 4)
70848b8605Smrg * \param out_nr  returns number of new vertices
71848b8605Smrg * \param out_translate  returns the translation function to use by the caller
72848b8605Smrg */
73b8e80941Smrgenum indices_mode
74b8e80941Smrgu_index_translator(unsigned hw_mask,
75b8e80941Smrg                   enum pipe_prim_type prim,
76b8e80941Smrg                   unsigned in_index_size,
77b8e80941Smrg                   unsigned nr,
78b8e80941Smrg                   unsigned in_pv,
79b8e80941Smrg                   unsigned out_pv,
80b8e80941Smrg                   unsigned prim_restart,
81b8e80941Smrg                   enum pipe_prim_type *out_prim,
82b8e80941Smrg                   unsigned *out_index_size,
83b8e80941Smrg                   unsigned *out_nr,
84b8e80941Smrg                   u_translate_func *out_translate)
85848b8605Smrg{
86848b8605Smrg   unsigned in_idx;
87848b8605Smrg   unsigned out_idx;
88b8e80941Smrg   enum indices_mode ret = U_TRANSLATE_NORMAL;
89848b8605Smrg
90848b8605Smrg   assert(in_index_size == 1 ||
91848b8605Smrg          in_index_size == 2 ||
92848b8605Smrg          in_index_size == 4);
93848b8605Smrg
94848b8605Smrg   u_index_init();
95848b8605Smrg
96848b8605Smrg   in_idx = in_size_idx(in_index_size);
97848b8605Smrg   *out_index_size = (in_index_size == 4) ? 4 : 2;
98848b8605Smrg   out_idx = out_size_idx(*out_index_size);
99848b8605Smrg
100848b8605Smrg   if ((hw_mask & (1<<prim)) &&
101848b8605Smrg       in_index_size == *out_index_size &&
102848b8605Smrg       in_pv == out_pv)
103848b8605Smrg   {
104848b8605Smrg      /* Index translation not really needed */
105848b8605Smrg      if (in_index_size == 4)
106848b8605Smrg         *out_translate = translate_memcpy_uint;
107848b8605Smrg      else
108848b8605Smrg         *out_translate = translate_memcpy_ushort;
109848b8605Smrg
110848b8605Smrg      *out_prim = prim;
111848b8605Smrg      *out_nr = nr;
112848b8605Smrg
113848b8605Smrg      return U_TRANSLATE_MEMCPY;
114848b8605Smrg   }
115848b8605Smrg   else {
116b8e80941Smrg      *out_translate = translate[in_idx][out_idx][in_pv][out_pv][prim_restart][prim];
117b8e80941Smrg
118848b8605Smrg      switch (prim) {
119848b8605Smrg      case PIPE_PRIM_POINTS:
120848b8605Smrg         *out_prim = PIPE_PRIM_POINTS;
121848b8605Smrg         *out_nr = nr;
122848b8605Smrg         break;
123848b8605Smrg
124848b8605Smrg      case PIPE_PRIM_LINES:
125848b8605Smrg         *out_prim = PIPE_PRIM_LINES;
126848b8605Smrg         *out_nr = nr;
127848b8605Smrg         break;
128848b8605Smrg
129848b8605Smrg      case PIPE_PRIM_LINE_STRIP:
130848b8605Smrg         *out_prim = PIPE_PRIM_LINES;
131848b8605Smrg         *out_nr = (nr - 1) * 2;
132848b8605Smrg         break;
133848b8605Smrg
134848b8605Smrg      case PIPE_PRIM_LINE_LOOP:
135848b8605Smrg         *out_prim = PIPE_PRIM_LINES;
136848b8605Smrg         *out_nr = nr * 2;
137848b8605Smrg         break;
138848b8605Smrg
139848b8605Smrg      case PIPE_PRIM_TRIANGLES:
140848b8605Smrg         *out_prim = PIPE_PRIM_TRIANGLES;
141848b8605Smrg         *out_nr = nr;
142848b8605Smrg         break;
143848b8605Smrg
144848b8605Smrg      case PIPE_PRIM_TRIANGLE_STRIP:
145848b8605Smrg         *out_prim = PIPE_PRIM_TRIANGLES;
146848b8605Smrg         *out_nr = (nr - 2) * 3;
147848b8605Smrg         break;
148848b8605Smrg
149848b8605Smrg      case PIPE_PRIM_TRIANGLE_FAN:
150848b8605Smrg         *out_prim = PIPE_PRIM_TRIANGLES;
151848b8605Smrg         *out_nr = (nr - 2) * 3;
152848b8605Smrg         break;
153848b8605Smrg
154848b8605Smrg      case PIPE_PRIM_QUADS:
155848b8605Smrg         *out_prim = PIPE_PRIM_TRIANGLES;
156848b8605Smrg         *out_nr = (nr / 4) * 6;
157848b8605Smrg         break;
158848b8605Smrg
159848b8605Smrg      case PIPE_PRIM_QUAD_STRIP:
160848b8605Smrg         *out_prim = PIPE_PRIM_TRIANGLES;
161848b8605Smrg         *out_nr = (nr - 2) * 3;
162848b8605Smrg         break;
163848b8605Smrg
164848b8605Smrg      case PIPE_PRIM_POLYGON:
165848b8605Smrg         *out_prim = PIPE_PRIM_TRIANGLES;
166848b8605Smrg         *out_nr = (nr - 2) * 3;
167848b8605Smrg         break;
168848b8605Smrg
169b8e80941Smrg      case PIPE_PRIM_LINES_ADJACENCY:
170b8e80941Smrg         *out_prim = PIPE_PRIM_LINES_ADJACENCY;
171b8e80941Smrg         *out_nr = nr;
172b8e80941Smrg         break;
173b8e80941Smrg
174b8e80941Smrg      case PIPE_PRIM_LINE_STRIP_ADJACENCY:
175b8e80941Smrg         *out_prim = PIPE_PRIM_LINES_ADJACENCY;
176b8e80941Smrg         *out_nr = (nr - 3) * 4;
177b8e80941Smrg         break;
178b8e80941Smrg
179b8e80941Smrg      case PIPE_PRIM_TRIANGLES_ADJACENCY:
180b8e80941Smrg         *out_prim = PIPE_PRIM_TRIANGLES_ADJACENCY;
181b8e80941Smrg         *out_nr = nr;
182b8e80941Smrg         break;
183b8e80941Smrg
184b8e80941Smrg      case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
185b8e80941Smrg         *out_prim = PIPE_PRIM_TRIANGLES_ADJACENCY;
186b8e80941Smrg         *out_nr = ((nr - 4) / 2) * 6;
187b8e80941Smrg         break;
188b8e80941Smrg
189848b8605Smrg      default:
190848b8605Smrg         assert(0);
191848b8605Smrg         *out_prim = PIPE_PRIM_POINTS;
192848b8605Smrg         *out_nr = nr;
193848b8605Smrg         return U_TRANSLATE_ERROR;
194848b8605Smrg      }
195848b8605Smrg   }
196848b8605Smrg
197848b8605Smrg   return ret;
198848b8605Smrg}
199848b8605Smrg
200848b8605Smrg
201848b8605Smrg/**
202848b8605Smrg * If a driver does not support a particular gallium primitive type
203848b8605Smrg * (such as PIPE_PRIM_QUAD_STRIP) this function can be used to help
204848b8605Smrg * convert the primitive into a simpler type (like PIPE_PRIM_TRIANGLES).
205848b8605Smrg *
206848b8605Smrg * The generator functions generates a number of ushort or uint indexes
207848b8605Smrg * for drawing the new type of primitive.
208848b8605Smrg *
209b8e80941Smrg * Note that this function is used for non-indexed primitives.
210b8e80941Smrg *
211848b8605Smrg * \param hw_mask  a bitmask of (1 << PIPE_PRIM_x) values that indicates
212848b8605Smrg *                 kind of primitives are supported by the driver.
213848b8605Smrg * \param prim  the PIPE_PRIM_x that the user wants to draw
214848b8605Smrg * \param start  index of first vertex to draw
215848b8605Smrg * \param nr  number of vertices to draw
216848b8605Smrg * \param in_pv  user's provoking vertex (PV_FIRST/LAST)
217848b8605Smrg * \param out_pv  desired proking vertex for the hardware (PV_FIRST/LAST)
218848b8605Smrg * \param out_prim  returns the new primitive type for the driver
219848b8605Smrg * \param out_index_size  returns OUT_USHORT or OUT_UINT
220848b8605Smrg * \param out_nr  returns new number of vertices to draw
221848b8605Smrg * \param out_generate  returns pointer to the generator function
222848b8605Smrg */
223b8e80941Smrgenum indices_mode
224b8e80941Smrgu_index_generator(unsigned hw_mask,
225b8e80941Smrg                  enum pipe_prim_type prim,
226b8e80941Smrg                  unsigned start,
227b8e80941Smrg                  unsigned nr,
228b8e80941Smrg                  unsigned in_pv,
229b8e80941Smrg                  unsigned out_pv,
230b8e80941Smrg                  enum pipe_prim_type *out_prim,
231b8e80941Smrg                  unsigned *out_index_size,
232b8e80941Smrg                  unsigned *out_nr,
233b8e80941Smrg                  u_generate_func *out_generate)
234848b8605Smrg{
235848b8605Smrg   unsigned out_idx;
236848b8605Smrg
237848b8605Smrg   u_index_init();
238848b8605Smrg
239848b8605Smrg   *out_index_size = ((start + nr) > 0xfffe) ? 4 : 2;
240848b8605Smrg   out_idx = out_size_idx(*out_index_size);
241848b8605Smrg
242848b8605Smrg   if ((hw_mask & (1<<prim)) &&
243848b8605Smrg       (in_pv == out_pv)) {
244848b8605Smrg
245848b8605Smrg      *out_generate = generate[out_idx][in_pv][out_pv][PIPE_PRIM_POINTS];
246848b8605Smrg      *out_prim = prim;
247848b8605Smrg      *out_nr = nr;
248848b8605Smrg      return U_GENERATE_LINEAR;
249848b8605Smrg   }
250848b8605Smrg   else {
251b8e80941Smrg      *out_generate = generate[out_idx][in_pv][out_pv][prim];
252b8e80941Smrg
253848b8605Smrg      switch (prim) {
254848b8605Smrg      case PIPE_PRIM_POINTS:
255848b8605Smrg         *out_prim = PIPE_PRIM_POINTS;
256848b8605Smrg         *out_nr = nr;
257848b8605Smrg         return U_GENERATE_REUSABLE;
258848b8605Smrg
259848b8605Smrg      case PIPE_PRIM_LINES:
260848b8605Smrg         *out_prim = PIPE_PRIM_LINES;
261848b8605Smrg         *out_nr = nr;
262848b8605Smrg         return U_GENERATE_REUSABLE;
263848b8605Smrg
264848b8605Smrg      case PIPE_PRIM_LINE_STRIP:
265848b8605Smrg         *out_prim = PIPE_PRIM_LINES;
266848b8605Smrg         *out_nr = (nr - 1) * 2;
267848b8605Smrg         return U_GENERATE_REUSABLE;
268848b8605Smrg
269848b8605Smrg      case PIPE_PRIM_LINE_LOOP:
270848b8605Smrg         *out_prim = PIPE_PRIM_LINES;
271848b8605Smrg         *out_nr = nr * 2;
272848b8605Smrg         return U_GENERATE_ONE_OFF;
273848b8605Smrg
274848b8605Smrg      case PIPE_PRIM_TRIANGLES:
275848b8605Smrg         *out_prim = PIPE_PRIM_TRIANGLES;
276848b8605Smrg         *out_nr = nr;
277848b8605Smrg         return U_GENERATE_REUSABLE;
278848b8605Smrg
279848b8605Smrg      case PIPE_PRIM_TRIANGLE_STRIP:
280848b8605Smrg         *out_prim = PIPE_PRIM_TRIANGLES;
281848b8605Smrg         *out_nr = (nr - 2) * 3;
282848b8605Smrg         return U_GENERATE_REUSABLE;
283848b8605Smrg
284848b8605Smrg      case PIPE_PRIM_TRIANGLE_FAN:
285848b8605Smrg         *out_prim = PIPE_PRIM_TRIANGLES;
286848b8605Smrg         *out_nr = (nr - 2) * 3;
287848b8605Smrg         return U_GENERATE_REUSABLE;
288848b8605Smrg
289848b8605Smrg      case PIPE_PRIM_QUADS:
290848b8605Smrg         *out_prim = PIPE_PRIM_TRIANGLES;
291848b8605Smrg         *out_nr = (nr / 4) * 6;
292848b8605Smrg         return U_GENERATE_REUSABLE;
293848b8605Smrg
294848b8605Smrg      case PIPE_PRIM_QUAD_STRIP:
295848b8605Smrg         *out_prim = PIPE_PRIM_TRIANGLES;
296848b8605Smrg         *out_nr = (nr - 2) * 3;
297848b8605Smrg         return U_GENERATE_REUSABLE;
298848b8605Smrg
299848b8605Smrg      case PIPE_PRIM_POLYGON:
300848b8605Smrg         *out_prim = PIPE_PRIM_TRIANGLES;
301848b8605Smrg         *out_nr = (nr - 2) * 3;
302848b8605Smrg         return U_GENERATE_REUSABLE;
303848b8605Smrg
304b8e80941Smrg      case PIPE_PRIM_LINES_ADJACENCY:
305b8e80941Smrg         *out_prim = PIPE_PRIM_LINES_ADJACENCY;
306b8e80941Smrg         *out_nr = nr;
307b8e80941Smrg         return U_GENERATE_REUSABLE;
308b8e80941Smrg
309b8e80941Smrg      case PIPE_PRIM_LINE_STRIP_ADJACENCY:
310b8e80941Smrg         *out_prim = PIPE_PRIM_LINES_ADJACENCY;
311b8e80941Smrg         *out_nr = (nr - 3) * 4;
312b8e80941Smrg         return U_GENERATE_REUSABLE;
313b8e80941Smrg
314b8e80941Smrg      case PIPE_PRIM_TRIANGLES_ADJACENCY:
315b8e80941Smrg         *out_prim = PIPE_PRIM_TRIANGLES_ADJACENCY;
316b8e80941Smrg         *out_nr = nr;
317b8e80941Smrg         return U_GENERATE_REUSABLE;
318b8e80941Smrg
319b8e80941Smrg      case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
320b8e80941Smrg         *out_prim = PIPE_PRIM_TRIANGLES_ADJACENCY;
321b8e80941Smrg         *out_nr = ((nr - 4) / 2) * 6;
322b8e80941Smrg         return U_GENERATE_REUSABLE;
323b8e80941Smrg
324848b8605Smrg      default:
325848b8605Smrg         assert(0);
326848b8605Smrg         *out_generate = generate[out_idx][in_pv][out_pv][PIPE_PRIM_POINTS];
327848b8605Smrg         *out_prim = PIPE_PRIM_POINTS;
328848b8605Smrg         *out_nr = nr;
329848b8605Smrg         return U_TRANSLATE_ERROR;
330848b8605Smrg      }
331848b8605Smrg   }
332848b8605Smrg}
333