1/*
2 * Copyright 2009 VMware, Inc.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * on the rights to use, copy, modify, merge, publish, distribute, sub
9 * license, and/or sell copies of the Software, and to permit persons to whom
10 * the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
19 * VMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
22 * USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25#include "u_indices.h"
26#include "u_indices_priv.h"
27
28static void translate_memcpy_ushort( const void *in,
29                                     unsigned start,
30                                     unsigned in_nr,
31                                     unsigned out_nr,
32                                     unsigned restart_index,
33                                     void *out )
34{
35   memcpy(out, &((short *)in)[start], out_nr*sizeof(short));
36}
37
38static void translate_memcpy_uint( const void *in,
39                                   unsigned start,
40                                   unsigned in_nr,
41                                   unsigned out_nr,
42                                   unsigned restart_index,
43                                   void *out )
44{
45   memcpy(out, &((int *)in)[start], out_nr*sizeof(int));
46}
47
48
49/**
50 * Translate indexes when a driver can't support certain types
51 * of drawing.  Example include:
52 * - Translate 1-byte indexes into 2-byte indexes
53 * - Translate PIPE_PRIM_QUADS into PIPE_PRIM_TRIANGLES when the hardware
54 *   doesn't support the former.
55 * - Translate from first provoking vertex to last provoking vertex and
56 *   vice versa.
57 *
58 * Note that this function is used for indexed primitives.
59 *
60 * \param hw_mask  mask of (1 << PIPE_PRIM_x) flags indicating which types
61 *                 of primitives are supported by the hardware.
62 * \param prim  incoming PIPE_PRIM_x
63 * \param in_index_size  bytes per index value (1, 2 or 4)
64 * \param nr  number of incoming vertices
65 * \param in_pv  incoming provoking vertex convention (PV_FIRST or PV_LAST)
66 * \param out_pv  desired provoking vertex convention (PV_FIRST or PV_LAST)
67 * \param prim_restart  whether primitive restart is disable or enabled
68 * \param out_prim  returns new PIPE_PRIM_x we'll translate to
69 * \param out_index_size  returns bytes per new index value (2 or 4)
70 * \param out_nr  returns number of new vertices
71 * \param out_translate  returns the translation function to use by the caller
72 */
73enum indices_mode
74u_index_translator(unsigned hw_mask,
75                   enum pipe_prim_type prim,
76                   unsigned in_index_size,
77                   unsigned nr,
78                   unsigned in_pv,
79                   unsigned out_pv,
80                   unsigned prim_restart,
81                   enum pipe_prim_type *out_prim,
82                   unsigned *out_index_size,
83                   unsigned *out_nr,
84                   u_translate_func *out_translate)
85{
86   unsigned in_idx;
87   unsigned out_idx;
88   enum indices_mode ret = U_TRANSLATE_NORMAL;
89
90   assert(in_index_size == 1 ||
91          in_index_size == 2 ||
92          in_index_size == 4);
93
94   u_index_init();
95
96   in_idx = in_size_idx(in_index_size);
97   *out_index_size = (in_index_size == 4) ? 4 : 2;
98   out_idx = out_size_idx(*out_index_size);
99
100   if ((hw_mask & (1<<prim)) &&
101       in_index_size == *out_index_size &&
102       in_pv == out_pv)
103   {
104      /* Index translation not really needed */
105      if (in_index_size == 4)
106         *out_translate = translate_memcpy_uint;
107      else
108         *out_translate = translate_memcpy_ushort;
109
110      *out_prim = prim;
111      *out_nr = nr;
112
113      return U_TRANSLATE_MEMCPY;
114   }
115   else {
116      *out_translate = translate[in_idx][out_idx][in_pv][out_pv][prim_restart][prim];
117
118      switch (prim) {
119      case PIPE_PRIM_POINTS:
120         *out_prim = PIPE_PRIM_POINTS;
121         *out_nr = nr;
122         break;
123
124      case PIPE_PRIM_LINES:
125         *out_prim = PIPE_PRIM_LINES;
126         *out_nr = nr;
127         break;
128
129      case PIPE_PRIM_LINE_STRIP:
130         *out_prim = PIPE_PRIM_LINES;
131         *out_nr = (nr - 1) * 2;
132         break;
133
134      case PIPE_PRIM_LINE_LOOP:
135         *out_prim = PIPE_PRIM_LINES;
136         *out_nr = nr * 2;
137         break;
138
139      case PIPE_PRIM_TRIANGLES:
140         *out_prim = PIPE_PRIM_TRIANGLES;
141         *out_nr = nr;
142         break;
143
144      case PIPE_PRIM_TRIANGLE_STRIP:
145         *out_prim = PIPE_PRIM_TRIANGLES;
146         *out_nr = (nr - 2) * 3;
147         break;
148
149      case PIPE_PRIM_TRIANGLE_FAN:
150         *out_prim = PIPE_PRIM_TRIANGLES;
151         *out_nr = (nr - 2) * 3;
152         break;
153
154      case PIPE_PRIM_QUADS:
155         *out_prim = PIPE_PRIM_TRIANGLES;
156         *out_nr = (nr / 4) * 6;
157         break;
158
159      case PIPE_PRIM_QUAD_STRIP:
160         *out_prim = PIPE_PRIM_TRIANGLES;
161         *out_nr = (nr - 2) * 3;
162         break;
163
164      case PIPE_PRIM_POLYGON:
165         *out_prim = PIPE_PRIM_TRIANGLES;
166         *out_nr = (nr - 2) * 3;
167         break;
168
169      case PIPE_PRIM_LINES_ADJACENCY:
170         *out_prim = PIPE_PRIM_LINES_ADJACENCY;
171         *out_nr = nr;
172         break;
173
174      case PIPE_PRIM_LINE_STRIP_ADJACENCY:
175         *out_prim = PIPE_PRIM_LINES_ADJACENCY;
176         *out_nr = (nr - 3) * 4;
177         break;
178
179      case PIPE_PRIM_TRIANGLES_ADJACENCY:
180         *out_prim = PIPE_PRIM_TRIANGLES_ADJACENCY;
181         *out_nr = nr;
182         break;
183
184      case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
185         *out_prim = PIPE_PRIM_TRIANGLES_ADJACENCY;
186         *out_nr = ((nr - 4) / 2) * 6;
187         break;
188
189      default:
190         assert(0);
191         *out_prim = PIPE_PRIM_POINTS;
192         *out_nr = nr;
193         return U_TRANSLATE_ERROR;
194      }
195   }
196
197   return ret;
198}
199
200
201/**
202 * If a driver does not support a particular gallium primitive type
203 * (such as PIPE_PRIM_QUAD_STRIP) this function can be used to help
204 * convert the primitive into a simpler type (like PIPE_PRIM_TRIANGLES).
205 *
206 * The generator functions generates a number of ushort or uint indexes
207 * for drawing the new type of primitive.
208 *
209 * Note that this function is used for non-indexed primitives.
210 *
211 * \param hw_mask  a bitmask of (1 << PIPE_PRIM_x) values that indicates
212 *                 kind of primitives are supported by the driver.
213 * \param prim  the PIPE_PRIM_x that the user wants to draw
214 * \param start  index of first vertex to draw
215 * \param nr  number of vertices to draw
216 * \param in_pv  user's provoking vertex (PV_FIRST/LAST)
217 * \param out_pv  desired proking vertex for the hardware (PV_FIRST/LAST)
218 * \param out_prim  returns the new primitive type for the driver
219 * \param out_index_size  returns OUT_USHORT or OUT_UINT
220 * \param out_nr  returns new number of vertices to draw
221 * \param out_generate  returns pointer to the generator function
222 */
223enum indices_mode
224u_index_generator(unsigned hw_mask,
225                  enum pipe_prim_type prim,
226                  unsigned start,
227                  unsigned nr,
228                  unsigned in_pv,
229                  unsigned out_pv,
230                  enum pipe_prim_type *out_prim,
231                  unsigned *out_index_size,
232                  unsigned *out_nr,
233                  u_generate_func *out_generate)
234{
235   unsigned out_idx;
236
237   u_index_init();
238
239   *out_index_size = ((start + nr) > 0xfffe) ? 4 : 2;
240   out_idx = out_size_idx(*out_index_size);
241
242   if ((hw_mask & (1<<prim)) &&
243       (in_pv == out_pv)) {
244
245      *out_generate = generate[out_idx][in_pv][out_pv][PIPE_PRIM_POINTS];
246      *out_prim = prim;
247      *out_nr = nr;
248      return U_GENERATE_LINEAR;
249   }
250   else {
251      *out_generate = generate[out_idx][in_pv][out_pv][prim];
252
253      switch (prim) {
254      case PIPE_PRIM_POINTS:
255         *out_prim = PIPE_PRIM_POINTS;
256         *out_nr = nr;
257         return U_GENERATE_REUSABLE;
258
259      case PIPE_PRIM_LINES:
260         *out_prim = PIPE_PRIM_LINES;
261         *out_nr = nr;
262         return U_GENERATE_REUSABLE;
263
264      case PIPE_PRIM_LINE_STRIP:
265         *out_prim = PIPE_PRIM_LINES;
266         *out_nr = (nr - 1) * 2;
267         return U_GENERATE_REUSABLE;
268
269      case PIPE_PRIM_LINE_LOOP:
270         *out_prim = PIPE_PRIM_LINES;
271         *out_nr = nr * 2;
272         return U_GENERATE_ONE_OFF;
273
274      case PIPE_PRIM_TRIANGLES:
275         *out_prim = PIPE_PRIM_TRIANGLES;
276         *out_nr = nr;
277         return U_GENERATE_REUSABLE;
278
279      case PIPE_PRIM_TRIANGLE_STRIP:
280         *out_prim = PIPE_PRIM_TRIANGLES;
281         *out_nr = (nr - 2) * 3;
282         return U_GENERATE_REUSABLE;
283
284      case PIPE_PRIM_TRIANGLE_FAN:
285         *out_prim = PIPE_PRIM_TRIANGLES;
286         *out_nr = (nr - 2) * 3;
287         return U_GENERATE_REUSABLE;
288
289      case PIPE_PRIM_QUADS:
290         *out_prim = PIPE_PRIM_TRIANGLES;
291         *out_nr = (nr / 4) * 6;
292         return U_GENERATE_REUSABLE;
293
294      case PIPE_PRIM_QUAD_STRIP:
295         *out_prim = PIPE_PRIM_TRIANGLES;
296         *out_nr = (nr - 2) * 3;
297         return U_GENERATE_REUSABLE;
298
299      case PIPE_PRIM_POLYGON:
300         *out_prim = PIPE_PRIM_TRIANGLES;
301         *out_nr = (nr - 2) * 3;
302         return U_GENERATE_REUSABLE;
303
304      case PIPE_PRIM_LINES_ADJACENCY:
305         *out_prim = PIPE_PRIM_LINES_ADJACENCY;
306         *out_nr = nr;
307         return U_GENERATE_REUSABLE;
308
309      case PIPE_PRIM_LINE_STRIP_ADJACENCY:
310         *out_prim = PIPE_PRIM_LINES_ADJACENCY;
311         *out_nr = (nr - 3) * 4;
312         return U_GENERATE_REUSABLE;
313
314      case PIPE_PRIM_TRIANGLES_ADJACENCY:
315         *out_prim = PIPE_PRIM_TRIANGLES_ADJACENCY;
316         *out_nr = nr;
317         return U_GENERATE_REUSABLE;
318
319      case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
320         *out_prim = PIPE_PRIM_TRIANGLES_ADJACENCY;
321         *out_nr = ((nr - 4) / 2) * 6;
322         return U_GENERATE_REUSABLE;
323
324      default:
325         assert(0);
326         *out_generate = generate[out_idx][in_pv][out_pv][PIPE_PRIM_POINTS];
327         *out_prim = PIPE_PRIM_POINTS;
328         *out_nr = nr;
329         return U_TRANSLATE_ERROR;
330      }
331   }
332}
333