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