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 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 38static 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 48static 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 62enum pipe_prim_type 63u_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 */ 121enum indices_mode 122u_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 170unsigned 171u_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 */ 236enum indices_mode 237u_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