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