1 /* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 1999-2008 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 (at) vmware.com> 26 */ 27 28 #include <stdbool.h> 29 #include <stdio.h> 30 #include "main/glheader.h" 31 #include "main/bufferobj.h" 32 #include "main/compiler.h" 33 #include "main/context.h" 34 #include "main/enums.h" 35 #include "main/state.h" 36 #include "main/vtxfmt.h" 37 38 #include "vbo_context.h" 39 #include "vbo_noop.h" 40 41 42 static void 43 vbo_exec_debug_verts( struct vbo_exec_context *exec ) 44 { 45 GLuint count = exec->vtx.vert_count; 46 GLuint i; 47 48 printf("%s: %u vertices %d primitives, %d vertsize\n", 49 __func__, 50 count, 51 exec->vtx.prim_count, 52 exec->vtx.vertex_size); 53 54 for (i = 0 ; i < exec->vtx.prim_count ; i++) { 55 struct _mesa_prim *prim = &exec->vtx.prim[i]; 56 printf(" prim %d: %s%s %d..%d %s %s\n", 57 i, 58 _mesa_lookup_prim_by_nr(prim->mode), 59 prim->weak ? " (weak)" : "", 60 prim->start, 61 prim->start + prim->count, 62 prim->begin ? "BEGIN" : "(wrap)", 63 prim->end ? "END" : "(wrap)"); 64 } 65 } 66 67 68 /** 69 * Copy zero, one or two vertices from the current vertex buffer into 70 * the temporary "copy" buffer. 71 * This is used when a single primitive overflows a vertex buffer and 72 * we need to continue the primitive in a new vertex buffer. 73 * The temporary "copy" buffer holds the vertices which need to get 74 * copied from the old buffer to the new one. 75 */ 76 static GLuint 77 vbo_copy_vertices( struct vbo_exec_context *exec ) 78 { 79 struct _mesa_prim *last_prim = &exec->vtx.prim[exec->vtx.prim_count - 1]; 80 const GLuint nr = last_prim->count; 81 GLuint ovf, i; 82 const GLuint sz = exec->vtx.vertex_size; 83 fi_type *dst = exec->vtx.copied.buffer; 84 const fi_type *src = exec->vtx.buffer_map + last_prim->start * sz; 85 86 switch (exec->ctx->Driver.CurrentExecPrimitive) { 87 case GL_POINTS: 88 return 0; 89 case GL_LINES: 90 ovf = nr&1; 91 for (i = 0 ; i < ovf ; i++) 92 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) ); 93 return i; 94 case GL_TRIANGLES: 95 ovf = nr%3; 96 for (i = 0 ; i < ovf ; i++) 97 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) ); 98 return i; 99 case GL_QUADS: 100 ovf = nr&3; 101 for (i = 0 ; i < ovf ; i++) 102 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) ); 103 return i; 104 case GL_LINE_STRIP: 105 if (nr == 0) { 106 return 0; 107 } 108 else { 109 memcpy( dst, src+(nr-1)*sz, sz * sizeof(GLfloat) ); 110 return 1; 111 } 112 case GL_LINE_LOOP: 113 if (last_prim->begin == 0) { 114 /* We're dealing with the second or later section of a split/wrapped 115 * GL_LINE_LOOP. Since we're converting line loops to line strips, 116 * we've already increment the last_prim->start counter by one to 117 * skip the 0th vertex in the loop. We need to undo that (effectively 118 * subtract one from last_prim->start) so that we copy the 0th vertex 119 * to the next vertex buffer. 120 */ 121 assert(last_prim->start > 0); 122 src -= sz; 123 } 124 /* fall-through */ 125 case GL_TRIANGLE_FAN: 126 case GL_POLYGON: 127 if (nr == 0) { 128 return 0; 129 } 130 else if (nr == 1) { 131 memcpy( dst, src+0, sz * sizeof(GLfloat) ); 132 return 1; 133 } 134 else { 135 memcpy( dst, src+0, sz * sizeof(GLfloat) ); 136 memcpy( dst+sz, src+(nr-1)*sz, sz * sizeof(GLfloat) ); 137 return 2; 138 } 139 case GL_TRIANGLE_STRIP: 140 /* no parity issue, but need to make sure the tri is not drawn twice */ 141 if (nr & 1) { 142 last_prim->count--; 143 } 144 /* fallthrough */ 145 case GL_QUAD_STRIP: 146 switch (nr) { 147 case 0: 148 ovf = 0; 149 break; 150 case 1: 151 ovf = 1; 152 break; 153 default: 154 ovf = 2 + (nr & 1); 155 break; 156 } 157 for (i = 0 ; i < ovf ; i++) 158 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) ); 159 return i; 160 case PRIM_OUTSIDE_BEGIN_END: 161 return 0; 162 default: 163 assert(0); 164 return 0; 165 } 166 } 167 168 169 170 /* TODO: populate these as the vertex is defined: 171 */ 172 static void 173 vbo_exec_bind_arrays( struct gl_context *ctx ) 174 { 175 struct vbo_context *vbo = vbo_context(ctx); 176 struct vbo_exec_context *exec = &vbo->exec; 177 struct gl_vertex_array *arrays = exec->vtx.arrays; 178 const GLuint *map; 179 GLuint attr; 180 GLbitfield64 varying_inputs = 0x0; 181 bool swap_pos = false; 182 183 /* Install the default (ie Current) attributes first, then overlay 184 * all active ones. 185 */ 186 switch (get_program_mode(exec->ctx)) { 187 case VP_NONE: 188 for (attr = 0; attr < VERT_ATTRIB_FF_MAX; attr++) { 189 exec->vtx.inputs[attr] = &vbo->currval[VBO_ATTRIB_POS+attr]; 190 } 191 for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) { 192 assert(VERT_ATTRIB_GENERIC(attr) < ARRAY_SIZE(exec->vtx.inputs)); 193 exec->vtx.inputs[VERT_ATTRIB_GENERIC(attr)] = 194 &vbo->currval[VBO_ATTRIB_MAT_FRONT_AMBIENT+attr]; 195 } 196 map = vbo->map_vp_none; 197 break; 198 case VP_ARB: 199 for (attr = 0; attr < VERT_ATTRIB_FF_MAX; attr++) { 200 exec->vtx.inputs[attr] = &vbo->currval[VBO_ATTRIB_POS+attr]; 201 } 202 for (attr = 0; attr < VERT_ATTRIB_GENERIC_MAX; attr++) { 203 assert(VERT_ATTRIB_GENERIC(attr) < ARRAY_SIZE(exec->vtx.inputs)); 204 exec->vtx.inputs[VERT_ATTRIB_GENERIC(attr)] = 205 &vbo->currval[VBO_ATTRIB_GENERIC0+attr]; 206 } 207 map = vbo->map_vp_arb; 208 209 /* check if VERT_ATTRIB_POS is not read but VERT_BIT_GENERIC0 is read. 210 * In that case we effectively need to route the data from 211 * glVertexAttrib(0, val) calls to feed into the GENERIC0 input. 212 * The original state gets essentially restored below. 213 */ 214 if ((ctx->VertexProgram._Current->info.inputs_read & 215 VERT_BIT_POS) == 0 && 216 (ctx->VertexProgram._Current->info.inputs_read & 217 VERT_BIT_GENERIC0)) { 218 swap_pos = true; 219 exec->vtx.inputs[VERT_ATTRIB_GENERIC0] = exec->vtx.inputs[0]; 220 exec->vtx.attrsz[VERT_ATTRIB_GENERIC0] = exec->vtx.attrsz[0]; 221 exec->vtx.attrtype[VERT_ATTRIB_GENERIC0] = exec->vtx.attrtype[0]; 222 exec->vtx.attrptr[VERT_ATTRIB_GENERIC0] = exec->vtx.attrptr[0]; 223 exec->vtx.attrsz[0] = 0; 224 } 225 break; 226 default: 227 assert(0); 228 } 229 230 for (attr = 0; attr < VERT_ATTRIB_MAX ; attr++) { 231 const GLuint src = map[attr]; 232 233 if (exec->vtx.attrsz[src]) { 234 GLsizeiptr offset = (GLbyte *)exec->vtx.attrptr[src] - 235 (GLbyte *)exec->vtx.vertex; 236 237 /* override the default array set above */ 238 assert(attr < ARRAY_SIZE(exec->vtx.inputs)); 239 assert(attr < ARRAY_SIZE(exec->vtx.arrays)); /* arrays[] */ 240 exec->vtx.inputs[attr] = &arrays[attr]; 241 242 if (_mesa_is_bufferobj(exec->vtx.bufferobj)) { 243 /* a real buffer obj: Ptr is an offset, not a pointer */ 244 assert(exec->vtx.bufferobj->Mappings[MAP_INTERNAL].Pointer); 245 assert(offset >= 0); 246 arrays[attr].Ptr = (GLubyte *) 247 exec->vtx.bufferobj->Mappings[MAP_INTERNAL].Offset + offset; 248 } 249 else { 250 /* Ptr into ordinary app memory */ 251 arrays[attr].Ptr = (GLubyte *)exec->vtx.buffer_map + offset; 252 } 253 arrays[attr].Size = exec->vtx.attrsz[src]; 254 arrays[attr].StrideB = exec->vtx.vertex_size * sizeof(GLfloat); 255 arrays[attr].Type = exec->vtx.attrtype[src]; 256 arrays[attr].Integer = 257 vbo_attrtype_to_integer_flag(exec->vtx.attrtype[src]); 258 arrays[attr].Format = GL_RGBA; 259 arrays[attr]._ElementSize = arrays[attr].Size * sizeof(GLfloat); 260 _mesa_reference_buffer_object(ctx, 261 &arrays[attr].BufferObj, 262 exec->vtx.bufferobj); 263 264 varying_inputs |= VERT_BIT(attr); 265 } 266 } 267 268 /* In case we swapped the position and generic0 attribute. 269 * Restore the original setting of the vtx.* variables. 270 * They are still needed with the original order and settings in case 271 * of a split primitive. 272 */ 273 if (swap_pos) { 274 exec->vtx.attrsz[0] = exec->vtx.attrsz[VERT_ATTRIB_GENERIC0]; 275 exec->vtx.attrsz[VERT_ATTRIB_GENERIC0] = 0; 276 } 277 278 _mesa_set_varying_vp_inputs( ctx, varying_inputs ); 279 ctx->NewDriverState |= ctx->DriverFlags.NewArray; 280 } 281 282 283 /** 284 * Unmap the VBO. This is called before drawing. 285 */ 286 static void 287 vbo_exec_vtx_unmap( struct vbo_exec_context *exec ) 288 { 289 if (_mesa_is_bufferobj(exec->vtx.bufferobj)) { 290 struct gl_context *ctx = exec->ctx; 291 292 if (ctx->Driver.FlushMappedBufferRange) { 293 GLintptr offset = exec->vtx.buffer_used - 294 exec->vtx.bufferobj->Mappings[MAP_INTERNAL].Offset; 295 GLsizeiptr length = (exec->vtx.buffer_ptr - exec->vtx.buffer_map) * 296 sizeof(float); 297 298 if (length) 299 ctx->Driver.FlushMappedBufferRange(ctx, offset, length, 300 exec->vtx.bufferobj, 301 MAP_INTERNAL); 302 } 303 304 exec->vtx.buffer_used += (exec->vtx.buffer_ptr - 305 exec->vtx.buffer_map) * sizeof(float); 306 307 assert(exec->vtx.buffer_used <= VBO_VERT_BUFFER_SIZE); 308 assert(exec->vtx.buffer_ptr != NULL); 309 310 ctx->Driver.UnmapBuffer(ctx, exec->vtx.bufferobj, MAP_INTERNAL); 311 exec->vtx.buffer_map = NULL; 312 exec->vtx.buffer_ptr = NULL; 313 exec->vtx.max_vert = 0; 314 } 315 } 316 317 318 /** 319 * Map the vertex buffer to begin storing glVertex, glColor, etc data. 320 */ 321 void 322 vbo_exec_vtx_map( struct vbo_exec_context *exec ) 323 { 324 struct gl_context *ctx = exec->ctx; 325 const GLenum accessRange = GL_MAP_WRITE_BIT | /* for MapBufferRange */ 326 GL_MAP_INVALIDATE_RANGE_BIT | 327 GL_MAP_UNSYNCHRONIZED_BIT | 328 GL_MAP_FLUSH_EXPLICIT_BIT | 329 MESA_MAP_NOWAIT_BIT; 330 const GLenum usage = GL_STREAM_DRAW_ARB; 331 332 if (!_mesa_is_bufferobj(exec->vtx.bufferobj)) 333 return; 334 335 assert(!exec->vtx.buffer_map); 336 assert(!exec->vtx.buffer_ptr); 337 338 if (VBO_VERT_BUFFER_SIZE > exec->vtx.buffer_used + 1024) { 339 /* The VBO exists and there's room for more */ 340 if (exec->vtx.bufferobj->Size > 0) { 341 exec->vtx.buffer_map = 342 (fi_type *)ctx->Driver.MapBufferRange(ctx, 343 exec->vtx.buffer_used, 344 (VBO_VERT_BUFFER_SIZE - 345 exec->vtx.buffer_used), 346 accessRange, 347 exec->vtx.bufferobj, 348 MAP_INTERNAL); 349 exec->vtx.buffer_ptr = exec->vtx.buffer_map; 350 } 351 else { 352 exec->vtx.buffer_ptr = exec->vtx.buffer_map = NULL; 353 } 354 } 355 356 if (!exec->vtx.buffer_map) { 357 /* Need to allocate a new VBO */ 358 exec->vtx.buffer_used = 0; 359 360 if (ctx->Driver.BufferData(ctx, GL_ARRAY_BUFFER_ARB, 361 VBO_VERT_BUFFER_SIZE, 362 NULL, usage, 363 GL_MAP_WRITE_BIT | 364 GL_DYNAMIC_STORAGE_BIT | 365 GL_CLIENT_STORAGE_BIT, 366 exec->vtx.bufferobj)) { 367 /* buffer allocation worked, now map the buffer */ 368 exec->vtx.buffer_map = 369 (fi_type *)ctx->Driver.MapBufferRange(ctx, 370 0, VBO_VERT_BUFFER_SIZE, 371 accessRange, 372 exec->vtx.bufferobj, 373 MAP_INTERNAL); 374 } 375 else { 376 _mesa_error(ctx, GL_OUT_OF_MEMORY, "VBO allocation"); 377 exec->vtx.buffer_map = NULL; 378 } 379 } 380 381 exec->vtx.buffer_ptr = exec->vtx.buffer_map; 382 383 if (!exec->vtx.buffer_map) { 384 /* out of memory */ 385 _mesa_install_exec_vtxfmt( ctx, &exec->vtxfmt_noop ); 386 } 387 else { 388 if (_mesa_using_noop_vtxfmt(ctx->Exec)) { 389 /* The no-op functions are installed so switch back to regular 390 * functions. We do this test just to avoid frequent and needless 391 * calls to _mesa_install_exec_vtxfmt(). 392 */ 393 _mesa_install_exec_vtxfmt(ctx, &exec->vtxfmt); 394 } 395 } 396 397 if (0) 398 printf("map %d..\n", exec->vtx.buffer_used); 399 } 400 401 402 403 /** 404 * Execute the buffer and save copied verts. 405 * \param keep_unmapped if true, leave the VBO unmapped when we're done. 406 */ 407 void 408 vbo_exec_vtx_flush(struct vbo_exec_context *exec, GLboolean keepUnmapped) 409 { 410 if (0) 411 vbo_exec_debug_verts( exec ); 412 413 if (exec->vtx.prim_count && 414 exec->vtx.vert_count) { 415 416 exec->vtx.copied.nr = vbo_copy_vertices( exec ); 417 418 if (exec->vtx.copied.nr != exec->vtx.vert_count) { 419 struct gl_context *ctx = exec->ctx; 420 421 /* Before the update_state() as this may raise _NEW_VARYING_VP_INPUTS 422 * from _mesa_set_varying_vp_inputs(). 423 */ 424 vbo_exec_bind_arrays( ctx ); 425 426 if (ctx->NewState) 427 _mesa_update_state( ctx ); 428 429 if (_mesa_is_bufferobj(exec->vtx.bufferobj)) { 430 vbo_exec_vtx_unmap( exec ); 431 } 432 433 if (0) 434 printf("%s %d %d\n", __func__, exec->vtx.prim_count, 435 exec->vtx.vert_count); 436 437 vbo_context(ctx)->draw_prims( ctx, 438 exec->vtx.prim, 439 exec->vtx.prim_count, 440 NULL, 441 GL_TRUE, 442 0, 443 exec->vtx.vert_count - 1, 444 NULL, 0, NULL); 445 446 /* If using a real VBO, get new storage -- unless asked not to. 447 */ 448 if (_mesa_is_bufferobj(exec->vtx.bufferobj) && !keepUnmapped) { 449 vbo_exec_vtx_map( exec ); 450 } 451 } 452 } 453 454 /* May have to unmap explicitly if we didn't draw: 455 */ 456 if (keepUnmapped && 457 _mesa_is_bufferobj(exec->vtx.bufferobj) && 458 exec->vtx.buffer_map) { 459 vbo_exec_vtx_unmap( exec ); 460 } 461 462 if (keepUnmapped || exec->vtx.vertex_size == 0) 463 exec->vtx.max_vert = 0; 464 else 465 exec->vtx.max_vert = vbo_compute_max_verts(exec); 466 467 exec->vtx.buffer_ptr = exec->vtx.buffer_map; 468 exec->vtx.prim_count = 0; 469 exec->vtx.vert_count = 0; 470 } 471