xref: /aosp_15_r20/external/mesa3d/src/gallium/auxiliary/indices/u_indices.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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