Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / vbo / vbo_rebase.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 /* Helper for drivers which find themselves rendering a range of
30  * indices starting somewhere above zero.  Typically the application
31  * is issuing multiple DrawArrays() or DrawElements() to draw
32  * successive primitives layed out linearly in the vertex arrays.
33  * Unless the vertex arrays are all in a VBO, the OpenGL semantics
34  * imply that we need to re-upload the vertex data on each draw call.
35  * In that case, we want to avoid starting the upload at zero, as it
36  * will mean every draw call uploads an increasing amount of not-used
37  * vertex data.  Worse - in the software tnl module, all those
38  * vertices will be transformed and lit.
39  *
40  * If we just upload the new data, however, the indices will be
41  * incorrect as we tend to upload each set of vertex data to a new
42  * region.  
43  *
44  * This file provides a helper to adjust the arrays, primitives and
45  * indices of a draw call so that it can be re-issued with a min_index
46  * of zero.
47  */
48
49 #include "main/glheader.h"
50 #include "main/imports.h"
51 #include "main/mtypes.h"
52
53 #include "vbo.h"
54
55
56 #define REBASE(TYPE)                                            \
57 static void *rebase_##TYPE( const void *ptr,                    \
58                           GLuint count,                         \
59                           TYPE min_index )                      \
60 {                                                               \
61    const TYPE *in = (TYPE *)ptr;                                \
62    TYPE *tmp_indices = malloc(count * sizeof(TYPE));    \
63    GLuint i;                                                    \
64                                                                 \
65    for (i = 0; i < count; i++)                                  \
66       tmp_indices[i] = in[i] - min_index;                       \
67                                                                 \
68    return (void *)tmp_indices;                                  \
69 }
70
71
72 REBASE(GLuint)
73 REBASE(GLushort)
74 REBASE(GLubyte)
75
76 GLboolean vbo_all_varyings_in_vbos( const struct gl_client_array *arrays[] )
77 {
78    GLuint i;
79    
80    for (i = 0; i < VERT_ATTRIB_MAX; i++)
81       if (arrays[i]->BufferObj->Name == 0)
82          return GL_FALSE;
83
84    return GL_TRUE;
85 }
86
87 GLboolean vbo_any_varyings_in_vbos( const struct gl_client_array *arrays[] )
88 {
89    GLuint i;
90
91    for (i = 0; i < VERT_ATTRIB_MAX; i++)
92       if (arrays[i]->BufferObj->Name != 0)
93          return GL_TRUE;
94
95    return GL_FALSE;
96 }
97
98 /* Adjust primitives, indices and vertex definitions so that min_index
99  * becomes zero. There are lots of reasons for wanting to do this, eg:
100  *
101  * Software tnl:
102  *    - any time min_index != 0, otherwise unused vertices lower than
103  *      min_index will be transformed.
104  *
105  * Hardware tnl:
106  *    - if ib != NULL and min_index != 0, otherwise vertices lower than 
107  *      min_index will be uploaded.  Requires adjusting index values.
108  *
109  *    - if ib == NULL and min_index != 0, just for convenience so this doesn't
110  *      have to be handled within the driver.
111  *
112  * Hardware tnl with VBO support:
113  *    - as above, but only when vertices are not (all?) in VBO's.
114  *    - can't save time by trying to upload half a vbo - typically it is
115  *      all or nothing.
116  */
117 void vbo_rebase_prims( struct gl_context *ctx,
118                        const struct gl_client_array *arrays[],
119                        const struct _mesa_prim *prim,
120                        GLuint nr_prims,
121                        const struct _mesa_index_buffer *ib,
122                        GLuint min_index,
123                        GLuint max_index,
124                        vbo_draw_func draw )
125 {
126    struct gl_client_array tmp_arrays[VERT_ATTRIB_MAX];
127    const struct gl_client_array *tmp_array_pointers[VERT_ATTRIB_MAX];
128
129    struct _mesa_index_buffer tmp_ib;
130    struct _mesa_prim *tmp_prims = NULL;
131    void *tmp_indices = NULL;
132    GLuint i;
133
134    assert(min_index != 0);
135
136    if (0)
137       printf("%s %d..%d\n", __FUNCTION__, min_index, max_index);
138
139
140    /* XXX this path is disabled for now.
141     * There's rendering corruption in some apps when it's enabled.
142     */
143    if (0 && ib && ctx->Extensions.ARB_draw_elements_base_vertex) {
144       /* If we can just tell the hardware or the TNL to interpret our
145        * indices with a different base, do so.
146        */
147       tmp_prims = (struct _mesa_prim *)malloc(sizeof(*prim) * nr_prims);
148
149       for (i = 0; i < nr_prims; i++) {
150          tmp_prims[i] = prim[i];
151          tmp_prims[i].basevertex -= min_index;
152       }
153
154       prim = tmp_prims;
155    } else if (ib) {
156       /* Unfortunately need to adjust each index individually.
157        */
158       GLboolean map_ib = ib->obj->Name && !ib->obj->Pointer;
159       void *ptr;
160
161       if (map_ib) 
162          ctx->Driver.MapBuffer(ctx, 
163                                GL_ELEMENT_ARRAY_BUFFER,
164                                GL_READ_ONLY_ARB,
165                                ib->obj);
166
167
168       ptr = ADD_POINTERS(ib->obj->Pointer, ib->ptr);
169
170       /* Some users might prefer it if we translated elements to
171        * GLuints here.  Others wouldn't...
172        */
173       switch (ib->type) {
174       case GL_UNSIGNED_INT: 
175          tmp_indices = rebase_GLuint( ptr, ib->count, min_index );
176          break;
177       case GL_UNSIGNED_SHORT: 
178          tmp_indices = rebase_GLushort( ptr, ib->count, min_index );
179          break;
180       case GL_UNSIGNED_BYTE: 
181          tmp_indices = rebase_GLubyte( ptr, ib->count, min_index );
182          break;
183       }      
184
185       if (map_ib) 
186          ctx->Driver.UnmapBuffer(ctx, 
187                                  GL_ELEMENT_ARRAY_BUFFER,
188                                  ib->obj);
189
190       tmp_ib.obj = ctx->Shared->NullBufferObj;
191       tmp_ib.ptr = tmp_indices;
192       tmp_ib.count = ib->count;
193       tmp_ib.type = ib->type;
194
195       ib = &tmp_ib;
196    }
197    else {
198       /* Otherwise the primitives need adjustment.
199        */
200       tmp_prims = (struct _mesa_prim *)malloc(sizeof(*prim) * nr_prims);
201
202       for (i = 0; i < nr_prims; i++) {
203          /* If this fails, it could indicate an application error:
204           */
205          assert(prim[i].start >= min_index);
206
207          tmp_prims[i] = prim[i];
208          tmp_prims[i].start -= min_index;
209       }
210
211       prim = tmp_prims;
212    }
213
214    /* Just need to adjust the pointer values on each incoming array.
215     * This works for VBO and non-vbo rendering and shouldn't pesimize
216     * VBO-based upload schemes.  However this may still not be a fast
217     * path for hardware tnl for VBO based rendering as most machines
218     * will be happier if you just specify a starting vertex value in
219     * each primitive.
220     *
221     * For drivers with hardware tnl, you only want to do this if you
222     * are forced to, eg non-VBO indexed rendering with start != 0.
223     */
224    for (i = 0; i < VERT_ATTRIB_MAX; i++) {
225       tmp_arrays[i] = *arrays[i];
226       tmp_arrays[i].Ptr += min_index * tmp_arrays[i].StrideB;
227       tmp_array_pointers[i] = &tmp_arrays[i];
228    }
229    
230    /* Re-issue the draw call.
231     */
232    draw( ctx, 
233          tmp_array_pointers, 
234          prim, 
235          nr_prims, 
236          ib, 
237          GL_TRUE,
238          0, 
239          max_index - min_index );
240    
241    if (tmp_indices)
242       free(tmp_indices);
243    
244    if (tmp_prims)
245       free(tmp_prims);
246 }
247
248
249