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