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