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