Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / vbo / vbo_split_inplace.c
1
2 /*
3  * Mesa 3-D graphics library
4  * Version:  6.5
5  *
6  * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included
16  * in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  * Authors:
26  *    Keith Whitwell <keith@tungstengraphics.com>
27  */
28
29
30 #include "main/mtypes.h"
31 #include "main/macros.h"
32 #include "main/enums.h"
33 #include "main/image.h"
34 #include "vbo_split.h"
35
36
37 #define MAX_PRIM 32
38
39 /* Used for splitting without copying. No attempt is made to handle
40  * too large indexed vertex buffers: In general you need to copy to do
41  * that.
42  */
43 struct split_context {
44    struct gl_context *ctx;
45    const struct gl_client_array **array;
46    const struct _mesa_prim *prim;
47    GLuint nr_prims;
48    const struct _mesa_index_buffer *ib;
49    GLuint min_index;
50    GLuint max_index;
51    vbo_draw_func draw;
52
53    const struct split_limits *limits;
54    GLuint limit;
55
56    struct _mesa_prim dstprim[MAX_PRIM];
57    GLuint dstprim_nr;
58 };
59
60
61
62
63 static void flush_vertex( struct split_context *split )
64 {
65    struct _mesa_index_buffer ib;
66    GLuint i;
67
68    if (!split->dstprim_nr) 
69       return;
70
71    if (split->ib) {
72       ib = *split->ib;
73
74       ib.count = split->max_index - split->min_index + 1;
75       ib.ptr = (const void *)((const char *)ib.ptr + 
76                               split->min_index * _mesa_sizeof_type(ib.type));
77
78       /* Rebase the primitives to save index buffer entries. */
79       for (i = 0; i < split->dstprim_nr; i++)
80          split->dstprim[i].start -= split->min_index;
81    }
82
83    assert(split->max_index >= split->min_index);
84
85    split->draw(split->ctx,
86                split->array,
87                split->dstprim,
88                split->dstprim_nr,
89                split->ib ? &ib : NULL,
90                !split->ib,
91                split->min_index,
92                split->max_index);
93
94    split->dstprim_nr = 0;
95    split->min_index = ~0;
96    split->max_index = 0;
97 }
98
99
100 static struct _mesa_prim *next_outprim( struct split_context *split )
101 {
102    if (split->dstprim_nr == MAX_PRIM-1) {
103       flush_vertex(split);
104    }
105
106    {
107       struct _mesa_prim *prim = &split->dstprim[split->dstprim_nr++];
108       memset(prim, 0, sizeof(*prim));
109       return prim;
110    }
111 }
112
113 static void update_index_bounds(struct split_context *split,
114                                 const struct _mesa_prim *prim)
115 {
116    split->min_index = MIN2(split->min_index, prim->start);
117    split->max_index = MAX2(split->max_index, prim->start + prim->count - 1);
118 }
119
120 /* Return the maximum amount of vertices that can be emitted for a
121  * primitive starting at 'prim->start', depending on the previous
122  * index bounds.
123  */
124 static GLuint get_max_vertices(struct split_context *split,
125                                const struct _mesa_prim *prim)
126 {
127    if ((prim->start > split->min_index &&
128         prim->start - split->min_index >= split->limit) ||
129        (prim->start < split->max_index &&
130         split->max_index - prim->start >= split->limit))
131       /* "prim" starts too far away from the old range. */
132       return 0;
133
134    return MIN2(split->min_index, prim->start) + split->limit - prim->start;
135 }
136
137 /* Break large primitives into smaller ones.  If not possible, convert
138  * the primitive to indexed and pass to split_elts().
139  */
140 static void split_prims( struct split_context *split) 
141 {
142    GLuint i;
143
144    for (i = 0; i < split->nr_prims; i++) {
145       const struct _mesa_prim *prim = &split->prim[i];
146       GLuint first, incr;
147       GLboolean split_inplace = split_prim_inplace(prim->mode, &first, &incr);
148       GLuint available = get_max_vertices(split, prim);
149       GLuint count = prim->count - (prim->count - first) % incr;
150
151       if (prim->count < first)
152          continue;
153
154       if ((available < count && !split_inplace) ||
155           (available < first && split_inplace)) {
156          flush_vertex(split);
157          available = get_max_vertices(split, prim);
158       }
159       
160       if (available >= count) {
161          struct _mesa_prim *outprim = next_outprim(split);
162
163          *outprim = *prim;
164          update_index_bounds(split, outprim);
165       }
166       else if (split_inplace) {
167          GLuint j, nr;
168
169          for (j = 0 ; j < count ; ) {
170             GLuint remaining = count - j;
171             struct _mesa_prim *outprim = next_outprim(split);
172
173             nr = MIN2( available, remaining );
174             nr -= (nr - first) % incr;
175             
176             outprim->mode = prim->mode;
177             outprim->begin = (j == 0 && prim->begin);
178             outprim->end = (nr == remaining && prim->end);
179             outprim->start = prim->start + j;
180             outprim->count = nr;
181             outprim->num_instances = prim->num_instances;
182
183             update_index_bounds(split, outprim);
184
185             if (nr == remaining) {
186                /* Finished. 
187                 */
188                j += nr;
189             }
190             else {
191                /* Wrapped the primitive: 
192                 */
193                j += nr - (first - incr);
194                flush_vertex(split);
195                available = get_max_vertices(split, prim);
196             }
197          }
198       }
199       else if (split->ib == NULL) {
200          /* XXX: could at least send the first max_verts off from the
201           * inplace buffers.
202           */
203
204          /* else convert to indexed primitive and pass to split_elts,
205           * which will do the necessary copying and turn it back into a
206           * vertex primitive for rendering...
207           */
208          struct _mesa_index_buffer ib;
209          struct _mesa_prim tmpprim;
210          GLuint *elts = malloc(count * sizeof(GLuint));
211          GLuint j;
212          
213          for (j = 0; j < count; j++)
214             elts[j] = prim->start + j;
215
216          ib.count = count;
217          ib.type = GL_UNSIGNED_INT;
218          ib.obj = split->ctx->Shared->NullBufferObj;
219          ib.ptr = elts;
220             
221          tmpprim = *prim;
222          tmpprim.indexed = 1;
223          tmpprim.start = 0;
224          tmpprim.count = count;
225          tmpprim.num_instances = 1;
226
227          flush_vertex(split);
228
229          vbo_split_copy(split->ctx,
230                         split->array,
231                         &tmpprim, 1, 
232                         &ib,
233                         split->draw,
234                         split->limits);
235             
236          free(elts);
237       }
238       else {
239          flush_vertex(split);
240
241          vbo_split_copy(split->ctx,
242                         split->array,
243                         prim, 1, 
244                         split->ib,
245                         split->draw,
246                         split->limits);
247       }
248    }
249
250    flush_vertex(split);
251 }
252
253
254 void vbo_split_inplace( struct gl_context *ctx,
255                         const struct gl_client_array *arrays[],
256                         const struct _mesa_prim *prim,
257                         GLuint nr_prims,
258                         const struct _mesa_index_buffer *ib,
259                         GLuint min_index,
260                         GLuint max_index,
261                         vbo_draw_func draw,
262                         const struct split_limits *limits )
263 {
264    struct split_context split;
265
266    memset(&split, 0, sizeof(split));
267
268    split.ctx = ctx;
269    split.array = arrays;
270    split.prim = prim;
271    split.nr_prims = nr_prims;
272    split.ib = ib;
273
274    /* Empty interval, makes calculations simpler. */
275    split.min_index = ~0;
276    split.max_index = 0;
277
278    split.draw = draw;
279    split.limits = limits;
280    split.limit = ib ? limits->max_indices : limits->max_verts;
281
282    split_prims( &split );
283 }
284
285