1 2/* 3 * Mesa 3-D graphics library 4 * 5 * Copyright (C) 1999-2006 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 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 * OTHER DEALINGS IN THE SOFTWARE. 24 * 25 * Authors: 26 * Keith Whitwell <keithw@vmware.com> 27 */ 28 29/* Split indexed primitives with per-vertex copying. 30 */ 31 32#include <stdio.h> 33 34#include "main/glheader.h" 35#include "main/bufferobj.h" 36#include "main/imports.h" 37#include "main/glformats.h" 38#include "main/macros.h" 39#include "main/mtypes.h" 40#include "main/varray.h" 41#include "vbo/vbo.h" 42 43#include "t_split.h" 44#include "tnl.h" 45 46 47#define ELT_TABLE_SIZE 16 48 49/** 50 * Used for vertex-level splitting of indexed buffers. Note that 51 * non-indexed primitives may be converted to indexed in some cases 52 * (eg loops, fans) in order to use this splitting path. 53 */ 54struct copy_context { 55 struct gl_context *ctx; 56 const struct tnl_vertex_array *array; 57 const struct _mesa_prim *prim; 58 GLuint nr_prims; 59 const struct _mesa_index_buffer *ib; 60 tnl_draw_func draw; 61 62 const struct split_limits *limits; 63 64 struct { 65 GLuint attr; 66 GLuint size; 67 const struct tnl_vertex_array *array; 68 const GLubyte *src_ptr; 69 70 struct gl_vertex_buffer_binding dstbinding; 71 struct gl_array_attributes dstattribs; 72 73 } varying[VERT_ATTRIB_MAX]; 74 GLuint nr_varying; 75 76 struct tnl_vertex_array dstarray[VERT_ATTRIB_MAX]; 77 struct _mesa_index_buffer dstib; 78 79 GLuint *translated_elt_buf; 80 const GLuint *srcelt; 81 82 /** A baby hash table to avoid re-emitting (some) duplicate 83 * vertices when splitting indexed primitives. 84 */ 85 struct { 86 GLuint in; 87 GLuint out; 88 } vert_cache[ELT_TABLE_SIZE]; 89 90 GLuint vertex_size; 91 GLubyte *dstbuf; 92 GLubyte *dstptr; /**< dstptr == dstbuf + dstelt_max * vertsize */ 93 GLuint dstbuf_size; /**< in vertices */ 94 GLuint dstbuf_nr; /**< count of emitted vertices, also the largest value 95 * in dstelt. Our MaxIndex. 96 */ 97 98 GLuint *dstelt; 99 GLuint dstelt_nr; 100 GLuint dstelt_size; 101 102#define MAX_PRIM 32 103 struct _mesa_prim dstprim[MAX_PRIM]; 104 GLuint dstprim_nr; 105}; 106 107 108/** 109 * Shallow copy one vertex array to another. 110 */ 111static inline void 112copy_vertex_array(struct tnl_vertex_array *dst, 113 const struct tnl_vertex_array *src) 114{ 115 dst->VertexAttrib = src->VertexAttrib; 116 dst->BufferBinding = src->BufferBinding; 117} 118 119 120/** 121 * Starts returning true slightly before the buffer fills, to ensure 122 * that there is sufficient room for any remaining vertices to finish 123 * off the prim: 124 */ 125static GLboolean 126check_flush(struct copy_context *copy) 127{ 128 GLenum mode = copy->dstprim[copy->dstprim_nr].mode; 129 130 if (GL_TRIANGLE_STRIP == mode && 131 copy->dstelt_nr & 1) { /* see bug9962 */ 132 return GL_FALSE; 133 } 134 135 if (copy->dstbuf_nr + 4 > copy->dstbuf_size) 136 return GL_TRUE; 137 138 if (copy->dstelt_nr + 4 > copy->dstelt_size) 139 return GL_TRUE; 140 141 return GL_FALSE; 142} 143 144 145/** 146 * Dump the parameters/info for a vbo->draw() call. 147 */ 148static void 149dump_draw_info(struct gl_context *ctx, 150 const struct tnl_vertex_array *arrays, 151 const struct _mesa_prim *prims, 152 GLuint nr_prims, 153 const struct _mesa_index_buffer *ib, 154 GLuint min_index, 155 GLuint max_index) 156{ 157 GLuint i, j; 158 159 printf("VBO Draw:\n"); 160 for (i = 0; i < nr_prims; i++) { 161 printf("Prim %u of %u\n", i, nr_prims); 162 printf(" Prim mode 0x%x\n", prims[i].mode); 163 printf(" IB: %p\n", (void*) ib); 164 for (j = 0; j < VERT_ATTRIB_MAX; j++) { 165 const struct tnl_vertex_array *array = &arrays[j]; 166 const struct gl_vertex_buffer_binding *binding 167 = array->BufferBinding; 168 const struct gl_array_attributes *attrib = array->VertexAttrib; 169 const GLubyte *ptr = _mesa_vertex_attrib_address(attrib, binding); 170 printf(" array %d at %p:\n", j, (void*) &arrays[j]); 171 printf(" ptr %p, size %d, type 0x%x, stride %d\n", 172 ptr, attrib->Format.Size, attrib->Format.Type, binding->Stride); 173 if (0) { 174 GLint k = prims[i].start + prims[i].count - 1; 175 GLfloat *last = (GLfloat *) (ptr + binding->Stride * k); 176 printf(" last: %f %f %f\n", 177 last[0], last[1], last[2]); 178 } 179 } 180 } 181} 182 183 184static void 185flush(struct copy_context *copy) 186{ 187 struct gl_context *ctx = copy->ctx; 188 GLuint i; 189 190 /* Set some counters: 191 */ 192 copy->dstib.count = copy->dstelt_nr; 193 194#if 0 195 dump_draw_info(copy->ctx, 196 copy->dstarray, 197 copy->dstprim, 198 copy->dstprim_nr, 199 ©->dstib, 200 0, 201 copy->dstbuf_nr); 202#else 203 (void) dump_draw_info; 204#endif 205 206 copy->draw(ctx, 207 copy->dstarray, 208 copy->dstprim, 209 copy->dstprim_nr, 210 ©->dstib, 211 GL_TRUE, 212 0, 213 copy->dstbuf_nr - 1, 214 NULL, 0, NULL); 215 216 /* Reset all pointers: 217 */ 218 copy->dstprim_nr = 0; 219 copy->dstelt_nr = 0; 220 copy->dstbuf_nr = 0; 221 copy->dstptr = copy->dstbuf; 222 223 /* Clear the vertex cache: 224 */ 225 for (i = 0; i < ELT_TABLE_SIZE; i++) 226 copy->vert_cache[i].in = ~0; 227} 228 229 230/** 231 * Called at begin of each primitive during replay. 232 */ 233static void 234begin(struct copy_context *copy, GLenum mode, GLboolean begin_flag) 235{ 236 struct _mesa_prim *prim = ©->dstprim[copy->dstprim_nr]; 237 238 prim->mode = mode; 239 prim->begin = begin_flag; 240 prim->num_instances = 1; 241} 242 243 244/** 245 * Use a hashtable to attempt to identify recently-emitted vertices 246 * and avoid re-emitting them. 247 */ 248static GLuint 249elt(struct copy_context *copy, GLuint elt_idx) 250{ 251 GLuint elt = copy->srcelt[elt_idx] + copy->prim->basevertex; 252 GLuint slot = elt & (ELT_TABLE_SIZE-1); 253 254 /* Look up the incoming element in the vertex cache. Re-emit if 255 * necessary. 256 */ 257 if (copy->vert_cache[slot].in != elt) { 258 GLubyte *csr = copy->dstptr; 259 GLuint i; 260 261 for (i = 0; i < copy->nr_varying; i++) { 262 const struct tnl_vertex_array *srcarray = copy->varying[i].array; 263 const struct gl_vertex_buffer_binding* srcbinding 264 = srcarray->BufferBinding; 265 const GLubyte *srcptr 266 = copy->varying[i].src_ptr + elt * srcbinding->Stride; 267 268 memcpy(csr, srcptr, copy->varying[i].size); 269 csr += copy->varying[i].size; 270 271#ifdef NAN_CHECK 272 if (srcarray->Format.Type == GL_FLOAT) { 273 GLuint k; 274 GLfloat *f = (GLfloat *) srcptr; 275 for (k = 0; k < srcarray->Size; k++) { 276 assert(!IS_INF_OR_NAN(f[k])); 277 assert(f[k] <= 1.0e20 && f[k] >= -1.0e20); 278 } 279 } 280#endif 281 282 if (0) { 283 const GLuint *f = (const GLuint *)srcptr; 284 GLuint j; 285 printf(" varying %d: ", i); 286 for (j = 0; j < copy->varying[i].size / 4; j++) 287 printf("%x ", f[j]); 288 printf("\n"); 289 } 290 } 291 292 copy->vert_cache[slot].in = elt; 293 copy->vert_cache[slot].out = copy->dstbuf_nr++; 294 copy->dstptr += copy->vertex_size; 295 296 assert(csr == copy->dstptr); 297 assert(copy->dstptr == (copy->dstbuf + 298 copy->dstbuf_nr * copy->vertex_size)); 299 } 300 301 copy->dstelt[copy->dstelt_nr++] = copy->vert_cache[slot].out; 302 return check_flush(copy); 303} 304 305 306/** 307 * Called at end of each primitive during replay. 308 */ 309static void 310end(struct copy_context *copy, GLboolean end_flag) 311{ 312 struct _mesa_prim *prim = ©->dstprim[copy->dstprim_nr]; 313 314 prim->end = end_flag; 315 prim->count = copy->dstelt_nr - prim->start; 316 317 if (++copy->dstprim_nr == MAX_PRIM || check_flush(copy)) { 318 flush(copy); 319 } 320} 321 322 323static void 324replay_elts(struct copy_context *copy) 325{ 326 GLuint i, j, k; 327 GLboolean split; 328 329 for (i = 0; i < copy->nr_prims; i++) { 330 const struct _mesa_prim *prim = ©->prim[i]; 331 const GLuint start = prim->start; 332 GLuint first, incr; 333 334 switch (prim->mode) { 335 case GL_LINE_LOOP: 336 /* Convert to linestrip and emit the final vertex explicitly, 337 * but only in the resultant strip that requires it. 338 */ 339 j = 0; 340 while (j != prim->count) { 341 begin(copy, GL_LINE_STRIP, prim->begin && j == 0); 342 343 for (split = GL_FALSE; j != prim->count && !split; j++) 344 split = elt(copy, start + j); 345 346 if (j == prim->count) { 347 /* Done, emit final line. Split doesn't matter as 348 * it is always raised a bit early so we can emit 349 * the last verts if necessary! 350 */ 351 if (prim->end) 352 (void)elt(copy, start + 0); 353 354 end(copy, prim->end); 355 } 356 else { 357 /* Wrap 358 */ 359 assert(split); 360 end(copy, 0); 361 j--; 362 } 363 } 364 break; 365 366 case GL_TRIANGLE_FAN: 367 case GL_POLYGON: 368 j = 2; 369 while (j != prim->count) { 370 begin(copy, prim->mode, prim->begin && j == 0); 371 372 split = elt(copy, start+0); 373 assert(!split); 374 375 split = elt(copy, start+j-1); 376 assert(!split); 377 378 for (; j != prim->count && !split; j++) 379 split = elt(copy, start+j); 380 381 end(copy, prim->end && j == prim->count); 382 383 if (j != prim->count) { 384 /* Wrapped the primitive, need to repeat some vertices: 385 */ 386 j -= 1; 387 } 388 } 389 break; 390 391 default: 392 (void)_tnl_split_prim_inplace(prim->mode, &first, &incr); 393 394 j = 0; 395 while (j != prim->count) { 396 397 begin(copy, prim->mode, prim->begin && j == 0); 398 399 split = 0; 400 for (k = 0; k < first; k++, j++) 401 split |= elt(copy, start+j); 402 403 assert(!split); 404 405 for (; j != prim->count && !split;) 406 for (k = 0; k < incr; k++, j++) 407 split |= elt(copy, start+j); 408 409 end(copy, prim->end && j == prim->count); 410 411 if (j != prim->count) { 412 /* Wrapped the primitive, need to repeat some vertices: 413 */ 414 assert(j > first - incr); 415 j -= (first - incr); 416 } 417 } 418 break; 419 } 420 } 421 422 if (copy->dstprim_nr) 423 flush(copy); 424} 425 426 427static void 428replay_init(struct copy_context *copy) 429{ 430 struct gl_context *ctx = copy->ctx; 431 GLuint i; 432 GLuint offset; 433 const GLvoid *srcptr; 434 435 /* Make a list of varying attributes and their vbo's. Also 436 * calculate vertex size. 437 */ 438 copy->vertex_size = 0; 439 for (i = 0; i < VERT_ATTRIB_MAX; i++) { 440 const struct tnl_vertex_array *array = ©->array[i]; 441 const struct gl_vertex_buffer_binding *binding = array->BufferBinding; 442 443 if (binding->Stride == 0) { 444 copy_vertex_array(©->dstarray[i], array); 445 } 446 else { 447 const struct gl_array_attributes *attrib = array->VertexAttrib; 448 struct gl_buffer_object *vbo = binding->BufferObj; 449 const GLubyte *ptr = _mesa_vertex_attrib_address(attrib, binding); 450 GLuint j = copy->nr_varying++; 451 452 copy->varying[j].attr = i; 453 copy->varying[j].array = ©->array[i]; 454 copy->varying[j].size = attrib->Format._ElementSize; 455 copy->vertex_size += attrib->Format._ElementSize; 456 457 if (_mesa_is_bufferobj(vbo) && 458 !_mesa_bufferobj_mapped(vbo, MAP_INTERNAL)) 459 ctx->Driver.MapBufferRange(ctx, 0, vbo->Size, GL_MAP_READ_BIT, vbo, 460 MAP_INTERNAL); 461 462 copy->varying[j].src_ptr = 463 ADD_POINTERS(vbo->Mappings[MAP_INTERNAL].Pointer, ptr); 464 465 copy->dstarray[i].VertexAttrib = ©->varying[j].dstattribs; 466 copy->dstarray[i].BufferBinding = ©->varying[j].dstbinding; 467 } 468 } 469 470 /* There must always be an index buffer. Currently require the 471 * caller convert non-indexed prims to indexed. Could alternately 472 * do it internally. 473 */ 474 if (_mesa_is_bufferobj(copy->ib->obj) && 475 !_mesa_bufferobj_mapped(copy->ib->obj, MAP_INTERNAL)) 476 ctx->Driver.MapBufferRange(ctx, 0, copy->ib->obj->Size, GL_MAP_READ_BIT, 477 copy->ib->obj, MAP_INTERNAL); 478 479 srcptr = (const GLubyte *) 480 ADD_POINTERS(copy->ib->obj->Mappings[MAP_INTERNAL].Pointer, 481 copy->ib->ptr); 482 483 switch (copy->ib->index_size) { 484 case 1: 485 copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count); 486 copy->srcelt = copy->translated_elt_buf; 487 488 for (i = 0; i < copy->ib->count; i++) 489 copy->translated_elt_buf[i] = ((const GLubyte *)srcptr)[i]; 490 break; 491 492 case 2: 493 copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count); 494 copy->srcelt = copy->translated_elt_buf; 495 496 for (i = 0; i < copy->ib->count; i++) 497 copy->translated_elt_buf[i] = ((const GLushort *)srcptr)[i]; 498 break; 499 500 case 4: 501 copy->translated_elt_buf = NULL; 502 copy->srcelt = (const GLuint *)srcptr; 503 break; 504 } 505 506 /* Figure out the maximum allowed vertex buffer size: 507 */ 508 if (copy->vertex_size * copy->limits->max_verts <= copy->limits->max_vb_size) { 509 copy->dstbuf_size = copy->limits->max_verts; 510 } 511 else { 512 copy->dstbuf_size = copy->limits->max_vb_size / copy->vertex_size; 513 } 514 515 /* Allocate an output vertex buffer: 516 * 517 * XXX: This should be a VBO! 518 */ 519 copy->dstbuf = malloc(copy->dstbuf_size * copy->vertex_size); 520 copy->dstptr = copy->dstbuf; 521 522 /* Setup new vertex arrays to point into the output buffer: 523 */ 524 for (offset = 0, i = 0; i < copy->nr_varying; i++) { 525 const struct tnl_vertex_array *src = copy->varying[i].array; 526 const struct gl_array_attributes *srcattr = src->VertexAttrib; 527 struct tnl_vertex_array *dst = ©->dstarray[copy->varying[i].attr]; 528 struct gl_vertex_buffer_binding *dstbind = ©->varying[i].dstbinding; 529 struct gl_array_attributes *dstattr = ©->varying[i].dstattribs; 530 531 dstattr->Format = srcattr->Format; 532 dstattr->Ptr = copy->dstbuf + offset; 533 dstbind->Stride = copy->vertex_size; 534 dstbind->BufferObj = ctx->Shared->NullBufferObj; 535 dst->BufferBinding = dstbind; 536 dst->VertexAttrib = dstattr; 537 538 offset += copy->varying[i].size; 539 } 540 541 /* Allocate an output element list: 542 */ 543 copy->dstelt_size = MIN2(65536, copy->ib->count * 2 + 3); 544 copy->dstelt_size = MIN2(copy->dstelt_size, copy->limits->max_indices); 545 copy->dstelt = malloc(sizeof(GLuint) * copy->dstelt_size); 546 copy->dstelt_nr = 0; 547 548 /* Setup the new index buffer to point to the allocated element 549 * list: 550 */ 551 copy->dstib.count = 0; /* duplicates dstelt_nr */ 552 copy->dstib.index_size = 4; 553 copy->dstib.obj = ctx->Shared->NullBufferObj; 554 copy->dstib.ptr = copy->dstelt; 555} 556 557 558/** 559 * Free up everything allocated during split/replay. 560 */ 561static void 562replay_finish(struct copy_context *copy) 563{ 564 struct gl_context *ctx = copy->ctx; 565 GLuint i; 566 567 /* Free our vertex and index buffers */ 568 free(copy->translated_elt_buf); 569 free(copy->dstbuf); 570 free(copy->dstelt); 571 572 /* Unmap VBO's */ 573 for (i = 0; i < copy->nr_varying; i++) { 574 struct gl_buffer_object *vbo = 575 copy->varying[i].array->BufferBinding->BufferObj; 576 if (_mesa_is_bufferobj(vbo) && _mesa_bufferobj_mapped(vbo, MAP_INTERNAL)) 577 ctx->Driver.UnmapBuffer(ctx, vbo, MAP_INTERNAL); 578 } 579 580 /* Unmap index buffer */ 581 if (_mesa_is_bufferobj(copy->ib->obj) && 582 _mesa_bufferobj_mapped(copy->ib->obj, MAP_INTERNAL)) { 583 ctx->Driver.UnmapBuffer(ctx, copy->ib->obj, MAP_INTERNAL); 584 } 585} 586 587 588/** 589 * Split VBO into smaller pieces, draw the pieces. 590 */ 591void 592_tnl_split_copy(struct gl_context *ctx, 593 const struct tnl_vertex_array *arrays, 594 const struct _mesa_prim *prim, 595 GLuint nr_prims, 596 const struct _mesa_index_buffer *ib, 597 tnl_draw_func draw, 598 const struct split_limits *limits) 599{ 600 struct copy_context copy; 601 GLuint i, this_nr_prims; 602 603 for (i = 0; i < nr_prims;) { 604 /* Our SW TNL pipeline doesn't handle basevertex yet, so bind_indices 605 * will rebase the elements to the basevertex, and we'll only 606 * emit strings of prims with the same basevertex in one draw call. 607 */ 608 for (this_nr_prims = 1; i + this_nr_prims < nr_prims; 609 this_nr_prims++) { 610 if (prim[i].basevertex != prim[i + this_nr_prims].basevertex) 611 break; 612 } 613 614 memset(©, 0, sizeof(copy)); 615 616 /* Require indexed primitives: 617 */ 618 assert(ib); 619 620 copy.ctx = ctx; 621 copy.array = arrays; 622 copy.prim = &prim[i]; 623 copy.nr_prims = this_nr_prims; 624 copy.ib = ib; 625 copy.draw = draw; 626 copy.limits = limits; 627 628 /* Clear the vertex cache: 629 */ 630 for (i = 0; i < ELT_TABLE_SIZE; i++) 631 copy.vert_cache[i].in = ~0; 632 633 replay_init(©); 634 replay_elts(©); 635 replay_finish(©); 636 } 637} 638