1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included 14 * in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: 25 * Keith Whitwell <keithw@vmware.com> 26 */ 27 28 29#include "main/glheader.h" 30#include "main/arrayobj.h" 31#include "main/api_arrayelt.h" 32#include "vbo_private.h" 33 34const GLubyte 35_vbo_attribute_alias_map[VP_MODE_MAX][VERT_ATTRIB_MAX] = { 36 /* VP_MODE_FF: */ 37 { 38 VBO_ATTRIB_POS, /* VERT_ATTRIB_POS */ 39 VBO_ATTRIB_NORMAL, /* VERT_ATTRIB_NORMAL */ 40 VBO_ATTRIB_COLOR0, /* VERT_ATTRIB_COLOR0 */ 41 VBO_ATTRIB_COLOR1, /* VERT_ATTRIB_COLOR1 */ 42 VBO_ATTRIB_FOG, /* VERT_ATTRIB_FOG */ 43 VBO_ATTRIB_COLOR_INDEX, /* VERT_ATTRIB_COLOR_INDEX */ 44 VBO_ATTRIB_TEX0, /* VERT_ATTRIB_TEX0 */ 45 VBO_ATTRIB_TEX1, /* VERT_ATTRIB_TEX1 */ 46 VBO_ATTRIB_TEX2, /* VERT_ATTRIB_TEX2 */ 47 VBO_ATTRIB_TEX3, /* VERT_ATTRIB_TEX3 */ 48 VBO_ATTRIB_TEX4, /* VERT_ATTRIB_TEX4 */ 49 VBO_ATTRIB_TEX5, /* VERT_ATTRIB_TEX5 */ 50 VBO_ATTRIB_TEX6, /* VERT_ATTRIB_TEX6 */ 51 VBO_ATTRIB_TEX7, /* VERT_ATTRIB_TEX7 */ 52 VBO_ATTRIB_POINT_SIZE, /* VERT_ATTRIB_POINT_SIZE */ 53 VBO_ATTRIB_GENERIC0, /* VERT_ATTRIB_GENERIC0 */ 54 VBO_ATTRIB_GENERIC1, /* VERT_ATTRIB_GENERIC1 */ 55 VBO_ATTRIB_GENERIC2, /* VERT_ATTRIB_GENERIC2 */ 56 VBO_ATTRIB_SELECT_RESULT_OFFSET,/* VERT_ATTRIB_GENERIC3 */ 57 VBO_ATTRIB_MAT_FRONT_AMBIENT, /* VERT_ATTRIB_GENERIC4 */ 58 VBO_ATTRIB_MAT_BACK_AMBIENT, /* VERT_ATTRIB_GENERIC5 */ 59 VBO_ATTRIB_MAT_FRONT_DIFFUSE, /* VERT_ATTRIB_GENERIC6 */ 60 VBO_ATTRIB_MAT_BACK_DIFFUSE, /* VERT_ATTRIB_GENERIC7 */ 61 VBO_ATTRIB_MAT_FRONT_SPECULAR, /* VERT_ATTRIB_GENERIC8 */ 62 VBO_ATTRIB_MAT_BACK_SPECULAR, /* VERT_ATTRIB_GENERIC9 */ 63 VBO_ATTRIB_MAT_FRONT_EMISSION, /* VERT_ATTRIB_GENERIC10 */ 64 VBO_ATTRIB_MAT_BACK_EMISSION, /* VERT_ATTRIB_GENERIC11 */ 65 VBO_ATTRIB_MAT_FRONT_SHININESS, /* VERT_ATTRIB_GENERIC12 */ 66 VBO_ATTRIB_MAT_BACK_SHININESS, /* VERT_ATTRIB_GENERIC13 */ 67 VBO_ATTRIB_MAT_FRONT_INDEXES, /* VERT_ATTRIB_GENERIC14 */ 68 VBO_ATTRIB_MAT_BACK_INDEXES, /* VERT_ATTRIB_GENERIC15 */ 69 VBO_ATTRIB_EDGEFLAG, /* VERT_ATTRIB_EDGEFLAG */ 70 }, 71 72 /* VP_MODE_SHADER: */ 73 { 74 VBO_ATTRIB_POS, /* VERT_ATTRIB_POS */ 75 VBO_ATTRIB_NORMAL, /* VERT_ATTRIB_NORMAL */ 76 VBO_ATTRIB_COLOR0, /* VERT_ATTRIB_COLOR0 */ 77 VBO_ATTRIB_COLOR1, /* VERT_ATTRIB_COLOR1 */ 78 VBO_ATTRIB_FOG, /* VERT_ATTRIB_FOG */ 79 VBO_ATTRIB_COLOR_INDEX, /* VERT_ATTRIB_COLOR_INDEX */ 80 VBO_ATTRIB_TEX0, /* VERT_ATTRIB_TEX0 */ 81 VBO_ATTRIB_TEX1, /* VERT_ATTRIB_TEX1 */ 82 VBO_ATTRIB_TEX2, /* VERT_ATTRIB_TEX2 */ 83 VBO_ATTRIB_TEX3, /* VERT_ATTRIB_TEX3 */ 84 VBO_ATTRIB_TEX4, /* VERT_ATTRIB_TEX4 */ 85 VBO_ATTRIB_TEX5, /* VERT_ATTRIB_TEX5 */ 86 VBO_ATTRIB_TEX6, /* VERT_ATTRIB_TEX6 */ 87 VBO_ATTRIB_TEX7, /* VERT_ATTRIB_TEX7 */ 88 VBO_ATTRIB_POINT_SIZE, /* VERT_ATTRIB_POINT_SIZE */ 89 VBO_ATTRIB_GENERIC0, /* VERT_ATTRIB_GENERIC0 */ 90 VBO_ATTRIB_GENERIC1, /* VERT_ATTRIB_GENERIC1 */ 91 VBO_ATTRIB_GENERIC2, /* VERT_ATTRIB_GENERIC2 */ 92 VBO_ATTRIB_GENERIC3, /* VERT_ATTRIB_GENERIC3 */ 93 VBO_ATTRIB_GENERIC4, /* VERT_ATTRIB_GENERIC4 */ 94 VBO_ATTRIB_GENERIC5, /* VERT_ATTRIB_GENERIC5 */ 95 VBO_ATTRIB_GENERIC6, /* VERT_ATTRIB_GENERIC6 */ 96 VBO_ATTRIB_GENERIC7, /* VERT_ATTRIB_GENERIC7 */ 97 VBO_ATTRIB_GENERIC8, /* VERT_ATTRIB_GENERIC8 */ 98 VBO_ATTRIB_GENERIC9, /* VERT_ATTRIB_GENERIC9 */ 99 VBO_ATTRIB_GENERIC10, /* VERT_ATTRIB_GENERIC10 */ 100 VBO_ATTRIB_GENERIC11, /* VERT_ATTRIB_GENERIC11 */ 101 VBO_ATTRIB_GENERIC12, /* VERT_ATTRIB_GENERIC12 */ 102 VBO_ATTRIB_GENERIC13, /* VERT_ATTRIB_GENERIC13 */ 103 VBO_ATTRIB_GENERIC14, /* VERT_ATTRIB_GENERIC14 */ 104 VBO_ATTRIB_GENERIC15, /* VERT_ATTRIB_GENERIC15 */ 105 VBO_ATTRIB_EDGEFLAG, /* VERT_ATTRIB_EDGEFLAG */ 106 } 107}; 108 109 110void 111vbo_exec_init(struct gl_context *ctx) 112{ 113 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 114 115 vbo_exec_vtx_init(exec); 116 117 ctx->Driver.NeedFlush = 0; 118 ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END; 119 120 exec->eval.recalculate_maps = GL_TRUE; 121} 122 123 124void vbo_exec_destroy( struct gl_context *ctx ) 125{ 126 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 127 128 vbo_exec_vtx_destroy( exec ); 129} 130 131 132/** 133 * In some degenarate cases we can improve our ability to merge 134 * consecutive primitives. For example: 135 * glBegin(GL_LINE_STRIP); 136 * glVertex(1); 137 * glVertex(1); 138 * glEnd(); 139 * glBegin(GL_LINE_STRIP); 140 * glVertex(1); 141 * glVertex(1); 142 * glEnd(); 143 * Can be merged as a GL_LINES prim with four vertices. 144 * 145 * This function converts 2-vertex line strips/loops into GL_LINES, etc. 146 */ 147void 148vbo_try_prim_conversion(GLubyte *mode, unsigned *count) 149{ 150 if (*mode == GL_LINE_STRIP && *count == 2) { 151 /* convert 2-vertex line strip to a separate line */ 152 *mode = GL_LINES; 153 } else if ((*mode == GL_TRIANGLE_STRIP || *mode == GL_TRIANGLE_FAN) && 154 *count == 3) { 155 /* convert 3-vertex tri strip or fan to a separate triangle */ 156 *mode = GL_TRIANGLES; 157 } 158 159 /* Note: we can't convert a 4-vertex quad strip to a separate quad 160 * because the vertex ordering is different. We'd have to muck 161 * around in the vertex data to make it work. 162 */ 163} 164 165 166/** 167 * Function for merging two subsequent glBegin/glEnd draws. 168 * Return true if p1 was concatenated onto p0 (to discard p1 in the caller). 169 */ 170bool 171vbo_merge_draws(struct gl_context *ctx, bool in_dlist, 172 GLubyte mode0, GLubyte mode1, 173 unsigned start0, unsigned start1, 174 unsigned *count0, unsigned count1, 175 unsigned basevertex0, unsigned basevertex1, 176 bool *end0, bool begin1, bool end1) 177{ 178 /* The prim mode must match (ex: both GL_TRIANGLES) */ 179 if (mode0 != mode1) 180 return false; 181 182 /* p1's vertices must come right after p0 */ 183 if (start0 + *count0 != start1) 184 return false; 185 186 /* This checks whether mode is equal to any line primitive type, taking 187 * advantage of the fact that primitives types go from 0 to 14. 188 * 189 * Lines and lines with adjacency reset the line stipple pattern for every 190 * primitive, so draws can be merged even if line stippling is enabled. 191 */ 192 if ((1 << mode0) & 193 ((1 << GL_LINE_LOOP) | 194 (1 << GL_LINE_STRIP) | 195 (1 << GL_LINE_STRIP_ADJACENCY))) { 196 /* "begin" resets the line stipple pattern during line stipple emulation 197 * in tnl. 198 * 199 * StippleFlag can be unknown when compiling a display list. 200 * 201 * Other uses of "begin" are internal to the vbo module, and in those 202 * cases, "begin" is not used after merging draws. 203 */ 204 if (begin1 == 1 && (in_dlist || ctx->Line.StippleFlag)) 205 return false; 206 207 /* _mesa_prim::end is irrelevant at this point and is only used 208 * before this function is called. 209 */ 210 } 211 212 assert(basevertex0 == basevertex1); 213 214 switch (mode0) { 215 case GL_POINTS: 216 /* can always merge subsequent GL_POINTS primitives */ 217 break; 218 /* check independent primitives with no extra vertices */ 219 case GL_LINES: 220 if (*count0 % 2) 221 return false; 222 break; 223 case GL_TRIANGLES: 224 if (*count0 % 3) 225 return false; 226 break; 227 case GL_QUADS: 228 case GL_LINES_ADJACENCY: 229 if (*count0 % 4) 230 return false; 231 break; 232 case GL_TRIANGLES_ADJACENCY: 233 if (*count0 % 6) 234 return false; 235 break; 236 case GL_PATCHES: 237 /* "patch_vertices" can be unknown when compiling a display list. */ 238 if (in_dlist || 239 *count0 % ctx->TessCtrlProgram.patch_vertices) 240 return false; 241 break; 242 default: 243 return false; 244 } 245 246 /* Merge draws. */ 247 *count0 += count1; 248 *end0 = end1; 249 return true; 250} 251 252/** 253 * Copy zero, one or two vertices from the current vertex buffer into 254 * the temporary "copy" buffer. 255 * This is used when a single primitive overflows a vertex buffer and 256 * we need to continue the primitive in a new vertex buffer. 257 * The temporary "copy" buffer holds the vertices which need to get 258 * copied from the old buffer to the new one. 259 */ 260unsigned 261vbo_copy_vertices(struct gl_context *ctx, 262 GLenum mode, 263 unsigned start, unsigned *pcount, bool begin, 264 unsigned vertex_size, 265 bool in_dlist, 266 fi_type *dst, 267 const fi_type *src) 268{ 269 const unsigned count = *pcount; 270 unsigned copy = 0; 271 272 switch (mode) { 273 case GL_POINTS: 274 return 0; 275 case GL_LINES: 276 copy = count % 2; 277 break; 278 case GL_TRIANGLES: 279 copy = count % 3; 280 break; 281 case GL_QUADS: 282 case GL_LINES_ADJACENCY: 283 copy = count % 4; 284 break; 285 case GL_TRIANGLES_ADJACENCY: 286 copy = count % 6; 287 break; 288 case GL_LINE_STRIP: 289 copy = MIN2(1, count); 290 break; 291 case GL_LINE_STRIP_ADJACENCY: 292 /* We need to copy 3 vertices, because: 293 * Last strip: ---o---o---x (last line) 294 * Next strip: x---o---o--- (next line) 295 */ 296 copy = MIN2(3, count); 297 break; 298 case GL_PATCHES: 299 if (in_dlist) { 300 /* We don't know the value of GL_PATCH_VERTICES when compiling 301 * a display list. 302 * 303 * Fail an assertion in debug builds and use the value of 3 304 * in release builds, which is more likely than any other value. 305 */ 306 assert(!"patch_vertices is unknown"); 307 copy = count % 3; 308 } else { 309 copy = count % ctx->TessCtrlProgram.patch_vertices; 310 } 311 break; 312 case GL_LINE_LOOP: 313 if (!in_dlist && begin == 0) { 314 /* We're dealing with the second or later section of a split/wrapped 315 * GL_LINE_LOOP. Since we're converting line loops to line strips, 316 * we've already incremented the last_prim->start counter by one to 317 * skip the 0th vertex in the loop. We need to undo that (effectively 318 * subtract one from last_prim->start) so that we copy the 0th vertex 319 * to the next vertex buffer. 320 */ 321 assert(start > 0); 322 src -= vertex_size; 323 } 324 FALLTHROUGH; 325 case GL_TRIANGLE_FAN: 326 case GL_POLYGON: 327 if (count == 0) { 328 return 0; 329 } else if (count == 1) { 330 memcpy(dst, src + 0, vertex_size * sizeof(GLfloat)); 331 return 1; 332 } else { 333 memcpy(dst, src + 0, vertex_size * sizeof(GLfloat)); 334 memcpy(dst + vertex_size, src + (count - 1) * vertex_size, 335 vertex_size * sizeof(GLfloat)); 336 return 2; 337 } 338 case GL_TRIANGLE_STRIP: 339 /* Draw an even number of triangles to keep front/back facing the same. */ 340 *pcount -= count % 2; 341 FALLTHROUGH; 342 case GL_QUAD_STRIP: 343 if (count <= 1) 344 copy = count; 345 else 346 copy = 2 + (count % 2); 347 break; 348 case PRIM_OUTSIDE_BEGIN_END: 349 return 0; 350 case GL_TRIANGLE_STRIP_ADJACENCY: 351 /* TODO: Splitting tri strips with adjacency is too complicated. */ 352 default: 353 unreachable("Unexpected primitive type"); 354 return 0; 355 } 356 357 memcpy(dst, src + (count - copy) * vertex_size, 358 copy * vertex_size * sizeof(GLfloat)); 359 return copy; 360} 361