101e04c3fSmrg 201e04c3fSmrg/* 301e04c3fSmrg * Mesa 3-D graphics library 401e04c3fSmrg * 501e04c3fSmrg * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 601e04c3fSmrg * 701e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 801e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 901e04c3fSmrg * to deal in the Software without restriction, including without limitation 1001e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1101e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the 1201e04c3fSmrg * Software is furnished to do so, subject to the following conditions: 1301e04c3fSmrg * 1401e04c3fSmrg * The above copyright notice and this permission notice shall be included 1501e04c3fSmrg * in all copies or substantial portions of the Software. 1601e04c3fSmrg * 1701e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 1801e04c3fSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1901e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 2001e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 2101e04c3fSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 2201e04c3fSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2301e04c3fSmrg * OTHER DEALINGS IN THE SOFTWARE. 2401e04c3fSmrg * 2501e04c3fSmrg * Authors: 2601e04c3fSmrg * Keith Whitwell <keithw@vmware.com> 2701e04c3fSmrg */ 2801e04c3fSmrg 2901e04c3fSmrg/* Split indexed primitives with per-vertex copying. 3001e04c3fSmrg */ 3101e04c3fSmrg 3201e04c3fSmrg#include <stdio.h> 3301e04c3fSmrg 3401e04c3fSmrg#include "main/glheader.h" 3501e04c3fSmrg#include "main/bufferobj.h" 367ec681f3Smrg 3701e04c3fSmrg#include "main/glformats.h" 3801e04c3fSmrg#include "main/macros.h" 3901e04c3fSmrg#include "main/mtypes.h" 4001e04c3fSmrg#include "main/varray.h" 4101e04c3fSmrg#include "vbo/vbo.h" 4201e04c3fSmrg 4301e04c3fSmrg#include "t_split.h" 4401e04c3fSmrg#include "tnl.h" 4501e04c3fSmrg 4601e04c3fSmrg 4701e04c3fSmrg#define ELT_TABLE_SIZE 16 4801e04c3fSmrg 4901e04c3fSmrg/** 5001e04c3fSmrg * Used for vertex-level splitting of indexed buffers. Note that 5101e04c3fSmrg * non-indexed primitives may be converted to indexed in some cases 5201e04c3fSmrg * (eg loops, fans) in order to use this splitting path. 5301e04c3fSmrg */ 5401e04c3fSmrgstruct copy_context { 5501e04c3fSmrg struct gl_context *ctx; 5601e04c3fSmrg const struct tnl_vertex_array *array; 5701e04c3fSmrg const struct _mesa_prim *prim; 5801e04c3fSmrg GLuint nr_prims; 5901e04c3fSmrg const struct _mesa_index_buffer *ib; 6001e04c3fSmrg tnl_draw_func draw; 6101e04c3fSmrg 6201e04c3fSmrg const struct split_limits *limits; 6301e04c3fSmrg 6401e04c3fSmrg struct { 6501e04c3fSmrg GLuint attr; 6601e04c3fSmrg GLuint size; 6701e04c3fSmrg const struct tnl_vertex_array *array; 6801e04c3fSmrg const GLubyte *src_ptr; 6901e04c3fSmrg 7001e04c3fSmrg struct gl_vertex_buffer_binding dstbinding; 7101e04c3fSmrg struct gl_array_attributes dstattribs; 7201e04c3fSmrg 7301e04c3fSmrg } varying[VERT_ATTRIB_MAX]; 7401e04c3fSmrg GLuint nr_varying; 7501e04c3fSmrg 7601e04c3fSmrg struct tnl_vertex_array dstarray[VERT_ATTRIB_MAX]; 7701e04c3fSmrg struct _mesa_index_buffer dstib; 7801e04c3fSmrg 7901e04c3fSmrg GLuint *translated_elt_buf; 8001e04c3fSmrg const GLuint *srcelt; 8101e04c3fSmrg 8201e04c3fSmrg /** A baby hash table to avoid re-emitting (some) duplicate 8301e04c3fSmrg * vertices when splitting indexed primitives. 8401e04c3fSmrg */ 8501e04c3fSmrg struct { 8601e04c3fSmrg GLuint in; 8701e04c3fSmrg GLuint out; 8801e04c3fSmrg } vert_cache[ELT_TABLE_SIZE]; 8901e04c3fSmrg 9001e04c3fSmrg GLuint vertex_size; 9101e04c3fSmrg GLubyte *dstbuf; 9201e04c3fSmrg GLubyte *dstptr; /**< dstptr == dstbuf + dstelt_max * vertsize */ 9301e04c3fSmrg GLuint dstbuf_size; /**< in vertices */ 9401e04c3fSmrg GLuint dstbuf_nr; /**< count of emitted vertices, also the largest value 9501e04c3fSmrg * in dstelt. Our MaxIndex. 9601e04c3fSmrg */ 9701e04c3fSmrg 9801e04c3fSmrg GLuint *dstelt; 9901e04c3fSmrg GLuint dstelt_nr; 10001e04c3fSmrg GLuint dstelt_size; 10101e04c3fSmrg 10201e04c3fSmrg#define MAX_PRIM 32 10301e04c3fSmrg struct _mesa_prim dstprim[MAX_PRIM]; 10401e04c3fSmrg GLuint dstprim_nr; 10501e04c3fSmrg}; 10601e04c3fSmrg 10701e04c3fSmrg 10801e04c3fSmrg/** 10901e04c3fSmrg * Shallow copy one vertex array to another. 11001e04c3fSmrg */ 11101e04c3fSmrgstatic inline void 11201e04c3fSmrgcopy_vertex_array(struct tnl_vertex_array *dst, 11301e04c3fSmrg const struct tnl_vertex_array *src) 11401e04c3fSmrg{ 11501e04c3fSmrg dst->VertexAttrib = src->VertexAttrib; 11601e04c3fSmrg dst->BufferBinding = src->BufferBinding; 11701e04c3fSmrg} 11801e04c3fSmrg 11901e04c3fSmrg 12001e04c3fSmrg/** 12101e04c3fSmrg * Starts returning true slightly before the buffer fills, to ensure 12201e04c3fSmrg * that there is sufficient room for any remaining vertices to finish 12301e04c3fSmrg * off the prim: 12401e04c3fSmrg */ 12501e04c3fSmrgstatic GLboolean 12601e04c3fSmrgcheck_flush(struct copy_context *copy) 12701e04c3fSmrg{ 12801e04c3fSmrg GLenum mode = copy->dstprim[copy->dstprim_nr].mode; 12901e04c3fSmrg 13001e04c3fSmrg if (GL_TRIANGLE_STRIP == mode && 13101e04c3fSmrg copy->dstelt_nr & 1) { /* see bug9962 */ 13201e04c3fSmrg return GL_FALSE; 13301e04c3fSmrg } 13401e04c3fSmrg 13501e04c3fSmrg if (copy->dstbuf_nr + 4 > copy->dstbuf_size) 13601e04c3fSmrg return GL_TRUE; 13701e04c3fSmrg 13801e04c3fSmrg if (copy->dstelt_nr + 4 > copy->dstelt_size) 13901e04c3fSmrg return GL_TRUE; 14001e04c3fSmrg 14101e04c3fSmrg return GL_FALSE; 14201e04c3fSmrg} 14301e04c3fSmrg 14401e04c3fSmrg 14501e04c3fSmrg/** 14601e04c3fSmrg * Dump the parameters/info for a vbo->draw() call. 14701e04c3fSmrg */ 14801e04c3fSmrgstatic void 1497ec681f3Smrgdump_draw_info(const struct tnl_vertex_array *arrays, 15001e04c3fSmrg const struct _mesa_prim *prims, 15101e04c3fSmrg GLuint nr_prims, 1527ec681f3Smrg const struct _mesa_index_buffer *ib) 15301e04c3fSmrg{ 15401e04c3fSmrg GLuint i, j; 15501e04c3fSmrg 15601e04c3fSmrg printf("VBO Draw:\n"); 15701e04c3fSmrg for (i = 0; i < nr_prims; i++) { 15801e04c3fSmrg printf("Prim %u of %u\n", i, nr_prims); 15901e04c3fSmrg printf(" Prim mode 0x%x\n", prims[i].mode); 16001e04c3fSmrg printf(" IB: %p\n", (void*) ib); 16101e04c3fSmrg for (j = 0; j < VERT_ATTRIB_MAX; j++) { 16201e04c3fSmrg const struct tnl_vertex_array *array = &arrays[j]; 16301e04c3fSmrg const struct gl_vertex_buffer_binding *binding 16401e04c3fSmrg = array->BufferBinding; 16501e04c3fSmrg const struct gl_array_attributes *attrib = array->VertexAttrib; 16601e04c3fSmrg const GLubyte *ptr = _mesa_vertex_attrib_address(attrib, binding); 16701e04c3fSmrg printf(" array %d at %p:\n", j, (void*) &arrays[j]); 16801e04c3fSmrg printf(" ptr %p, size %d, type 0x%x, stride %d\n", 169b9abf16eSmaya ptr, attrib->Format.Size, attrib->Format.Type, binding->Stride); 17001e04c3fSmrg if (0) { 17101e04c3fSmrg GLint k = prims[i].start + prims[i].count - 1; 17201e04c3fSmrg GLfloat *last = (GLfloat *) (ptr + binding->Stride * k); 17301e04c3fSmrg printf(" last: %f %f %f\n", 17401e04c3fSmrg last[0], last[1], last[2]); 17501e04c3fSmrg } 17601e04c3fSmrg } 17701e04c3fSmrg } 17801e04c3fSmrg} 17901e04c3fSmrg 18001e04c3fSmrg 18101e04c3fSmrgstatic void 18201e04c3fSmrgflush(struct copy_context *copy) 18301e04c3fSmrg{ 18401e04c3fSmrg struct gl_context *ctx = copy->ctx; 18501e04c3fSmrg GLuint i; 18601e04c3fSmrg 18701e04c3fSmrg /* Set some counters: 18801e04c3fSmrg */ 18901e04c3fSmrg copy->dstib.count = copy->dstelt_nr; 19001e04c3fSmrg 19101e04c3fSmrg#if 0 1927ec681f3Smrg dump_draw_info(copy->dstarray, 19301e04c3fSmrg copy->dstprim, 19401e04c3fSmrg copy->dstprim_nr, 1957ec681f3Smrg ©->dstib); 19601e04c3fSmrg#else 19701e04c3fSmrg (void) dump_draw_info; 19801e04c3fSmrg#endif 19901e04c3fSmrg 20001e04c3fSmrg copy->draw(ctx, 20101e04c3fSmrg copy->dstarray, 20201e04c3fSmrg copy->dstprim, 20301e04c3fSmrg copy->dstprim_nr, 20401e04c3fSmrg ©->dstib, 20501e04c3fSmrg GL_TRUE, 20601e04c3fSmrg 0, 20701e04c3fSmrg copy->dstbuf_nr - 1, 2087ec681f3Smrg 1, 2097ec681f3Smrg 0); 21001e04c3fSmrg 21101e04c3fSmrg /* Reset all pointers: 21201e04c3fSmrg */ 21301e04c3fSmrg copy->dstprim_nr = 0; 21401e04c3fSmrg copy->dstelt_nr = 0; 21501e04c3fSmrg copy->dstbuf_nr = 0; 21601e04c3fSmrg copy->dstptr = copy->dstbuf; 21701e04c3fSmrg 21801e04c3fSmrg /* Clear the vertex cache: 21901e04c3fSmrg */ 22001e04c3fSmrg for (i = 0; i < ELT_TABLE_SIZE; i++) 22101e04c3fSmrg copy->vert_cache[i].in = ~0; 22201e04c3fSmrg} 22301e04c3fSmrg 22401e04c3fSmrg 22501e04c3fSmrg/** 22601e04c3fSmrg * Called at begin of each primitive during replay. 22701e04c3fSmrg */ 22801e04c3fSmrgstatic void 22901e04c3fSmrgbegin(struct copy_context *copy, GLenum mode, GLboolean begin_flag) 23001e04c3fSmrg{ 23101e04c3fSmrg struct _mesa_prim *prim = ©->dstprim[copy->dstprim_nr]; 23201e04c3fSmrg 23301e04c3fSmrg prim->mode = mode; 23401e04c3fSmrg prim->begin = begin_flag; 23501e04c3fSmrg} 23601e04c3fSmrg 23701e04c3fSmrg 23801e04c3fSmrg/** 23901e04c3fSmrg * Use a hashtable to attempt to identify recently-emitted vertices 24001e04c3fSmrg * and avoid re-emitting them. 24101e04c3fSmrg */ 24201e04c3fSmrgstatic GLuint 24301e04c3fSmrgelt(struct copy_context *copy, GLuint elt_idx) 24401e04c3fSmrg{ 24501e04c3fSmrg GLuint elt = copy->srcelt[elt_idx] + copy->prim->basevertex; 24601e04c3fSmrg GLuint slot = elt & (ELT_TABLE_SIZE-1); 24701e04c3fSmrg 24801e04c3fSmrg /* Look up the incoming element in the vertex cache. Re-emit if 24901e04c3fSmrg * necessary. 25001e04c3fSmrg */ 25101e04c3fSmrg if (copy->vert_cache[slot].in != elt) { 25201e04c3fSmrg GLubyte *csr = copy->dstptr; 25301e04c3fSmrg GLuint i; 25401e04c3fSmrg 25501e04c3fSmrg for (i = 0; i < copy->nr_varying; i++) { 25601e04c3fSmrg const struct tnl_vertex_array *srcarray = copy->varying[i].array; 25701e04c3fSmrg const struct gl_vertex_buffer_binding* srcbinding 25801e04c3fSmrg = srcarray->BufferBinding; 25901e04c3fSmrg const GLubyte *srcptr 26001e04c3fSmrg = copy->varying[i].src_ptr + elt * srcbinding->Stride; 26101e04c3fSmrg 26201e04c3fSmrg memcpy(csr, srcptr, copy->varying[i].size); 26301e04c3fSmrg csr += copy->varying[i].size; 26401e04c3fSmrg 26501e04c3fSmrg#ifdef NAN_CHECK 266b9abf16eSmaya if (srcarray->Format.Type == GL_FLOAT) { 26701e04c3fSmrg GLuint k; 26801e04c3fSmrg GLfloat *f = (GLfloat *) srcptr; 26901e04c3fSmrg for (k = 0; k < srcarray->Size; k++) { 2707ec681f3Smrg assert(!util_is_inf_or_nan(f[k])); 27101e04c3fSmrg assert(f[k] <= 1.0e20 && f[k] >= -1.0e20); 27201e04c3fSmrg } 27301e04c3fSmrg } 27401e04c3fSmrg#endif 27501e04c3fSmrg 27601e04c3fSmrg if (0) { 27701e04c3fSmrg const GLuint *f = (const GLuint *)srcptr; 27801e04c3fSmrg GLuint j; 27901e04c3fSmrg printf(" varying %d: ", i); 28001e04c3fSmrg for (j = 0; j < copy->varying[i].size / 4; j++) 28101e04c3fSmrg printf("%x ", f[j]); 28201e04c3fSmrg printf("\n"); 28301e04c3fSmrg } 28401e04c3fSmrg } 28501e04c3fSmrg 28601e04c3fSmrg copy->vert_cache[slot].in = elt; 28701e04c3fSmrg copy->vert_cache[slot].out = copy->dstbuf_nr++; 28801e04c3fSmrg copy->dstptr += copy->vertex_size; 28901e04c3fSmrg 29001e04c3fSmrg assert(csr == copy->dstptr); 29101e04c3fSmrg assert(copy->dstptr == (copy->dstbuf + 29201e04c3fSmrg copy->dstbuf_nr * copy->vertex_size)); 29301e04c3fSmrg } 29401e04c3fSmrg 29501e04c3fSmrg copy->dstelt[copy->dstelt_nr++] = copy->vert_cache[slot].out; 29601e04c3fSmrg return check_flush(copy); 29701e04c3fSmrg} 29801e04c3fSmrg 29901e04c3fSmrg 30001e04c3fSmrg/** 30101e04c3fSmrg * Called at end of each primitive during replay. 30201e04c3fSmrg */ 30301e04c3fSmrgstatic void 30401e04c3fSmrgend(struct copy_context *copy, GLboolean end_flag) 30501e04c3fSmrg{ 30601e04c3fSmrg struct _mesa_prim *prim = ©->dstprim[copy->dstprim_nr]; 30701e04c3fSmrg 30801e04c3fSmrg prim->end = end_flag; 30901e04c3fSmrg prim->count = copy->dstelt_nr - prim->start; 31001e04c3fSmrg 31101e04c3fSmrg if (++copy->dstprim_nr == MAX_PRIM || check_flush(copy)) { 31201e04c3fSmrg flush(copy); 31301e04c3fSmrg } 31401e04c3fSmrg} 31501e04c3fSmrg 31601e04c3fSmrg 31701e04c3fSmrgstatic void 31801e04c3fSmrgreplay_elts(struct copy_context *copy) 31901e04c3fSmrg{ 32001e04c3fSmrg GLuint i, j, k; 32101e04c3fSmrg GLboolean split; 32201e04c3fSmrg 32301e04c3fSmrg for (i = 0; i < copy->nr_prims; i++) { 32401e04c3fSmrg const struct _mesa_prim *prim = ©->prim[i]; 32501e04c3fSmrg const GLuint start = prim->start; 32601e04c3fSmrg GLuint first, incr; 32701e04c3fSmrg 32801e04c3fSmrg switch (prim->mode) { 32901e04c3fSmrg case GL_LINE_LOOP: 33001e04c3fSmrg /* Convert to linestrip and emit the final vertex explicitly, 33101e04c3fSmrg * but only in the resultant strip that requires it. 33201e04c3fSmrg */ 33301e04c3fSmrg j = 0; 33401e04c3fSmrg while (j != prim->count) { 33501e04c3fSmrg begin(copy, GL_LINE_STRIP, prim->begin && j == 0); 33601e04c3fSmrg 33701e04c3fSmrg for (split = GL_FALSE; j != prim->count && !split; j++) 33801e04c3fSmrg split = elt(copy, start + j); 33901e04c3fSmrg 34001e04c3fSmrg if (j == prim->count) { 34101e04c3fSmrg /* Done, emit final line. Split doesn't matter as 34201e04c3fSmrg * it is always raised a bit early so we can emit 34301e04c3fSmrg * the last verts if necessary! 34401e04c3fSmrg */ 34501e04c3fSmrg if (prim->end) 34601e04c3fSmrg (void)elt(copy, start + 0); 34701e04c3fSmrg 34801e04c3fSmrg end(copy, prim->end); 34901e04c3fSmrg } 35001e04c3fSmrg else { 35101e04c3fSmrg /* Wrap 35201e04c3fSmrg */ 35301e04c3fSmrg assert(split); 35401e04c3fSmrg end(copy, 0); 35501e04c3fSmrg j--; 35601e04c3fSmrg } 35701e04c3fSmrg } 35801e04c3fSmrg break; 35901e04c3fSmrg 36001e04c3fSmrg case GL_TRIANGLE_FAN: 36101e04c3fSmrg case GL_POLYGON: 36201e04c3fSmrg j = 2; 36301e04c3fSmrg while (j != prim->count) { 36401e04c3fSmrg begin(copy, prim->mode, prim->begin && j == 0); 36501e04c3fSmrg 36601e04c3fSmrg split = elt(copy, start+0); 36701e04c3fSmrg assert(!split); 36801e04c3fSmrg 36901e04c3fSmrg split = elt(copy, start+j-1); 37001e04c3fSmrg assert(!split); 37101e04c3fSmrg 37201e04c3fSmrg for (; j != prim->count && !split; j++) 37301e04c3fSmrg split = elt(copy, start+j); 37401e04c3fSmrg 37501e04c3fSmrg end(copy, prim->end && j == prim->count); 37601e04c3fSmrg 37701e04c3fSmrg if (j != prim->count) { 37801e04c3fSmrg /* Wrapped the primitive, need to repeat some vertices: 37901e04c3fSmrg */ 38001e04c3fSmrg j -= 1; 38101e04c3fSmrg } 38201e04c3fSmrg } 38301e04c3fSmrg break; 38401e04c3fSmrg 38501e04c3fSmrg default: 38601e04c3fSmrg (void)_tnl_split_prim_inplace(prim->mode, &first, &incr); 38701e04c3fSmrg 38801e04c3fSmrg j = 0; 38901e04c3fSmrg while (j != prim->count) { 39001e04c3fSmrg 39101e04c3fSmrg begin(copy, prim->mode, prim->begin && j == 0); 39201e04c3fSmrg 39301e04c3fSmrg split = 0; 39401e04c3fSmrg for (k = 0; k < first; k++, j++) 39501e04c3fSmrg split |= elt(copy, start+j); 39601e04c3fSmrg 39701e04c3fSmrg assert(!split); 39801e04c3fSmrg 39901e04c3fSmrg for (; j != prim->count && !split;) 40001e04c3fSmrg for (k = 0; k < incr; k++, j++) 40101e04c3fSmrg split |= elt(copy, start+j); 40201e04c3fSmrg 40301e04c3fSmrg end(copy, prim->end && j == prim->count); 40401e04c3fSmrg 40501e04c3fSmrg if (j != prim->count) { 40601e04c3fSmrg /* Wrapped the primitive, need to repeat some vertices: 40701e04c3fSmrg */ 40801e04c3fSmrg assert(j > first - incr); 40901e04c3fSmrg j -= (first - incr); 41001e04c3fSmrg } 41101e04c3fSmrg } 41201e04c3fSmrg break; 41301e04c3fSmrg } 41401e04c3fSmrg } 41501e04c3fSmrg 41601e04c3fSmrg if (copy->dstprim_nr) 41701e04c3fSmrg flush(copy); 41801e04c3fSmrg} 41901e04c3fSmrg 42001e04c3fSmrg 42101e04c3fSmrgstatic void 42201e04c3fSmrgreplay_init(struct copy_context *copy) 42301e04c3fSmrg{ 42401e04c3fSmrg struct gl_context *ctx = copy->ctx; 42501e04c3fSmrg GLuint i; 42601e04c3fSmrg GLuint offset; 42701e04c3fSmrg const GLvoid *srcptr; 42801e04c3fSmrg 42901e04c3fSmrg /* Make a list of varying attributes and their vbo's. Also 43001e04c3fSmrg * calculate vertex size. 43101e04c3fSmrg */ 43201e04c3fSmrg copy->vertex_size = 0; 43301e04c3fSmrg for (i = 0; i < VERT_ATTRIB_MAX; i++) { 43401e04c3fSmrg const struct tnl_vertex_array *array = ©->array[i]; 43501e04c3fSmrg const struct gl_vertex_buffer_binding *binding = array->BufferBinding; 43601e04c3fSmrg 43701e04c3fSmrg if (binding->Stride == 0) { 43801e04c3fSmrg copy_vertex_array(©->dstarray[i], array); 43901e04c3fSmrg } 44001e04c3fSmrg else { 44101e04c3fSmrg const struct gl_array_attributes *attrib = array->VertexAttrib; 44201e04c3fSmrg struct gl_buffer_object *vbo = binding->BufferObj; 44301e04c3fSmrg const GLubyte *ptr = _mesa_vertex_attrib_address(attrib, binding); 44401e04c3fSmrg GLuint j = copy->nr_varying++; 44501e04c3fSmrg 44601e04c3fSmrg copy->varying[j].attr = i; 44701e04c3fSmrg copy->varying[j].array = ©->array[i]; 448b9abf16eSmaya copy->varying[j].size = attrib->Format._ElementSize; 449b9abf16eSmaya copy->vertex_size += attrib->Format._ElementSize; 45001e04c3fSmrg 4517ec681f3Smrg if (vbo) { 4527ec681f3Smrg if (!_mesa_bufferobj_mapped(vbo, MAP_INTERNAL)) { 4537ec681f3Smrg ctx->Driver.MapBufferRange(ctx, 0, vbo->Size, GL_MAP_READ_BIT, vbo, 4547ec681f3Smrg MAP_INTERNAL); 4557ec681f3Smrg } 45601e04c3fSmrg 4577ec681f3Smrg copy->varying[j].src_ptr = 4587ec681f3Smrg ADD_POINTERS(vbo->Mappings[MAP_INTERNAL].Pointer, ptr); 4597ec681f3Smrg } else { 4607ec681f3Smrg copy->varying[j].src_ptr = ptr; 4617ec681f3Smrg } 46201e04c3fSmrg 46301e04c3fSmrg copy->dstarray[i].VertexAttrib = ©->varying[j].dstattribs; 46401e04c3fSmrg copy->dstarray[i].BufferBinding = ©->varying[j].dstbinding; 46501e04c3fSmrg } 46601e04c3fSmrg } 46701e04c3fSmrg 46801e04c3fSmrg /* There must always be an index buffer. Currently require the 46901e04c3fSmrg * caller convert non-indexed prims to indexed. Could alternately 47001e04c3fSmrg * do it internally. 47101e04c3fSmrg */ 4727ec681f3Smrg if (copy->ib->obj) { 4737ec681f3Smrg if (!_mesa_bufferobj_mapped(copy->ib->obj, MAP_INTERNAL)) 4747ec681f3Smrg ctx->Driver.MapBufferRange(ctx, 0, copy->ib->obj->Size, GL_MAP_READ_BIT, 4757ec681f3Smrg copy->ib->obj, MAP_INTERNAL); 4767ec681f3Smrg 4777ec681f3Smrg srcptr = (const GLubyte *) 4787ec681f3Smrg ADD_POINTERS(copy->ib->obj->Mappings[MAP_INTERNAL].Pointer, 4797ec681f3Smrg copy->ib->ptr); 4807ec681f3Smrg } else 4817ec681f3Smrg srcptr = copy->ib->ptr; 4827ec681f3Smrg 4837ec681f3Smrg switch (copy->ib->index_size_shift) { 4847ec681f3Smrg case 0: 48501e04c3fSmrg copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count); 48601e04c3fSmrg copy->srcelt = copy->translated_elt_buf; 48701e04c3fSmrg 48801e04c3fSmrg for (i = 0; i < copy->ib->count; i++) 48901e04c3fSmrg copy->translated_elt_buf[i] = ((const GLubyte *)srcptr)[i]; 49001e04c3fSmrg break; 49101e04c3fSmrg 4927ec681f3Smrg case 1: 49301e04c3fSmrg copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count); 49401e04c3fSmrg copy->srcelt = copy->translated_elt_buf; 49501e04c3fSmrg 49601e04c3fSmrg for (i = 0; i < copy->ib->count; i++) 49701e04c3fSmrg copy->translated_elt_buf[i] = ((const GLushort *)srcptr)[i]; 49801e04c3fSmrg break; 49901e04c3fSmrg 5007ec681f3Smrg case 2: 50101e04c3fSmrg copy->translated_elt_buf = NULL; 50201e04c3fSmrg copy->srcelt = (const GLuint *)srcptr; 50301e04c3fSmrg break; 50401e04c3fSmrg } 50501e04c3fSmrg 50601e04c3fSmrg /* Figure out the maximum allowed vertex buffer size: 50701e04c3fSmrg */ 50801e04c3fSmrg if (copy->vertex_size * copy->limits->max_verts <= copy->limits->max_vb_size) { 50901e04c3fSmrg copy->dstbuf_size = copy->limits->max_verts; 51001e04c3fSmrg } 51101e04c3fSmrg else { 51201e04c3fSmrg copy->dstbuf_size = copy->limits->max_vb_size / copy->vertex_size; 51301e04c3fSmrg } 51401e04c3fSmrg 51501e04c3fSmrg /* Allocate an output vertex buffer: 51601e04c3fSmrg * 51701e04c3fSmrg * XXX: This should be a VBO! 51801e04c3fSmrg */ 51901e04c3fSmrg copy->dstbuf = malloc(copy->dstbuf_size * copy->vertex_size); 52001e04c3fSmrg copy->dstptr = copy->dstbuf; 52101e04c3fSmrg 52201e04c3fSmrg /* Setup new vertex arrays to point into the output buffer: 52301e04c3fSmrg */ 52401e04c3fSmrg for (offset = 0, i = 0; i < copy->nr_varying; i++) { 52501e04c3fSmrg const struct tnl_vertex_array *src = copy->varying[i].array; 52601e04c3fSmrg const struct gl_array_attributes *srcattr = src->VertexAttrib; 52701e04c3fSmrg struct tnl_vertex_array *dst = ©->dstarray[copy->varying[i].attr]; 52801e04c3fSmrg struct gl_vertex_buffer_binding *dstbind = ©->varying[i].dstbinding; 52901e04c3fSmrg struct gl_array_attributes *dstattr = ©->varying[i].dstattribs; 53001e04c3fSmrg 531b9abf16eSmaya dstattr->Format = srcattr->Format; 53201e04c3fSmrg dstattr->Ptr = copy->dstbuf + offset; 533b9abf16eSmaya dstbind->Stride = copy->vertex_size; 5347ec681f3Smrg dstbind->BufferObj = NULL; 53501e04c3fSmrg dst->BufferBinding = dstbind; 53601e04c3fSmrg dst->VertexAttrib = dstattr; 53701e04c3fSmrg 53801e04c3fSmrg offset += copy->varying[i].size; 53901e04c3fSmrg } 54001e04c3fSmrg 54101e04c3fSmrg /* Allocate an output element list: 54201e04c3fSmrg */ 54301e04c3fSmrg copy->dstelt_size = MIN2(65536, copy->ib->count * 2 + 3); 54401e04c3fSmrg copy->dstelt_size = MIN2(copy->dstelt_size, copy->limits->max_indices); 54501e04c3fSmrg copy->dstelt = malloc(sizeof(GLuint) * copy->dstelt_size); 54601e04c3fSmrg copy->dstelt_nr = 0; 54701e04c3fSmrg 54801e04c3fSmrg /* Setup the new index buffer to point to the allocated element 54901e04c3fSmrg * list: 55001e04c3fSmrg */ 55101e04c3fSmrg copy->dstib.count = 0; /* duplicates dstelt_nr */ 5527ec681f3Smrg copy->dstib.index_size_shift = 2; 5537ec681f3Smrg copy->dstib.obj = NULL; 55401e04c3fSmrg copy->dstib.ptr = copy->dstelt; 55501e04c3fSmrg} 55601e04c3fSmrg 55701e04c3fSmrg 55801e04c3fSmrg/** 55901e04c3fSmrg * Free up everything allocated during split/replay. 56001e04c3fSmrg */ 56101e04c3fSmrgstatic void 56201e04c3fSmrgreplay_finish(struct copy_context *copy) 56301e04c3fSmrg{ 56401e04c3fSmrg struct gl_context *ctx = copy->ctx; 56501e04c3fSmrg GLuint i; 56601e04c3fSmrg 56701e04c3fSmrg /* Free our vertex and index buffers */ 56801e04c3fSmrg free(copy->translated_elt_buf); 56901e04c3fSmrg free(copy->dstbuf); 57001e04c3fSmrg free(copy->dstelt); 57101e04c3fSmrg 57201e04c3fSmrg /* Unmap VBO's */ 57301e04c3fSmrg for (i = 0; i < copy->nr_varying; i++) { 57401e04c3fSmrg struct gl_buffer_object *vbo = 57501e04c3fSmrg copy->varying[i].array->BufferBinding->BufferObj; 5767ec681f3Smrg if (vbo && _mesa_bufferobj_mapped(vbo, MAP_INTERNAL)) 57701e04c3fSmrg ctx->Driver.UnmapBuffer(ctx, vbo, MAP_INTERNAL); 57801e04c3fSmrg } 57901e04c3fSmrg 58001e04c3fSmrg /* Unmap index buffer */ 5817ec681f3Smrg if (copy->ib->obj && 58201e04c3fSmrg _mesa_bufferobj_mapped(copy->ib->obj, MAP_INTERNAL)) { 58301e04c3fSmrg ctx->Driver.UnmapBuffer(ctx, copy->ib->obj, MAP_INTERNAL); 58401e04c3fSmrg } 58501e04c3fSmrg} 58601e04c3fSmrg 58701e04c3fSmrg 58801e04c3fSmrg/** 58901e04c3fSmrg * Split VBO into smaller pieces, draw the pieces. 59001e04c3fSmrg */ 59101e04c3fSmrgvoid 59201e04c3fSmrg_tnl_split_copy(struct gl_context *ctx, 59301e04c3fSmrg const struct tnl_vertex_array *arrays, 59401e04c3fSmrg const struct _mesa_prim *prim, 59501e04c3fSmrg GLuint nr_prims, 59601e04c3fSmrg const struct _mesa_index_buffer *ib, 59701e04c3fSmrg tnl_draw_func draw, 59801e04c3fSmrg const struct split_limits *limits) 59901e04c3fSmrg{ 60001e04c3fSmrg struct copy_context copy; 60101e04c3fSmrg GLuint i, this_nr_prims; 60201e04c3fSmrg 60301e04c3fSmrg for (i = 0; i < nr_prims;) { 60401e04c3fSmrg /* Our SW TNL pipeline doesn't handle basevertex yet, so bind_indices 60501e04c3fSmrg * will rebase the elements to the basevertex, and we'll only 60601e04c3fSmrg * emit strings of prims with the same basevertex in one draw call. 60701e04c3fSmrg */ 60801e04c3fSmrg for (this_nr_prims = 1; i + this_nr_prims < nr_prims; 60901e04c3fSmrg this_nr_prims++) { 61001e04c3fSmrg if (prim[i].basevertex != prim[i + this_nr_prims].basevertex) 61101e04c3fSmrg break; 61201e04c3fSmrg } 61301e04c3fSmrg 61401e04c3fSmrg memset(©, 0, sizeof(copy)); 61501e04c3fSmrg 61601e04c3fSmrg /* Require indexed primitives: 61701e04c3fSmrg */ 61801e04c3fSmrg assert(ib); 61901e04c3fSmrg 62001e04c3fSmrg copy.ctx = ctx; 62101e04c3fSmrg copy.array = arrays; 62201e04c3fSmrg copy.prim = &prim[i]; 62301e04c3fSmrg copy.nr_prims = this_nr_prims; 62401e04c3fSmrg copy.ib = ib; 62501e04c3fSmrg copy.draw = draw; 62601e04c3fSmrg copy.limits = limits; 62701e04c3fSmrg 62801e04c3fSmrg /* Clear the vertex cache: 62901e04c3fSmrg */ 63001e04c3fSmrg for (i = 0; i < ELT_TABLE_SIZE; i++) 63101e04c3fSmrg copy.vert_cache[i].in = ~0; 63201e04c3fSmrg 63301e04c3fSmrg replay_init(©); 63401e04c3fSmrg replay_elts(©); 63501e04c3fSmrg replay_finish(©); 63601e04c3fSmrg } 63701e04c3fSmrg} 638