vbo_exec_draw.c revision 298be2b028263b2c343a707662c6fbfa18293cb2
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.2 4 * 5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: 25 * Keith Whitwell <keith@tungstengraphics.com> 26 */ 27 28#include "main/glheader.h" 29#include "main/bufferobj.h" 30#include "main/context.h" 31#include "main/enums.h" 32#include "main/state.h" 33 34#include "vbo_context.h" 35 36 37#if FEATURE_beginend 38 39 40static void 41vbo_exec_debug_verts( struct vbo_exec_context *exec ) 42{ 43 GLuint count = exec->vtx.vert_count; 44 GLuint i; 45 46 printf("%s: %u vertices %d primitives, %d vertsize\n", 47 __FUNCTION__, 48 count, 49 exec->vtx.prim_count, 50 exec->vtx.vertex_size); 51 52 for (i = 0 ; i < exec->vtx.prim_count ; i++) { 53 struct _mesa_prim *prim = &exec->vtx.prim[i]; 54 printf(" prim %d: %s%s %d..%d %s %s\n", 55 i, 56 _mesa_lookup_prim_by_nr(prim->mode), 57 prim->weak ? " (weak)" : "", 58 prim->start, 59 prim->start + prim->count, 60 prim->begin ? "BEGIN" : "(wrap)", 61 prim->end ? "END" : "(wrap)"); 62 } 63} 64 65 66/* 67 * NOTE: Need to have calculated primitives by this point -- do it on the fly. 68 * NOTE: Old 'parity' issue is gone. 69 */ 70static GLuint 71vbo_copy_vertices( struct vbo_exec_context *exec ) 72{ 73 GLuint nr = exec->vtx.prim[exec->vtx.prim_count-1].count; 74 GLuint ovf, i; 75 GLuint sz = exec->vtx.vertex_size; 76 GLfloat *dst = exec->vtx.copied.buffer; 77 const GLfloat *src = (exec->vtx.buffer_map + 78 exec->vtx.prim[exec->vtx.prim_count-1].start * 79 exec->vtx.vertex_size); 80 81 82 switch (exec->ctx->Driver.CurrentExecPrimitive) { 83 case GL_POINTS: 84 return 0; 85 case GL_LINES: 86 ovf = nr&1; 87 for (i = 0 ; i < ovf ; i++) 88 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) ); 89 return i; 90 case GL_TRIANGLES: 91 ovf = nr%3; 92 for (i = 0 ; i < ovf ; i++) 93 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) ); 94 return i; 95 case GL_QUADS: 96 ovf = nr&3; 97 for (i = 0 ; i < ovf ; i++) 98 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) ); 99 return i; 100 case GL_LINE_STRIP: 101 if (nr == 0) { 102 return 0; 103 } 104 else { 105 memcpy( dst, src+(nr-1)*sz, sz * sizeof(GLfloat) ); 106 return 1; 107 } 108 case GL_LINE_LOOP: 109 case GL_TRIANGLE_FAN: 110 case GL_POLYGON: 111 if (nr == 0) { 112 return 0; 113 } 114 else if (nr == 1) { 115 memcpy( dst, src+0, sz * sizeof(GLfloat) ); 116 return 1; 117 } 118 else { 119 memcpy( dst, src+0, sz * sizeof(GLfloat) ); 120 memcpy( dst+sz, src+(nr-1)*sz, sz * sizeof(GLfloat) ); 121 return 2; 122 } 123 case GL_TRIANGLE_STRIP: 124 /* no parity issue, but need to make sure the tri is not drawn twice */ 125 if (nr & 1) { 126 exec->vtx.prim[exec->vtx.prim_count-1].count--; 127 } 128 /* fallthrough */ 129 case GL_QUAD_STRIP: 130 switch (nr) { 131 case 0: 132 ovf = 0; 133 break; 134 case 1: 135 ovf = 1; 136 break; 137 default: 138 ovf = 2 + (nr & 1); 139 break; 140 } 141 for (i = 0 ; i < ovf ; i++) 142 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) ); 143 return i; 144 case PRIM_OUTSIDE_BEGIN_END: 145 return 0; 146 default: 147 assert(0); 148 return 0; 149 } 150} 151 152 153 154/* TODO: populate these as the vertex is defined: 155 */ 156static void 157vbo_exec_bind_arrays( GLcontext *ctx ) 158{ 159 struct vbo_context *vbo = vbo_context(ctx); 160 struct vbo_exec_context *exec = &vbo->exec; 161 struct gl_client_array *arrays = exec->vtx.arrays; 162 const GLuint count = exec->vtx.vert_count; 163 const GLubyte *data = (GLubyte *) exec->vtx.buffer_map; 164 const GLuint *map; 165 GLuint attr; 166 GLbitfield varying_inputs = 0x0; 167 168 /* Install the default (ie Current) attributes first, then overlay 169 * all active ones. 170 */ 171 switch (get_program_mode(exec->ctx)) { 172 case VP_NONE: 173 for (attr = 0; attr < 16; attr++) { 174 exec->vtx.inputs[attr] = &vbo->legacy_currval[attr]; 175 } 176 for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) { 177 ASSERT(attr + 16 < Elements(exec->vtx.inputs)); 178 exec->vtx.inputs[attr + 16] = &vbo->mat_currval[attr]; 179 } 180 map = vbo->map_vp_none; 181 break; 182 case VP_NV: 183 case VP_ARB: 184 /* The aliasing of attributes for NV vertex programs has already 185 * occurred. NV vertex programs cannot access material values, 186 * nor attributes greater than VERT_ATTRIB_TEX7. 187 */ 188 for (attr = 0; attr < 16; attr++) { 189 exec->vtx.inputs[attr] = &vbo->legacy_currval[attr]; 190 ASSERT(attr + 16 < Elements(exec->vtx.inputs)); 191 exec->vtx.inputs[attr + 16] = &vbo->generic_currval[attr]; 192 } 193 map = vbo->map_vp_arb; 194 195 /* check if VERT_ATTRIB_POS is not read but VERT_BIT_GENERIC0 is read. 196 * In that case we effectively need to route the data from 197 * glVertexAttrib(0, val) calls to feed into the GENERIC0 input. 198 */ 199 if ((ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_POS) == 0 && 200 (ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_GENERIC0)) { 201 exec->vtx.inputs[16] = exec->vtx.inputs[0]; 202 exec->vtx.attrsz[16] = exec->vtx.attrsz[0]; 203 exec->vtx.attrptr[16] = exec->vtx.attrptr[0]; 204 exec->vtx.attrsz[0] = 0; 205 } 206 break; 207 default: 208 assert(0); 209 } 210 211 /* Make all active attributes (including edgeflag) available as 212 * arrays of floats. 213 */ 214 for (attr = 0; attr < VERT_ATTRIB_MAX ; attr++) { 215 const GLuint src = map[attr]; 216 217 if (exec->vtx.attrsz[src]) { 218 /* override the default array set above */ 219 ASSERT(attr < Elements(exec->vtx.inputs)); 220 ASSERT(attr < Elements(exec->vtx.arrays)); /* arrays[] */ 221 exec->vtx.inputs[attr] = &arrays[attr]; 222 223 if (_mesa_is_bufferobj(exec->vtx.bufferobj)) { 224 /* a real buffer obj: Ptr is an offset, not a pointer*/ 225 GLsizeiptr offset; 226 assert(exec->vtx.bufferobj->Pointer); /* buf should be mapped */ 227 offset = (GLbyte *) data - 228 (GLbyte *) exec->vtx.bufferobj->Pointer + 229 exec->vtx.bufferobj->Offset; 230 assert(offset >= 0); 231 arrays[attr].Ptr = (void *) offset; 232 } 233 else { 234 /* Ptr into ordinary app memory */ 235 arrays[attr].Ptr = (void *) data; 236 } 237 arrays[attr].Size = exec->vtx.attrsz[src]; 238 arrays[attr].StrideB = exec->vtx.vertex_size * sizeof(GLfloat); 239 arrays[attr].Stride = exec->vtx.vertex_size * sizeof(GLfloat); 240 arrays[attr].Type = GL_FLOAT; 241 arrays[attr].Format = GL_RGBA; 242 arrays[attr].Enabled = 1; 243 _mesa_reference_buffer_object(ctx, 244 &arrays[attr].BufferObj, 245 exec->vtx.bufferobj); 246 arrays[attr]._MaxElement = count; /* ??? */ 247 248 data += exec->vtx.attrsz[src] * sizeof(GLfloat); 249 varying_inputs |= 1 << attr; 250 } 251 } 252 253 _mesa_set_varying_vp_inputs( ctx, varying_inputs ); 254} 255 256 257static void 258vbo_exec_vtx_unmap( struct vbo_exec_context *exec ) 259{ 260 GLenum target = GL_ARRAY_BUFFER_ARB; 261 262 if (_mesa_is_bufferobj(exec->vtx.bufferobj)) { 263 GLcontext *ctx = exec->ctx; 264 265 if (ctx->Driver.FlushMappedBufferRange) { 266 GLintptr offset = exec->vtx.buffer_used - exec->vtx.bufferobj->Offset; 267 GLsizeiptr length = (exec->vtx.buffer_ptr - exec->vtx.buffer_map) * sizeof(float); 268 269 if (length) 270 ctx->Driver.FlushMappedBufferRange(ctx, target, 271 offset, length, 272 exec->vtx.bufferobj); 273 } 274 275 exec->vtx.buffer_used += (exec->vtx.buffer_ptr - 276 exec->vtx.buffer_map) * sizeof(float); 277 278 assert(exec->vtx.buffer_used <= VBO_VERT_BUFFER_SIZE); 279 assert(exec->vtx.buffer_ptr != NULL); 280 281 ctx->Driver.UnmapBuffer(ctx, target, exec->vtx.bufferobj); 282 exec->vtx.buffer_map = NULL; 283 exec->vtx.buffer_ptr = NULL; 284 exec->vtx.max_vert = 0; 285 } 286} 287 288 289void 290vbo_exec_vtx_map( struct vbo_exec_context *exec ) 291{ 292 GLcontext *ctx = exec->ctx; 293 const GLenum target = GL_ARRAY_BUFFER_ARB; 294 const GLenum access = GL_READ_WRITE_ARB; /* for MapBuffer */ 295 const GLenum accessRange = GL_MAP_WRITE_BIT | /* for MapBufferRange */ 296 GL_MAP_INVALIDATE_RANGE_BIT | 297 GL_MAP_UNSYNCHRONIZED_BIT | 298 GL_MAP_FLUSH_EXPLICIT_BIT | 299 MESA_MAP_NOWAIT_BIT; 300 const GLenum usage = GL_STREAM_DRAW_ARB; 301 302 if (!_mesa_is_bufferobj(exec->vtx.bufferobj)) 303 return; 304 305 if (exec->vtx.buffer_map != NULL) { 306 assert(0); 307 exec->vtx.buffer_map = NULL; 308 exec->vtx.buffer_ptr = NULL; 309 } 310 311 if (VBO_VERT_BUFFER_SIZE > exec->vtx.buffer_used + 1024 && 312 ctx->Driver.MapBufferRange) { 313 exec->vtx.buffer_map = 314 (GLfloat *)ctx->Driver.MapBufferRange(ctx, 315 target, 316 exec->vtx.buffer_used, 317 (VBO_VERT_BUFFER_SIZE - 318 exec->vtx.buffer_used), 319 accessRange, 320 exec->vtx.bufferobj); 321 exec->vtx.buffer_ptr = exec->vtx.buffer_map; 322 } 323 324 if (!exec->vtx.buffer_map) { 325 exec->vtx.buffer_used = 0; 326 327 ctx->Driver.BufferData(ctx, target, 328 VBO_VERT_BUFFER_SIZE, 329 NULL, usage, exec->vtx.bufferobj); 330 331 332 if (ctx->Driver.MapBufferRange) 333 exec->vtx.buffer_map = 334 (GLfloat *)ctx->Driver.MapBufferRange(ctx, target, 335 0, VBO_VERT_BUFFER_SIZE, 336 accessRange, 337 exec->vtx.bufferobj); 338 if (!exec->vtx.buffer_map) 339 exec->vtx.buffer_map = 340 (GLfloat *)ctx->Driver.MapBuffer(ctx, target, access, exec->vtx.bufferobj); 341 assert(exec->vtx.buffer_map); 342 exec->vtx.buffer_ptr = exec->vtx.buffer_map; 343 } 344 345 if (0) 346 printf("map %d..\n", exec->vtx.buffer_used); 347} 348 349 350 351/** 352 * Execute the buffer and save copied verts. 353 */ 354void 355vbo_exec_vtx_flush( struct vbo_exec_context *exec, GLboolean unmap ) 356{ 357 if (0) 358 vbo_exec_debug_verts( exec ); 359 360 if (exec->vtx.prim_count && 361 exec->vtx.vert_count) { 362 363 exec->vtx.copied.nr = vbo_copy_vertices( exec ); 364 365 if (exec->vtx.copied.nr != exec->vtx.vert_count) { 366 GLcontext *ctx = exec->ctx; 367 368 /* Before the update_state() as this may raise _NEW_ARRAY 369 * from _mesa_set_varying_vp_inputs(). 370 */ 371 vbo_exec_bind_arrays( ctx ); 372 373 if (ctx->NewState) 374 _mesa_update_state( ctx ); 375 376 if (_mesa_is_bufferobj(exec->vtx.bufferobj)) { 377 vbo_exec_vtx_unmap( exec ); 378 } 379 380 if (0) 381 printf("%s %d %d\n", __FUNCTION__, exec->vtx.prim_count, 382 exec->vtx.vert_count); 383 384 vbo_context(ctx)->draw_prims( ctx, 385 exec->vtx.inputs, 386 exec->vtx.prim, 387 exec->vtx.prim_count, 388 NULL, 389 GL_TRUE, 390 0, 391 exec->vtx.vert_count - 1); 392 393 /* If using a real VBO, get new storage -- unless asked not to. 394 */ 395 if (_mesa_is_bufferobj(exec->vtx.bufferobj) && !unmap) { 396 vbo_exec_vtx_map( exec ); 397 } 398 } 399 } 400 401 /* May have to unmap explicitly if we didn't draw: 402 */ 403 if (unmap && 404 _mesa_is_bufferobj(exec->vtx.bufferobj) && 405 exec->vtx.buffer_map) { 406 vbo_exec_vtx_unmap( exec ); 407 } 408 409 410 if (unmap || exec->vtx.vertex_size == 0) 411 exec->vtx.max_vert = 0; 412 else 413 exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) / 414 (exec->vtx.vertex_size * sizeof(GLfloat))); 415 416 exec->vtx.buffer_ptr = exec->vtx.buffer_map; 417 exec->vtx.prim_count = 0; 418 exec->vtx.vert_count = 0; 419} 420 421 422#endif /* FEATURE_beginend */ 423