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