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 3001e04c3fSmrg#include "main/mtypes.h" 3101e04c3fSmrg#include "main/macros.h" 3201e04c3fSmrg#include "main/enums.h" 3301e04c3fSmrg#include "vbo/vbo.h" 3401e04c3fSmrg 3501e04c3fSmrg#include "t_split.h" 3601e04c3fSmrg 3701e04c3fSmrg 3801e04c3fSmrg#define MAX_PRIM 32 3901e04c3fSmrg 4001e04c3fSmrg/* Used for splitting without copying. No attempt is made to handle 4101e04c3fSmrg * too large indexed vertex buffers: In general you need to copy to do 4201e04c3fSmrg * that. 4301e04c3fSmrg */ 4401e04c3fSmrgstruct split_context { 4501e04c3fSmrg struct gl_context *ctx; 4601e04c3fSmrg const struct tnl_vertex_array *array; 4701e04c3fSmrg const struct _mesa_prim *prim; 4801e04c3fSmrg GLuint nr_prims; 4901e04c3fSmrg const struct _mesa_index_buffer *ib; 5001e04c3fSmrg GLuint min_index; 5101e04c3fSmrg GLuint max_index; 527ec681f3Smrg GLuint num_instances; 537ec681f3Smrg GLuint base_instance; 5401e04c3fSmrg tnl_draw_func draw; 5501e04c3fSmrg 5601e04c3fSmrg const struct split_limits *limits; 5701e04c3fSmrg GLuint limit; 5801e04c3fSmrg 5901e04c3fSmrg struct _mesa_prim dstprim[MAX_PRIM]; 6001e04c3fSmrg GLuint dstprim_nr; 6101e04c3fSmrg}; 6201e04c3fSmrg 6301e04c3fSmrg 6401e04c3fSmrg 6501e04c3fSmrg 6601e04c3fSmrgstatic void 6701e04c3fSmrgflush_vertex( struct split_context *split) 6801e04c3fSmrg{ 6901e04c3fSmrg struct gl_context *ctx = split->ctx; 7001e04c3fSmrg struct _mesa_index_buffer ib; 7101e04c3fSmrg GLuint i; 7201e04c3fSmrg 7301e04c3fSmrg if (!split->dstprim_nr) 7401e04c3fSmrg return; 7501e04c3fSmrg 7601e04c3fSmrg if (split->ib) { 7701e04c3fSmrg ib = *split->ib; 7801e04c3fSmrg 7901e04c3fSmrg ib.count = split->max_index - split->min_index + 1; 8001e04c3fSmrg ib.ptr = (const void *)((const char *)ib.ptr + 817ec681f3Smrg (split->min_index << ib.index_size_shift)); 8201e04c3fSmrg 8301e04c3fSmrg /* Rebase the primitives to save index buffer entries. */ 8401e04c3fSmrg for (i = 0; i < split->dstprim_nr; i++) 8501e04c3fSmrg split->dstprim[i].start -= split->min_index; 8601e04c3fSmrg } 8701e04c3fSmrg 8801e04c3fSmrg assert(split->max_index >= split->min_index); 8901e04c3fSmrg 9001e04c3fSmrg split->draw(ctx, 9101e04c3fSmrg split->array, 9201e04c3fSmrg split->dstprim, 9301e04c3fSmrg split->dstprim_nr, 9401e04c3fSmrg split->ib ? &ib : NULL, 9501e04c3fSmrg !split->ib, 9601e04c3fSmrg split->min_index, 9701e04c3fSmrg split->max_index, 987ec681f3Smrg split->num_instances, 997ec681f3Smrg split->base_instance); 10001e04c3fSmrg 10101e04c3fSmrg split->dstprim_nr = 0; 10201e04c3fSmrg split->min_index = ~0; 10301e04c3fSmrg split->max_index = 0; 10401e04c3fSmrg} 10501e04c3fSmrg 10601e04c3fSmrg 10701e04c3fSmrgstatic struct _mesa_prim * 10801e04c3fSmrgnext_outprim(struct split_context *split) 10901e04c3fSmrg{ 11001e04c3fSmrg if (split->dstprim_nr == MAX_PRIM-1) { 11101e04c3fSmrg flush_vertex(split); 11201e04c3fSmrg } 11301e04c3fSmrg 11401e04c3fSmrg { 11501e04c3fSmrg struct _mesa_prim *prim = &split->dstprim[split->dstprim_nr++]; 11601e04c3fSmrg memset(prim, 0, sizeof(*prim)); 11701e04c3fSmrg return prim; 11801e04c3fSmrg } 11901e04c3fSmrg} 12001e04c3fSmrg 12101e04c3fSmrg 12201e04c3fSmrgstatic void 12301e04c3fSmrgupdate_index_bounds(struct split_context *split, 12401e04c3fSmrg const struct _mesa_prim *prim) 12501e04c3fSmrg{ 12601e04c3fSmrg split->min_index = MIN2(split->min_index, prim->start); 12701e04c3fSmrg split->max_index = MAX2(split->max_index, prim->start + prim->count - 1); 12801e04c3fSmrg} 12901e04c3fSmrg 13001e04c3fSmrg 13101e04c3fSmrg/* Return the maximum amount of vertices that can be emitted for a 13201e04c3fSmrg * primitive starting at 'prim->start', depending on the previous 13301e04c3fSmrg * index bounds. 13401e04c3fSmrg */ 13501e04c3fSmrgstatic GLuint 13601e04c3fSmrgget_max_vertices(struct split_context *split, 13701e04c3fSmrg const struct _mesa_prim *prim) 13801e04c3fSmrg{ 13901e04c3fSmrg if ((prim->start > split->min_index && 14001e04c3fSmrg prim->start - split->min_index >= split->limit) || 14101e04c3fSmrg (prim->start < split->max_index && 14201e04c3fSmrg split->max_index - prim->start >= split->limit)) 14301e04c3fSmrg /* "prim" starts too far away from the old range. */ 14401e04c3fSmrg return 0; 14501e04c3fSmrg 14601e04c3fSmrg return MIN2(split->min_index, prim->start) + split->limit - prim->start; 14701e04c3fSmrg} 14801e04c3fSmrg 14901e04c3fSmrg 15001e04c3fSmrg/* Break large primitives into smaller ones. If not possible, convert 15101e04c3fSmrg * the primitive to indexed and pass to split_elts(). 15201e04c3fSmrg */ 15301e04c3fSmrgstatic void 15401e04c3fSmrgsplit_prims(struct split_context *split) 15501e04c3fSmrg{ 15601e04c3fSmrg GLuint i; 15701e04c3fSmrg 15801e04c3fSmrg for (i = 0; i < split->nr_prims; i++) { 15901e04c3fSmrg const struct _mesa_prim *prim = &split->prim[i]; 16001e04c3fSmrg GLuint first, incr; 16101e04c3fSmrg GLboolean split_inplace = 16201e04c3fSmrg _tnl_split_prim_inplace(prim->mode, &first, &incr); 16301e04c3fSmrg GLuint available = get_max_vertices(split, prim); 16401e04c3fSmrg GLuint count = prim->count - (prim->count - first) % incr; 16501e04c3fSmrg 16601e04c3fSmrg if (prim->count < first) 16701e04c3fSmrg continue; 16801e04c3fSmrg 16901e04c3fSmrg if ((available < count && !split_inplace) || 17001e04c3fSmrg (available < first && split_inplace)) { 17101e04c3fSmrg flush_vertex(split); 17201e04c3fSmrg available = get_max_vertices(split, prim); 17301e04c3fSmrg } 17401e04c3fSmrg 17501e04c3fSmrg if (available >= count) { 17601e04c3fSmrg struct _mesa_prim *outprim = next_outprim(split); 17701e04c3fSmrg 17801e04c3fSmrg *outprim = *prim; 17901e04c3fSmrg update_index_bounds(split, outprim); 18001e04c3fSmrg } 18101e04c3fSmrg else if (split_inplace) { 18201e04c3fSmrg GLuint j, nr; 18301e04c3fSmrg 18401e04c3fSmrg for (j = 0 ; j < count ;) { 18501e04c3fSmrg GLuint remaining = count - j; 18601e04c3fSmrg struct _mesa_prim *outprim = next_outprim(split); 18701e04c3fSmrg 18801e04c3fSmrg nr = MIN2(available, remaining); 18901e04c3fSmrg nr -= (nr - first) % incr; 19001e04c3fSmrg 19101e04c3fSmrg outprim->mode = prim->mode; 19201e04c3fSmrg outprim->begin = (j == 0 && prim->begin); 19301e04c3fSmrg outprim->end = (nr == remaining && prim->end); 19401e04c3fSmrg outprim->start = prim->start + j; 19501e04c3fSmrg outprim->count = nr; 19601e04c3fSmrg 19701e04c3fSmrg update_index_bounds(split, outprim); 19801e04c3fSmrg 19901e04c3fSmrg if (nr == remaining) { 20001e04c3fSmrg /* Finished */ 20101e04c3fSmrg j += nr; 20201e04c3fSmrg } 20301e04c3fSmrg else { 20401e04c3fSmrg /* Wrapped the primitive */ 20501e04c3fSmrg j += nr - (first - incr); 20601e04c3fSmrg flush_vertex(split); 20701e04c3fSmrg available = get_max_vertices(split, prim); 20801e04c3fSmrg } 20901e04c3fSmrg } 21001e04c3fSmrg } 21101e04c3fSmrg else if (split->ib == NULL) { 21201e04c3fSmrg /* XXX: could at least send the first max_verts off from the 21301e04c3fSmrg * inplace buffers. 21401e04c3fSmrg */ 21501e04c3fSmrg 21601e04c3fSmrg /* else convert to indexed primitive and pass to split_elts, 21701e04c3fSmrg * which will do the necessary copying and turn it back into a 21801e04c3fSmrg * vertex primitive for rendering... 21901e04c3fSmrg */ 22001e04c3fSmrg struct _mesa_index_buffer ib; 22101e04c3fSmrg struct _mesa_prim tmpprim; 22201e04c3fSmrg GLuint *elts = malloc(count * sizeof(GLuint)); 22301e04c3fSmrg GLuint j; 22401e04c3fSmrg 22501e04c3fSmrg for (j = 0; j < count; j++) 22601e04c3fSmrg elts[j] = prim->start + j; 22701e04c3fSmrg 22801e04c3fSmrg ib.count = count; 2297ec681f3Smrg ib.index_size_shift = 2; 2307ec681f3Smrg ib.obj = NULL; 23101e04c3fSmrg ib.ptr = elts; 23201e04c3fSmrg 23301e04c3fSmrg tmpprim = *prim; 23401e04c3fSmrg tmpprim.start = 0; 23501e04c3fSmrg tmpprim.count = count; 23601e04c3fSmrg 23701e04c3fSmrg flush_vertex(split); 23801e04c3fSmrg 23901e04c3fSmrg _tnl_split_copy(split->ctx, 24001e04c3fSmrg split->array, 24101e04c3fSmrg &tmpprim, 1, 24201e04c3fSmrg &ib, 24301e04c3fSmrg split->draw, 24401e04c3fSmrg split->limits); 24501e04c3fSmrg 24601e04c3fSmrg free(elts); 24701e04c3fSmrg } 24801e04c3fSmrg else { 24901e04c3fSmrg flush_vertex(split); 25001e04c3fSmrg 25101e04c3fSmrg _tnl_split_copy(split->ctx, 25201e04c3fSmrg split->array, 25301e04c3fSmrg prim, 1, 25401e04c3fSmrg split->ib, 25501e04c3fSmrg split->draw, 25601e04c3fSmrg split->limits); 25701e04c3fSmrg } 25801e04c3fSmrg } 25901e04c3fSmrg 26001e04c3fSmrg flush_vertex(split); 26101e04c3fSmrg} 26201e04c3fSmrg 26301e04c3fSmrg 26401e04c3fSmrgvoid 26501e04c3fSmrg_tnl_split_inplace(struct gl_context *ctx, 26601e04c3fSmrg const struct tnl_vertex_array *arrays, 26701e04c3fSmrg const struct _mesa_prim *prim, 26801e04c3fSmrg GLuint nr_prims, 26901e04c3fSmrg const struct _mesa_index_buffer *ib, 2707ec681f3Smrg GLuint num_instances, 2717ec681f3Smrg GLuint base_instance, 27201e04c3fSmrg tnl_draw_func draw, 27301e04c3fSmrg const struct split_limits *limits) 27401e04c3fSmrg{ 27501e04c3fSmrg struct split_context split; 27601e04c3fSmrg 27701e04c3fSmrg memset(&split, 0, sizeof(split)); 27801e04c3fSmrg 27901e04c3fSmrg split.ctx = ctx; 28001e04c3fSmrg split.array = arrays; 28101e04c3fSmrg split.prim = prim; 28201e04c3fSmrg split.nr_prims = nr_prims; 28301e04c3fSmrg split.ib = ib; 28401e04c3fSmrg 28501e04c3fSmrg /* Empty interval, makes calculations simpler. */ 28601e04c3fSmrg split.min_index = ~0; 28701e04c3fSmrg split.max_index = 0; 2887ec681f3Smrg split.num_instances = num_instances; 2897ec681f3Smrg split.base_instance = base_instance; 29001e04c3fSmrg 29101e04c3fSmrg split.draw = draw; 29201e04c3fSmrg split.limits = limits; 29301e04c3fSmrg split.limit = ib ? limits->max_indices : limits->max_verts; 29401e04c3fSmrg 29501e04c3fSmrg split_prims(&split); 29601e04c3fSmrg} 297