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