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