u_indices.c revision af69d88d
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 nr,
31                                     void *out )
32{
33   memcpy(out, &((short *)in)[start], nr*sizeof(short));
34}
35
36static void translate_memcpy_uint( const void *in,
37                                   unsigned start,
38                                   unsigned nr,
39                                   void *out )
40{
41   memcpy(out, &((int *)in)[start], nr*sizeof(int));
42}
43
44
45/**
46 * Translate indexes when a driver can't support certain types
47 * of drawing.  Example include:
48 * - Translate 1-byte indexes into 2-byte indexes
49 * - Translate PIPE_PRIM_QUADS into PIPE_PRIM_TRIANGLES when the hardware
50 *   doesn't support the former.
51 * - Translate from first provoking vertex to last provoking vertex and
52 *   vice versa.
53 *
54 * \param hw_mask  mask of (1 << PIPE_PRIM_x) flags indicating which types
55 *                 of primitives are supported by the hardware.
56 * \param prim  incoming PIPE_PRIM_x
57 * \param in_index_size  bytes per index value (1, 2 or 4)
58 * \param nr  number of incoming vertices
59 * \param in_pv  incoming provoking vertex convention (PV_FIRST or PV_LAST)
60 * \param out_pv  desired provoking vertex convention (PV_FIRST or PV_LAST)
61 * \param out_prim  returns new PIPE_PRIM_x we'll translate to
62 * \param out_index_size  returns bytes per new index value (2 or 4)
63 * \param out_nr  returns number of new vertices
64 * \param out_translate  returns the translation function to use by the caller
65 */
66int u_index_translator( unsigned hw_mask,
67                        unsigned prim,
68                        unsigned in_index_size,
69                        unsigned nr,
70                        unsigned in_pv,
71                        unsigned out_pv,
72                        unsigned *out_prim,
73                        unsigned *out_index_size,
74                        unsigned *out_nr,
75                        u_translate_func *out_translate )
76{
77   unsigned in_idx;
78   unsigned out_idx;
79   int ret = U_TRANSLATE_NORMAL;
80
81   assert(in_index_size == 1 ||
82          in_index_size == 2 ||
83          in_index_size == 4);
84
85   u_index_init();
86
87   in_idx = in_size_idx(in_index_size);
88   *out_index_size = (in_index_size == 4) ? 4 : 2;
89   out_idx = out_size_idx(*out_index_size);
90
91   if ((hw_mask & (1<<prim)) &&
92       in_index_size == *out_index_size &&
93       in_pv == out_pv)
94   {
95      /* Index translation not really needed */
96      if (in_index_size == 4)
97         *out_translate = translate_memcpy_uint;
98      else
99         *out_translate = translate_memcpy_ushort;
100
101      *out_prim = prim;
102      *out_nr = nr;
103
104      return U_TRANSLATE_MEMCPY;
105   }
106   else {
107      switch (prim) {
108      case PIPE_PRIM_POINTS:
109         *out_translate = translate[in_idx][out_idx][in_pv][out_pv][prim];
110         *out_prim = PIPE_PRIM_POINTS;
111         *out_nr = nr;
112         break;
113
114      case PIPE_PRIM_LINES:
115         *out_translate = translate[in_idx][out_idx][in_pv][out_pv][prim];
116         *out_prim = PIPE_PRIM_LINES;
117         *out_nr = nr;
118         break;
119
120      case PIPE_PRIM_LINE_STRIP:
121         *out_translate = translate[in_idx][out_idx][in_pv][out_pv][prim];
122         *out_prim = PIPE_PRIM_LINES;
123         *out_nr = (nr - 1) * 2;
124         break;
125
126      case PIPE_PRIM_LINE_LOOP:
127         *out_translate = translate[in_idx][out_idx][in_pv][out_pv][prim];
128         *out_prim = PIPE_PRIM_LINES;
129         *out_nr = nr * 2;
130         break;
131
132      case PIPE_PRIM_TRIANGLES:
133         *out_translate = translate[in_idx][out_idx][in_pv][out_pv][prim];
134         *out_prim = PIPE_PRIM_TRIANGLES;
135         *out_nr = nr;
136         break;
137
138      case PIPE_PRIM_TRIANGLE_STRIP:
139         *out_translate = translate[in_idx][out_idx][in_pv][out_pv][prim];
140         *out_prim = PIPE_PRIM_TRIANGLES;
141         *out_nr = (nr - 2) * 3;
142         break;
143
144      case PIPE_PRIM_TRIANGLE_FAN:
145         *out_translate = translate[in_idx][out_idx][in_pv][out_pv][prim];
146         *out_prim = PIPE_PRIM_TRIANGLES;
147         *out_nr = (nr - 2) * 3;
148         break;
149
150      case PIPE_PRIM_QUADS:
151         *out_translate = translate[in_idx][out_idx][in_pv][out_pv][prim];
152         *out_prim = PIPE_PRIM_TRIANGLES;
153         *out_nr = (nr / 4) * 6;
154         break;
155
156      case PIPE_PRIM_QUAD_STRIP:
157         *out_translate = translate[in_idx][out_idx][in_pv][out_pv][prim];
158         *out_prim = PIPE_PRIM_TRIANGLES;
159         *out_nr = (nr - 2) * 3;
160         break;
161
162      case PIPE_PRIM_POLYGON:
163         *out_translate = translate[in_idx][out_idx][in_pv][out_pv][prim];
164         *out_prim = PIPE_PRIM_TRIANGLES;
165         *out_nr = (nr - 2) * 3;
166         break;
167
168      default:
169         assert(0);
170         *out_translate = translate[in_idx][out_idx][in_pv][out_pv][prim];
171         *out_prim = PIPE_PRIM_POINTS;
172         *out_nr = nr;
173         return U_TRANSLATE_ERROR;
174      }
175   }
176
177   return ret;
178}
179
180
181/**
182 * If a driver does not support a particular gallium primitive type
183 * (such as PIPE_PRIM_QUAD_STRIP) this function can be used to help
184 * convert the primitive into a simpler type (like PIPE_PRIM_TRIANGLES).
185 *
186 * The generator functions generates a number of ushort or uint indexes
187 * for drawing the new type of primitive.
188 *
189 * \param hw_mask  a bitmask of (1 << PIPE_PRIM_x) values that indicates
190 *                 kind of primitives are supported by the driver.
191 * \param prim  the PIPE_PRIM_x that the user wants to draw
192 * \param start  index of first vertex to draw
193 * \param nr  number of vertices to draw
194 * \param in_pv  user's provoking vertex (PV_FIRST/LAST)
195 * \param out_pv  desired proking vertex for the hardware (PV_FIRST/LAST)
196 * \param out_prim  returns the new primitive type for the driver
197 * \param out_index_size  returns OUT_USHORT or OUT_UINT
198 * \param out_nr  returns new number of vertices to draw
199 * \param out_generate  returns pointer to the generator function
200 */
201int u_index_generator( unsigned hw_mask,
202                       unsigned prim,
203                       unsigned start,
204                       unsigned nr,
205                       unsigned in_pv,
206                       unsigned out_pv,
207                       unsigned *out_prim,
208                       unsigned *out_index_size,
209                       unsigned *out_nr,
210                       u_generate_func *out_generate )
211
212{
213   unsigned out_idx;
214
215   u_index_init();
216
217   *out_index_size = ((start + nr) > 0xfffe) ? 4 : 2;
218   out_idx = out_size_idx(*out_index_size);
219
220   if ((hw_mask & (1<<prim)) &&
221       (in_pv == out_pv)) {
222
223      *out_generate = generate[out_idx][in_pv][out_pv][PIPE_PRIM_POINTS];
224      *out_prim = prim;
225      *out_nr = nr;
226      return U_GENERATE_LINEAR;
227   }
228   else {
229      switch (prim) {
230      case PIPE_PRIM_POINTS:
231         *out_generate = generate[out_idx][in_pv][out_pv][prim];
232         *out_prim = PIPE_PRIM_POINTS;
233         *out_nr = nr;
234         return U_GENERATE_REUSABLE;
235
236      case PIPE_PRIM_LINES:
237         *out_generate = generate[out_idx][in_pv][out_pv][prim];
238         *out_prim = PIPE_PRIM_LINES;
239         *out_nr = nr;
240         return U_GENERATE_REUSABLE;
241
242      case PIPE_PRIM_LINE_STRIP:
243         *out_generate = generate[out_idx][in_pv][out_pv][prim];
244         *out_prim = PIPE_PRIM_LINES;
245         *out_nr = (nr - 1) * 2;
246         return U_GENERATE_REUSABLE;
247
248      case PIPE_PRIM_LINE_LOOP:
249         *out_generate = generate[out_idx][in_pv][out_pv][prim];
250         *out_prim = PIPE_PRIM_LINES;
251         *out_nr = nr * 2;
252         return U_GENERATE_ONE_OFF;
253
254      case PIPE_PRIM_TRIANGLES:
255         *out_generate = generate[out_idx][in_pv][out_pv][prim];
256         *out_prim = PIPE_PRIM_TRIANGLES;
257         *out_nr = nr;
258         return U_GENERATE_REUSABLE;
259
260      case PIPE_PRIM_TRIANGLE_STRIP:
261         *out_generate = generate[out_idx][in_pv][out_pv][prim];
262         *out_prim = PIPE_PRIM_TRIANGLES;
263         *out_nr = (nr - 2) * 3;
264         return U_GENERATE_REUSABLE;
265
266      case PIPE_PRIM_TRIANGLE_FAN:
267         *out_generate = generate[out_idx][in_pv][out_pv][prim];
268         *out_prim = PIPE_PRIM_TRIANGLES;
269         *out_nr = (nr - 2) * 3;
270         return U_GENERATE_REUSABLE;
271
272      case PIPE_PRIM_QUADS:
273         *out_generate = generate[out_idx][in_pv][out_pv][prim];
274         *out_prim = PIPE_PRIM_TRIANGLES;
275         *out_nr = (nr / 4) * 6;
276         return U_GENERATE_REUSABLE;
277
278      case PIPE_PRIM_QUAD_STRIP:
279         *out_generate = generate[out_idx][in_pv][out_pv][prim];
280         *out_prim = PIPE_PRIM_TRIANGLES;
281         *out_nr = (nr - 2) * 3;
282         return U_GENERATE_REUSABLE;
283
284      case PIPE_PRIM_POLYGON:
285         *out_generate = generate[out_idx][in_pv][out_pv][prim];
286         *out_prim = PIPE_PRIM_TRIANGLES;
287         *out_nr = (nr - 2) * 3;
288         return U_GENERATE_REUSABLE;
289
290      default:
291         assert(0);
292         *out_generate = generate[out_idx][in_pv][out_pv][PIPE_PRIM_POINTS];
293         *out_prim = PIPE_PRIM_POINTS;
294         *out_nr = nr;
295         return U_TRANSLATE_ERROR;
296      }
297   }
298}
299