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