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 30b8e80941Smrg#include "main/mtypes.h" 31b8e80941Smrg#include "main/macros.h" 32b8e80941Smrg#include "main/enums.h" 33b8e80941Smrg#include "vbo/vbo.h" 34b8e80941Smrg 35b8e80941Smrg#include "t_split.h" 36b8e80941Smrg 37b8e80941Smrg 38b8e80941Smrg#define MAX_PRIM 32 39b8e80941Smrg 40b8e80941Smrg/* Used for splitting without copying. No attempt is made to handle 41b8e80941Smrg * too large indexed vertex buffers: In general you need to copy to do 42b8e80941Smrg * that. 43b8e80941Smrg */ 44b8e80941Smrgstruct split_context { 45b8e80941Smrg struct gl_context *ctx; 46b8e80941Smrg const struct tnl_vertex_array *array; 47b8e80941Smrg const struct _mesa_prim *prim; 48b8e80941Smrg GLuint nr_prims; 49b8e80941Smrg const struct _mesa_index_buffer *ib; 50b8e80941Smrg GLuint min_index; 51b8e80941Smrg GLuint max_index; 52b8e80941Smrg tnl_draw_func draw; 53b8e80941Smrg 54b8e80941Smrg const struct split_limits *limits; 55b8e80941Smrg GLuint limit; 56b8e80941Smrg 57b8e80941Smrg struct _mesa_prim dstprim[MAX_PRIM]; 58b8e80941Smrg GLuint dstprim_nr; 59b8e80941Smrg}; 60b8e80941Smrg 61b8e80941Smrg 62b8e80941Smrg 63b8e80941Smrg 64b8e80941Smrgstatic void 65b8e80941Smrgflush_vertex( struct split_context *split) 66b8e80941Smrg{ 67b8e80941Smrg struct gl_context *ctx = split->ctx; 68b8e80941Smrg struct _mesa_index_buffer ib; 69b8e80941Smrg GLuint i; 70b8e80941Smrg 71b8e80941Smrg if (!split->dstprim_nr) 72b8e80941Smrg return; 73b8e80941Smrg 74b8e80941Smrg if (split->ib) { 75b8e80941Smrg ib = *split->ib; 76b8e80941Smrg 77b8e80941Smrg ib.count = split->max_index - split->min_index + 1; 78b8e80941Smrg ib.ptr = (const void *)((const char *)ib.ptr + 79b8e80941Smrg split->min_index * ib.index_size); 80b8e80941Smrg 81b8e80941Smrg /* Rebase the primitives to save index buffer entries. */ 82b8e80941Smrg for (i = 0; i < split->dstprim_nr; i++) 83b8e80941Smrg split->dstprim[i].start -= split->min_index; 84b8e80941Smrg } 85b8e80941Smrg 86b8e80941Smrg assert(split->max_index >= split->min_index); 87b8e80941Smrg 88b8e80941Smrg split->draw(ctx, 89b8e80941Smrg split->array, 90b8e80941Smrg split->dstprim, 91b8e80941Smrg split->dstprim_nr, 92b8e80941Smrg split->ib ? &ib : NULL, 93b8e80941Smrg !split->ib, 94b8e80941Smrg split->min_index, 95b8e80941Smrg split->max_index, 96b8e80941Smrg NULL, 0, NULL); 97b8e80941Smrg 98b8e80941Smrg split->dstprim_nr = 0; 99b8e80941Smrg split->min_index = ~0; 100b8e80941Smrg split->max_index = 0; 101b8e80941Smrg} 102b8e80941Smrg 103b8e80941Smrg 104b8e80941Smrgstatic struct _mesa_prim * 105b8e80941Smrgnext_outprim(struct split_context *split) 106b8e80941Smrg{ 107b8e80941Smrg if (split->dstprim_nr == MAX_PRIM-1) { 108b8e80941Smrg flush_vertex(split); 109b8e80941Smrg } 110b8e80941Smrg 111b8e80941Smrg { 112b8e80941Smrg struct _mesa_prim *prim = &split->dstprim[split->dstprim_nr++]; 113b8e80941Smrg memset(prim, 0, sizeof(*prim)); 114b8e80941Smrg return prim; 115b8e80941Smrg } 116b8e80941Smrg} 117b8e80941Smrg 118b8e80941Smrg 119b8e80941Smrgstatic void 120b8e80941Smrgupdate_index_bounds(struct split_context *split, 121b8e80941Smrg const struct _mesa_prim *prim) 122b8e80941Smrg{ 123b8e80941Smrg split->min_index = MIN2(split->min_index, prim->start); 124b8e80941Smrg split->max_index = MAX2(split->max_index, prim->start + prim->count - 1); 125b8e80941Smrg} 126b8e80941Smrg 127b8e80941Smrg 128b8e80941Smrg/* Return the maximum amount of vertices that can be emitted for a 129b8e80941Smrg * primitive starting at 'prim->start', depending on the previous 130b8e80941Smrg * index bounds. 131b8e80941Smrg */ 132b8e80941Smrgstatic GLuint 133b8e80941Smrgget_max_vertices(struct split_context *split, 134b8e80941Smrg const struct _mesa_prim *prim) 135b8e80941Smrg{ 136b8e80941Smrg if ((prim->start > split->min_index && 137b8e80941Smrg prim->start - split->min_index >= split->limit) || 138b8e80941Smrg (prim->start < split->max_index && 139b8e80941Smrg split->max_index - prim->start >= split->limit)) 140b8e80941Smrg /* "prim" starts too far away from the old range. */ 141b8e80941Smrg return 0; 142b8e80941Smrg 143b8e80941Smrg return MIN2(split->min_index, prim->start) + split->limit - prim->start; 144b8e80941Smrg} 145b8e80941Smrg 146b8e80941Smrg 147b8e80941Smrg/* Break large primitives into smaller ones. If not possible, convert 148b8e80941Smrg * the primitive to indexed and pass to split_elts(). 149b8e80941Smrg */ 150b8e80941Smrgstatic void 151b8e80941Smrgsplit_prims(struct split_context *split) 152b8e80941Smrg{ 153b8e80941Smrg GLuint i; 154b8e80941Smrg 155b8e80941Smrg for (i = 0; i < split->nr_prims; i++) { 156b8e80941Smrg const struct _mesa_prim *prim = &split->prim[i]; 157b8e80941Smrg GLuint first, incr; 158b8e80941Smrg GLboolean split_inplace = 159b8e80941Smrg _tnl_split_prim_inplace(prim->mode, &first, &incr); 160b8e80941Smrg GLuint available = get_max_vertices(split, prim); 161b8e80941Smrg GLuint count = prim->count - (prim->count - first) % incr; 162b8e80941Smrg 163b8e80941Smrg if (prim->count < first) 164b8e80941Smrg continue; 165b8e80941Smrg 166b8e80941Smrg if ((available < count && !split_inplace) || 167b8e80941Smrg (available < first && split_inplace)) { 168b8e80941Smrg flush_vertex(split); 169b8e80941Smrg available = get_max_vertices(split, prim); 170b8e80941Smrg } 171b8e80941Smrg 172b8e80941Smrg if (available >= count) { 173b8e80941Smrg struct _mesa_prim *outprim = next_outprim(split); 174b8e80941Smrg 175b8e80941Smrg *outprim = *prim; 176b8e80941Smrg update_index_bounds(split, outprim); 177b8e80941Smrg } 178b8e80941Smrg else if (split_inplace) { 179b8e80941Smrg GLuint j, nr; 180b8e80941Smrg 181b8e80941Smrg for (j = 0 ; j < count ;) { 182b8e80941Smrg GLuint remaining = count - j; 183b8e80941Smrg struct _mesa_prim *outprim = next_outprim(split); 184b8e80941Smrg 185b8e80941Smrg nr = MIN2(available, remaining); 186b8e80941Smrg nr -= (nr - first) % incr; 187b8e80941Smrg 188b8e80941Smrg outprim->mode = prim->mode; 189b8e80941Smrg outprim->begin = (j == 0 && prim->begin); 190b8e80941Smrg outprim->end = (nr == remaining && prim->end); 191b8e80941Smrg outprim->start = prim->start + j; 192b8e80941Smrg outprim->count = nr; 193b8e80941Smrg outprim->num_instances = prim->num_instances; 194b8e80941Smrg outprim->base_instance = prim->base_instance; 195b8e80941Smrg 196b8e80941Smrg update_index_bounds(split, outprim); 197b8e80941Smrg 198b8e80941Smrg if (nr == remaining) { 199b8e80941Smrg /* Finished */ 200b8e80941Smrg j += nr; 201b8e80941Smrg } 202b8e80941Smrg else { 203b8e80941Smrg /* Wrapped the primitive */ 204b8e80941Smrg j += nr - (first - incr); 205b8e80941Smrg flush_vertex(split); 206b8e80941Smrg available = get_max_vertices(split, prim); 207b8e80941Smrg } 208b8e80941Smrg } 209b8e80941Smrg } 210b8e80941Smrg else if (split->ib == NULL) { 211b8e80941Smrg /* XXX: could at least send the first max_verts off from the 212b8e80941Smrg * inplace buffers. 213b8e80941Smrg */ 214b8e80941Smrg 215b8e80941Smrg /* else convert to indexed primitive and pass to split_elts, 216b8e80941Smrg * which will do the necessary copying and turn it back into a 217b8e80941Smrg * vertex primitive for rendering... 218b8e80941Smrg */ 219b8e80941Smrg struct _mesa_index_buffer ib; 220b8e80941Smrg struct _mesa_prim tmpprim; 221b8e80941Smrg GLuint *elts = malloc(count * sizeof(GLuint)); 222b8e80941Smrg GLuint j; 223b8e80941Smrg 224b8e80941Smrg for (j = 0; j < count; j++) 225b8e80941Smrg elts[j] = prim->start + j; 226b8e80941Smrg 227b8e80941Smrg ib.count = count; 228b8e80941Smrg ib.index_size = 4; 229b8e80941Smrg ib.obj = split->ctx->Shared->NullBufferObj; 230b8e80941Smrg ib.ptr = elts; 231b8e80941Smrg 232b8e80941Smrg tmpprim = *prim; 233b8e80941Smrg tmpprim.indexed = 1; 234b8e80941Smrg tmpprim.start = 0; 235b8e80941Smrg tmpprim.count = count; 236b8e80941Smrg tmpprim.num_instances = 1; 237b8e80941Smrg tmpprim.base_instance = 0; 238b8e80941Smrg 239b8e80941Smrg flush_vertex(split); 240b8e80941Smrg 241b8e80941Smrg _tnl_split_copy(split->ctx, 242b8e80941Smrg split->array, 243b8e80941Smrg &tmpprim, 1, 244b8e80941Smrg &ib, 245b8e80941Smrg split->draw, 246b8e80941Smrg split->limits); 247b8e80941Smrg 248b8e80941Smrg free(elts); 249b8e80941Smrg } 250b8e80941Smrg else { 251b8e80941Smrg flush_vertex(split); 252b8e80941Smrg 253b8e80941Smrg _tnl_split_copy(split->ctx, 254b8e80941Smrg split->array, 255b8e80941Smrg prim, 1, 256b8e80941Smrg split->ib, 257b8e80941Smrg split->draw, 258b8e80941Smrg split->limits); 259b8e80941Smrg } 260b8e80941Smrg } 261b8e80941Smrg 262b8e80941Smrg flush_vertex(split); 263b8e80941Smrg} 264b8e80941Smrg 265b8e80941Smrg 266b8e80941Smrgvoid 267b8e80941Smrg_tnl_split_inplace(struct gl_context *ctx, 268b8e80941Smrg const struct tnl_vertex_array *arrays, 269b8e80941Smrg const struct _mesa_prim *prim, 270b8e80941Smrg GLuint nr_prims, 271b8e80941Smrg const struct _mesa_index_buffer *ib, 272b8e80941Smrg GLuint min_index, 273b8e80941Smrg GLuint max_index, 274b8e80941Smrg tnl_draw_func draw, 275b8e80941Smrg const struct split_limits *limits) 276b8e80941Smrg{ 277b8e80941Smrg struct split_context split; 278b8e80941Smrg 279b8e80941Smrg memset(&split, 0, sizeof(split)); 280b8e80941Smrg 281b8e80941Smrg split.ctx = ctx; 282b8e80941Smrg split.array = arrays; 283b8e80941Smrg split.prim = prim; 284b8e80941Smrg split.nr_prims = nr_prims; 285b8e80941Smrg split.ib = ib; 286b8e80941Smrg 287b8e80941Smrg /* Empty interval, makes calculations simpler. */ 288b8e80941Smrg split.min_index = ~0; 289b8e80941Smrg split.max_index = 0; 290b8e80941Smrg 291b8e80941Smrg split.draw = draw; 292b8e80941Smrg split.limits = limits; 293b8e80941Smrg split.limit = ib ? limits->max_indices : limits->max_verts; 294b8e80941Smrg 295b8e80941Smrg split_prims(&split); 296b8e80941Smrg} 297b8e80941Smrg 298b8e80941Smrg 299