1 /*
2  * Mesa 3-D graphics library
3  * Version:  7.2
4  *
5  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 
25 /* Author:
26  *    Keith Whitwell <keith@tungstengraphics.com>
27  */
28 
29 #include "main/glheader.h"
30 #include "main/bufferobj.h"
31 #include "main/context.h"
32 #include "main/imports.h"
33 #include "main/mfeatures.h"
34 #include "main/mtypes.h"
35 #include "main/macros.h"
36 #include "main/light.h"
37 #include "main/state.h"
38 
39 #include "vbo_context.h"
40 
41 
42 #if FEATURE_dlist
43 
44 
45 /**
46  * After playback, copy everything but the position from the
47  * last vertex to the saved state
48  */
49 static void
_playback_copy_to_current(struct gl_context * ctx,const struct vbo_save_vertex_list * node)50 _playback_copy_to_current(struct gl_context *ctx,
51                           const struct vbo_save_vertex_list *node)
52 {
53    struct vbo_context *vbo = vbo_context(ctx);
54    GLfloat vertex[VBO_ATTRIB_MAX * 4];
55    GLfloat *data;
56    GLuint i, offset;
57 
58    if (node->current_size == 0)
59       return;
60 
61    if (node->current_data) {
62       data = node->current_data;
63    }
64    else {
65       data = vertex;
66 
67       if (node->count)
68          offset = (node->buffer_offset +
69                    (node->count-1) * node->vertex_size * sizeof(GLfloat));
70       else
71          offset = node->buffer_offset;
72 
73       ctx->Driver.GetBufferSubData( ctx, offset,
74                                     node->vertex_size * sizeof(GLfloat),
75                                     data, node->vertex_store->bufferobj );
76 
77       data += node->attrsz[0]; /* skip vertex position */
78    }
79 
80    for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
81       if (node->attrsz[i]) {
82 	 GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
83          GLfloat tmp[4];
84 
85          COPY_CLEAN_4V_TYPE_AS_FLOAT(tmp,
86                                      node->attrsz[i],
87                                      data,
88                                      node->attrtype[i]);
89 
90          if (node->attrtype[i] != vbo->currval[i].Type ||
91              memcmp(current, tmp, 4 * sizeof(GLfloat)) != 0) {
92             memcpy(current, tmp, 4 * sizeof(GLfloat));
93 
94             vbo->currval[i].Size = node->attrsz[i];
95             vbo->currval[i]._ElementSize = vbo->currval[i].Size * sizeof(GLfloat);
96             vbo->currval[i].Type = node->attrtype[i];
97             vbo->currval[i].Integer =
98                   vbo_attrtype_to_integer_flag(node->attrtype[i]);
99 
100             if (i >= VBO_ATTRIB_FIRST_MATERIAL &&
101                 i <= VBO_ATTRIB_LAST_MATERIAL)
102                ctx->NewState |= _NEW_LIGHT;
103 
104             ctx->NewState |= _NEW_CURRENT_ATTRIB;
105          }
106 
107 	 data += node->attrsz[i];
108       }
109    }
110 
111    /* Colormaterial -- this kindof sucks.
112     */
113    if (ctx->Light.ColorMaterialEnabled) {
114       _mesa_update_color_material(ctx, ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
115    }
116 
117    /* CurrentExecPrimitive
118     */
119    if (node->prim_count) {
120       const struct _mesa_prim *prim = &node->prim[node->prim_count - 1];
121       if (prim->end)
122 	 ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
123       else
124 	 ctx->Driver.CurrentExecPrimitive = prim->mode;
125    }
126 }
127 
128 
129 
130 /**
131  * Treat the vertex storage as a VBO, define vertex arrays pointing
132  * into it:
133  */
vbo_bind_vertex_list(struct gl_context * ctx,const struct vbo_save_vertex_list * node)134 static void vbo_bind_vertex_list(struct gl_context *ctx,
135                                  const struct vbo_save_vertex_list *node)
136 {
137    struct vbo_context *vbo = vbo_context(ctx);
138    struct vbo_save_context *save = &vbo->save;
139    struct gl_client_array *arrays = save->arrays;
140    GLuint buffer_offset = node->buffer_offset;
141    const GLuint *map;
142    GLuint attr;
143    GLubyte node_attrsz[VBO_ATTRIB_MAX];  /* copy of node->attrsz[] */
144    GLenum node_attrtype[VBO_ATTRIB_MAX];  /* copy of node->attrtype[] */
145    GLbitfield64 varying_inputs = 0x0;
146 
147    memcpy(node_attrsz, node->attrsz, sizeof(node->attrsz));
148    memcpy(node_attrtype, node->attrtype, sizeof(node->attrtype));
149 
150    /* Install the default (ie Current) attributes first, then overlay
151     * all active ones.
152     */
153    switch (get_program_mode(ctx)) {
154    case VP_NONE:
155       for (attr = 0; attr < VERT_ATTRIB_FF_MAX; attr++) {
156          save->inputs[attr] = &vbo->currval[VBO_ATTRIB_POS+attr];
157       }
158       for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) {
159          save->inputs[VERT_ATTRIB_GENERIC(attr)] =
160             &vbo->currval[VBO_ATTRIB_MAT_FRONT_AMBIENT+attr];
161       }
162       map = vbo->map_vp_none;
163       break;
164    case VP_NV:
165    case VP_ARB:
166       /* The aliasing of attributes for NV vertex programs has already
167        * occurred.  NV vertex programs cannot access material values,
168        * nor attributes greater than VERT_ATTRIB_TEX7.
169        */
170       for (attr = 0; attr < VERT_ATTRIB_FF_MAX; attr++) {
171          save->inputs[attr] = &vbo->currval[VBO_ATTRIB_POS+attr];
172       }
173       for (attr = 0; attr < VERT_ATTRIB_GENERIC_MAX; attr++) {
174          save->inputs[VERT_ATTRIB_GENERIC(attr)] =
175             &vbo->currval[VBO_ATTRIB_GENERIC0+attr];
176       }
177       map = vbo->map_vp_arb;
178 
179       /* check if VERT_ATTRIB_POS is not read but VERT_BIT_GENERIC0 is read.
180        * In that case we effectively need to route the data from
181        * glVertexAttrib(0, val) calls to feed into the GENERIC0 input.
182        */
183       if ((ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_POS) == 0 &&
184           (ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_GENERIC0)) {
185          save->inputs[VERT_ATTRIB_GENERIC0] = save->inputs[0];
186          node_attrsz[VERT_ATTRIB_GENERIC0] = node_attrsz[0];
187          node_attrtype[VERT_ATTRIB_GENERIC0] = node_attrtype[0];
188          node_attrsz[0] = 0;
189       }
190       break;
191    default:
192       assert(0);
193    }
194 
195    for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
196       const GLuint src = map[attr];
197 
198       if (node_attrsz[src]) {
199          /* override the default array set above */
200          save->inputs[attr] = &arrays[attr];
201 
202 	 arrays[attr].Ptr = (const GLubyte *) NULL + buffer_offset;
203 	 arrays[attr].Size = node_attrsz[src];
204 	 arrays[attr].StrideB = node->vertex_size * sizeof(GLfloat);
205 	 arrays[attr].Stride = node->vertex_size * sizeof(GLfloat);
206          arrays[attr].Type = node_attrtype[src];
207          arrays[attr].Integer =
208                vbo_attrtype_to_integer_flag(node_attrtype[src]);
209          arrays[attr].Format = GL_RGBA;
210 	 arrays[attr].Enabled = 1;
211          arrays[attr]._ElementSize = arrays[attr].Size * sizeof(GLfloat);
212          _mesa_reference_buffer_object(ctx,
213                                        &arrays[attr].BufferObj,
214                                        node->vertex_store->bufferobj);
215 	 arrays[attr]._MaxElement = node->count; /* ??? */
216 
217 	 assert(arrays[attr].BufferObj->Name);
218 
219 	 buffer_offset += node_attrsz[src] * sizeof(GLfloat);
220          varying_inputs |= VERT_BIT(attr);
221       }
222    }
223 
224    _mesa_set_varying_vp_inputs( ctx, varying_inputs );
225    ctx->NewDriverState |= ctx->DriverFlags.NewArray;
226 }
227 
228 
229 static void
vbo_save_loopback_vertex_list(struct gl_context * ctx,const struct vbo_save_vertex_list * list)230 vbo_save_loopback_vertex_list(struct gl_context *ctx,
231                               const struct vbo_save_vertex_list *list)
232 {
233    const char *buffer =
234       ctx->Driver.MapBufferRange(ctx, 0,
235 				 list->vertex_store->bufferobj->Size,
236 				 GL_MAP_READ_BIT, /* ? */
237 				 list->vertex_store->bufferobj);
238 
239    vbo_loopback_vertex_list(ctx,
240                             (const GLfloat *)(buffer + list->buffer_offset),
241                             list->attrsz,
242                             list->prim,
243                             list->prim_count,
244                             list->wrap_count,
245                             list->vertex_size);
246 
247    ctx->Driver.UnmapBuffer(ctx, list->vertex_store->bufferobj);
248 }
249 
250 
251 /**
252  * Execute the buffer and save copied verts.
253  * This is called from the display list code when executing
254  * a drawing command.
255  */
256 void
vbo_save_playback_vertex_list(struct gl_context * ctx,void * data)257 vbo_save_playback_vertex_list(struct gl_context *ctx, void *data)
258 {
259    const struct vbo_save_vertex_list *node =
260       (const struct vbo_save_vertex_list *) data;
261    struct vbo_save_context *save = &vbo_context(ctx)->save;
262    GLboolean remap_vertex_store = GL_FALSE;
263 
264    if (save->vertex_store->buffer) {
265       /* The vertex store is currently mapped but we're about to replay
266        * a display list.  This can happen when a nested display list is
267        * being build with GL_COMPILE_AND_EXECUTE.
268        * We never want to have mapped vertex buffers when we're drawing.
269        * Unmap the vertex store, execute the list, then remap the vertex
270        * store.
271        */
272       vbo_save_unmap_vertex_store(ctx, save->vertex_store);
273       remap_vertex_store = GL_TRUE;
274    }
275 
276    FLUSH_CURRENT(ctx, 0);
277 
278    if (node->prim_count > 0) {
279 
280       if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END &&
281 	  node->prim[0].begin) {
282 
283 	 /* Degenerate case: list is called inside begin/end pair and
284 	  * includes operations such as glBegin or glDrawArrays.
285 	  */
286 	 if (0)
287 	    printf("displaylist recursive begin");
288 
289 	 vbo_save_loopback_vertex_list( ctx, node );
290 
291          goto end;
292       }
293       else if (save->replay_flags) {
294 	 /* Various degnerate cases: translate into immediate mode
295 	  * calls rather than trying to execute in place.
296 	  */
297 	 vbo_save_loopback_vertex_list( ctx, node );
298 
299          goto end;
300       }
301 
302       if (ctx->NewState)
303 	 _mesa_update_state( ctx );
304 
305       /* XXX also need to check if shader enabled, but invalid */
306       if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) ||
307           (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) {
308          _mesa_error(ctx, GL_INVALID_OPERATION,
309                      "glBegin (invalid vertex/fragment program)");
310          return;
311       }
312 
313       vbo_bind_vertex_list( ctx, node );
314 
315       vbo_draw_method(vbo_context(ctx), DRAW_DISPLAY_LIST);
316 
317       /* Again...
318        */
319       if (ctx->NewState)
320 	 _mesa_update_state( ctx );
321 
322       if (node->count > 0) {
323          vbo_context(ctx)->draw_prims(ctx,
324                                       node->prim,
325                                       node->prim_count,
326                                       NULL,
327                                       GL_TRUE,
328                                       0,    /* Node is a VBO, so this is ok */
329                                       node->count - 1,
330                                       NULL);
331       }
332    }
333 
334    /* Copy to current?
335     */
336    _playback_copy_to_current( ctx, node );
337 
338 end:
339    if (remap_vertex_store) {
340       save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
341    }
342 }
343 
344 
345 #endif /* FEATURE_dlist */
346