• 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  * Authors:
25  *    Keith Whitwell <keithw@vmware.com>
26  */
27 
28 #include <stdbool.h>
29 #include <stdio.h>
30 #include "main/glheader.h"
31 #include "main/bufferobj.h"
32 #include "main/compiler.h"
33 #include "main/context.h"
34 #include "main/enums.h"
35 #include "main/state.h"
36 #include "main/vtxfmt.h"
37 
38 #include "vbo_context.h"
39 #include "vbo_noop.h"
40 
41 
42 static void
vbo_exec_debug_verts(struct vbo_exec_context * exec)43 vbo_exec_debug_verts( struct vbo_exec_context *exec )
44 {
45    GLuint count = exec->vtx.vert_count;
46    GLuint i;
47 
48    printf("%s: %u vertices %d primitives, %d vertsize\n",
49 	  __func__,
50 	  count,
51 	  exec->vtx.prim_count,
52 	  exec->vtx.vertex_size);
53 
54    for (i = 0 ; i < exec->vtx.prim_count ; i++) {
55       struct _mesa_prim *prim = &exec->vtx.prim[i];
56       printf("   prim %d: %s%s %d..%d %s %s\n",
57 	     i,
58 	     _mesa_lookup_prim_by_nr(prim->mode),
59 	     prim->weak ? " (weak)" : "",
60 	     prim->start,
61 	     prim->start + prim->count,
62 	     prim->begin ? "BEGIN" : "(wrap)",
63 	     prim->end ? "END" : "(wrap)");
64    }
65 }
66 
67 
68 /**
69  * Copy zero, one or two vertices from the current vertex buffer into
70  * the temporary "copy" buffer.
71  * This is used when a single primitive overflows a vertex buffer and
72  * we need to continue the primitive in a new vertex buffer.
73  * The temporary "copy" buffer holds the vertices which need to get
74  * copied from the old buffer to the new one.
75  */
76 static GLuint
vbo_copy_vertices(struct vbo_exec_context * exec)77 vbo_copy_vertices( struct vbo_exec_context *exec )
78 {
79    struct _mesa_prim *last_prim = &exec->vtx.prim[exec->vtx.prim_count - 1];
80    const GLuint nr = last_prim->count;
81    GLuint ovf, i;
82    const GLuint sz = exec->vtx.vertex_size;
83    fi_type *dst = exec->vtx.copied.buffer;
84    const fi_type *src = exec->vtx.buffer_map + last_prim->start * sz;
85 
86    switch (exec->ctx->Driver.CurrentExecPrimitive) {
87    case GL_POINTS:
88       return 0;
89    case GL_LINES:
90       ovf = nr&1;
91       for (i = 0 ; i < ovf ; i++)
92 	 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
93       return i;
94    case GL_TRIANGLES:
95       ovf = nr%3;
96       for (i = 0 ; i < ovf ; i++)
97 	 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
98       return i;
99    case GL_QUADS:
100       ovf = nr&3;
101       for (i = 0 ; i < ovf ; i++)
102 	 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
103       return i;
104    case GL_LINE_STRIP:
105       if (nr == 0) {
106 	 return 0;
107       }
108       else {
109 	 memcpy( dst, src+(nr-1)*sz, sz * sizeof(GLfloat) );
110 	 return 1;
111       }
112    case GL_LINE_LOOP:
113       if (last_prim->begin == 0) {
114          /* We're dealing with the second or later section of a split/wrapped
115           * GL_LINE_LOOP.  Since we're converting line loops to line strips,
116           * we've already increment the last_prim->start counter by one to
117           * skip the 0th vertex in the loop.  We need to undo that (effectively
118           * subtract one from last_prim->start) so that we copy the 0th vertex
119           * to the next vertex buffer.
120           */
121          assert(last_prim->start > 0);
122          src -= sz;
123       }
124       /* fall-through */
125    case GL_TRIANGLE_FAN:
126    case GL_POLYGON:
127       if (nr == 0) {
128 	 return 0;
129       }
130       else if (nr == 1) {
131 	 memcpy( dst, src+0, sz * sizeof(GLfloat) );
132 	 return 1;
133       }
134       else {
135 	 memcpy( dst, src+0, sz * sizeof(GLfloat) );
136 	 memcpy( dst+sz, src+(nr-1)*sz, sz * sizeof(GLfloat) );
137 	 return 2;
138       }
139    case GL_TRIANGLE_STRIP:
140       /* no parity issue, but need to make sure the tri is not drawn twice */
141       if (nr & 1) {
142 	 last_prim->count--;
143       }
144       /* fallthrough */
145    case GL_QUAD_STRIP:
146       switch (nr) {
147       case 0:
148          ovf = 0;
149          break;
150       case 1:
151          ovf = 1;
152          break;
153       default:
154          ovf = 2 + (nr & 1);
155          break;
156       }
157       for (i = 0 ; i < ovf ; i++)
158 	 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
159       return i;
160    case PRIM_OUTSIDE_BEGIN_END:
161       return 0;
162    default:
163       assert(0);
164       return 0;
165    }
166 }
167 
168 
169 
170 /* TODO: populate these as the vertex is defined:
171  */
172 static void
vbo_exec_bind_arrays(struct gl_context * ctx)173 vbo_exec_bind_arrays( struct gl_context *ctx )
174 {
175    struct vbo_context *vbo = vbo_context(ctx);
176    struct vbo_exec_context *exec = &vbo->exec;
177    struct gl_vertex_array *arrays = exec->vtx.arrays;
178    const GLuint *map;
179    GLuint attr;
180    GLbitfield64 varying_inputs = 0x0;
181    bool swap_pos = false;
182 
183    /* Install the default (ie Current) attributes first, then overlay
184     * all active ones.
185     */
186    switch (get_program_mode(exec->ctx)) {
187    case VP_NONE:
188       for (attr = 0; attr < VERT_ATTRIB_FF_MAX; attr++) {
189          exec->vtx.inputs[attr] = &vbo->currval[VBO_ATTRIB_POS+attr];
190       }
191       for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) {
192          assert(VERT_ATTRIB_GENERIC(attr) < ARRAY_SIZE(exec->vtx.inputs));
193          exec->vtx.inputs[VERT_ATTRIB_GENERIC(attr)] =
194             &vbo->currval[VBO_ATTRIB_MAT_FRONT_AMBIENT+attr];
195       }
196       map = vbo->map_vp_none;
197       break;
198    case VP_ARB:
199       for (attr = 0; attr < VERT_ATTRIB_FF_MAX; attr++) {
200          exec->vtx.inputs[attr] = &vbo->currval[VBO_ATTRIB_POS+attr];
201       }
202       for (attr = 0; attr < VERT_ATTRIB_GENERIC_MAX; attr++) {
203          assert(VERT_ATTRIB_GENERIC(attr) < ARRAY_SIZE(exec->vtx.inputs));
204          exec->vtx.inputs[VERT_ATTRIB_GENERIC(attr)] =
205             &vbo->currval[VBO_ATTRIB_GENERIC0+attr];
206       }
207       map = vbo->map_vp_arb;
208 
209       /* check if VERT_ATTRIB_POS is not read but VERT_BIT_GENERIC0 is read.
210        * In that case we effectively need to route the data from
211        * glVertexAttrib(0, val) calls to feed into the GENERIC0 input.
212        * The original state gets essentially restored below.
213        */
214       if ((ctx->VertexProgram._Current->info.inputs_read &
215            VERT_BIT_POS) == 0 &&
216           (ctx->VertexProgram._Current->info.inputs_read &
217            VERT_BIT_GENERIC0)) {
218          swap_pos = true;
219          exec->vtx.inputs[VERT_ATTRIB_GENERIC0] = exec->vtx.inputs[0];
220          exec->vtx.attrsz[VERT_ATTRIB_GENERIC0] = exec->vtx.attrsz[0];
221          exec->vtx.attrtype[VERT_ATTRIB_GENERIC0] = exec->vtx.attrtype[0];
222          exec->vtx.attrptr[VERT_ATTRIB_GENERIC0] = exec->vtx.attrptr[0];
223          exec->vtx.attrsz[0] = 0;
224       }
225       break;
226    default:
227       assert(0);
228    }
229 
230    for (attr = 0; attr < VERT_ATTRIB_MAX ; attr++) {
231       const GLuint src = map[attr];
232 
233       if (exec->vtx.attrsz[src]) {
234 	 GLsizeiptr offset = (GLbyte *)exec->vtx.attrptr[src] -
235 	    (GLbyte *)exec->vtx.vertex;
236 
237          /* override the default array set above */
238          assert(attr < ARRAY_SIZE(exec->vtx.inputs));
239          assert(attr < ARRAY_SIZE(exec->vtx.arrays)); /* arrays[] */
240          exec->vtx.inputs[attr] = &arrays[attr];
241 
242          if (_mesa_is_bufferobj(exec->vtx.bufferobj)) {
243             /* a real buffer obj: Ptr is an offset, not a pointer */
244             assert(exec->vtx.bufferobj->Mappings[MAP_INTERNAL].Pointer);
245             assert(offset >= 0);
246             arrays[attr].Ptr = (GLubyte *)
247                exec->vtx.bufferobj->Mappings[MAP_INTERNAL].Offset + offset;
248          }
249          else {
250             /* Ptr into ordinary app memory */
251             arrays[attr].Ptr = (GLubyte *)exec->vtx.buffer_map + offset;
252          }
253 	 arrays[attr].Size = exec->vtx.attrsz[src];
254 	 arrays[attr].StrideB = exec->vtx.vertex_size * sizeof(GLfloat);
255 	 arrays[attr].Type = exec->vtx.attrtype[src];
256 	 arrays[attr].Integer =
257                vbo_attrtype_to_integer_flag(exec->vtx.attrtype[src]);
258          arrays[attr].Format = GL_RGBA;
259          arrays[attr]._ElementSize = arrays[attr].Size * sizeof(GLfloat);
260          _mesa_reference_buffer_object(ctx,
261                                        &arrays[attr].BufferObj,
262                                        exec->vtx.bufferobj);
263 
264          varying_inputs |= VERT_BIT(attr);
265       }
266    }
267 
268    /* In case we swapped the position and generic0 attribute.
269     * Restore the original setting of the vtx.* variables.
270     * They are still needed with the original order and settings in case
271     * of a split primitive.
272     */
273    if (swap_pos) {
274       exec->vtx.attrsz[0] = exec->vtx.attrsz[VERT_ATTRIB_GENERIC0];
275       exec->vtx.attrsz[VERT_ATTRIB_GENERIC0] = 0;
276    }
277 
278    _mesa_set_varying_vp_inputs( ctx, varying_inputs );
279    ctx->NewDriverState |= ctx->DriverFlags.NewArray;
280 }
281 
282 
283 /**
284  * Unmap the VBO.  This is called before drawing.
285  */
286 static void
vbo_exec_vtx_unmap(struct vbo_exec_context * exec)287 vbo_exec_vtx_unmap( struct vbo_exec_context *exec )
288 {
289    if (_mesa_is_bufferobj(exec->vtx.bufferobj)) {
290       struct gl_context *ctx = exec->ctx;
291 
292       if (ctx->Driver.FlushMappedBufferRange) {
293          GLintptr offset = exec->vtx.buffer_used -
294                            exec->vtx.bufferobj->Mappings[MAP_INTERNAL].Offset;
295          GLsizeiptr length = (exec->vtx.buffer_ptr - exec->vtx.buffer_map) *
296                              sizeof(float);
297 
298          if (length)
299             ctx->Driver.FlushMappedBufferRange(ctx, offset, length,
300                                                exec->vtx.bufferobj,
301                                                MAP_INTERNAL);
302       }
303 
304       exec->vtx.buffer_used += (exec->vtx.buffer_ptr -
305                                 exec->vtx.buffer_map) * sizeof(float);
306 
307       assert(exec->vtx.buffer_used <= VBO_VERT_BUFFER_SIZE);
308       assert(exec->vtx.buffer_ptr != NULL);
309 
310       ctx->Driver.UnmapBuffer(ctx, exec->vtx.bufferobj, MAP_INTERNAL);
311       exec->vtx.buffer_map = NULL;
312       exec->vtx.buffer_ptr = NULL;
313       exec->vtx.max_vert = 0;
314    }
315 }
316 
317 
318 /**
319  * Map the vertex buffer to begin storing glVertex, glColor, etc data.
320  */
321 void
vbo_exec_vtx_map(struct vbo_exec_context * exec)322 vbo_exec_vtx_map( struct vbo_exec_context *exec )
323 {
324    struct gl_context *ctx = exec->ctx;
325    const GLenum accessRange = GL_MAP_WRITE_BIT |  /* for MapBufferRange */
326                               GL_MAP_INVALIDATE_RANGE_BIT |
327                               GL_MAP_UNSYNCHRONIZED_BIT |
328                               GL_MAP_FLUSH_EXPLICIT_BIT |
329                               MESA_MAP_NOWAIT_BIT;
330    const GLenum usage = GL_STREAM_DRAW_ARB;
331 
332    if (!_mesa_is_bufferobj(exec->vtx.bufferobj))
333       return;
334 
335    assert(!exec->vtx.buffer_map);
336    assert(!exec->vtx.buffer_ptr);
337 
338    if (VBO_VERT_BUFFER_SIZE > exec->vtx.buffer_used + 1024) {
339       /* The VBO exists and there's room for more */
340       if (exec->vtx.bufferobj->Size > 0) {
341          exec->vtx.buffer_map =
342             (fi_type *)ctx->Driver.MapBufferRange(ctx,
343                                                   exec->vtx.buffer_used,
344                                                   (VBO_VERT_BUFFER_SIZE -
345                                                    exec->vtx.buffer_used),
346                                                   accessRange,
347                                                   exec->vtx.bufferobj,
348                                                   MAP_INTERNAL);
349          exec->vtx.buffer_ptr = exec->vtx.buffer_map;
350       }
351       else {
352          exec->vtx.buffer_ptr = exec->vtx.buffer_map = NULL;
353       }
354    }
355 
356    if (!exec->vtx.buffer_map) {
357       /* Need to allocate a new VBO */
358       exec->vtx.buffer_used = 0;
359 
360       if (ctx->Driver.BufferData(ctx, GL_ARRAY_BUFFER_ARB,
361                                  VBO_VERT_BUFFER_SIZE,
362                                  NULL, usage,
363                                  GL_MAP_WRITE_BIT |
364                                  GL_DYNAMIC_STORAGE_BIT |
365                                  GL_CLIENT_STORAGE_BIT,
366                                  exec->vtx.bufferobj)) {
367          /* buffer allocation worked, now map the buffer */
368          exec->vtx.buffer_map =
369             (fi_type *)ctx->Driver.MapBufferRange(ctx,
370                                                   0, VBO_VERT_BUFFER_SIZE,
371                                                   accessRange,
372                                                   exec->vtx.bufferobj,
373                                                   MAP_INTERNAL);
374       }
375       else {
376          _mesa_error(ctx, GL_OUT_OF_MEMORY, "VBO allocation");
377          exec->vtx.buffer_map = NULL;
378       }
379    }
380 
381    exec->vtx.buffer_ptr = exec->vtx.buffer_map;
382 
383    if (!exec->vtx.buffer_map) {
384       /* out of memory */
385       _mesa_install_exec_vtxfmt( ctx, &exec->vtxfmt_noop );
386    }
387    else {
388       if (_mesa_using_noop_vtxfmt(ctx->Exec)) {
389          /* The no-op functions are installed so switch back to regular
390           * functions.  We do this test just to avoid frequent and needless
391           * calls to _mesa_install_exec_vtxfmt().
392           */
393          _mesa_install_exec_vtxfmt(ctx, &exec->vtxfmt);
394       }
395    }
396 
397    if (0)
398       printf("map %d..\n", exec->vtx.buffer_used);
399 }
400 
401 
402 
403 /**
404  * Execute the buffer and save copied verts.
405  * \param keep_unmapped  if true, leave the VBO unmapped when we're done.
406  */
407 void
vbo_exec_vtx_flush(struct vbo_exec_context * exec,GLboolean keepUnmapped)408 vbo_exec_vtx_flush(struct vbo_exec_context *exec, GLboolean keepUnmapped)
409 {
410    if (0)
411       vbo_exec_debug_verts( exec );
412 
413    if (exec->vtx.prim_count &&
414        exec->vtx.vert_count) {
415 
416       exec->vtx.copied.nr = vbo_copy_vertices( exec );
417 
418       if (exec->vtx.copied.nr != exec->vtx.vert_count) {
419 	 struct gl_context *ctx = exec->ctx;
420 
421 	 /* Before the update_state() as this may raise _NEW_VARYING_VP_INPUTS
422           * from _mesa_set_varying_vp_inputs().
423 	  */
424 	 vbo_exec_bind_arrays( ctx );
425 
426          if (ctx->NewState)
427             _mesa_update_state( ctx );
428 
429          if (_mesa_is_bufferobj(exec->vtx.bufferobj)) {
430             vbo_exec_vtx_unmap( exec );
431          }
432 
433          if (0)
434             printf("%s %d %d\n", __func__, exec->vtx.prim_count,
435 		   exec->vtx.vert_count);
436 
437 	 vbo_context(ctx)->draw_prims( ctx,
438 				       exec->vtx.prim,
439 				       exec->vtx.prim_count,
440 				       NULL,
441 				       GL_TRUE,
442 				       0,
443 				       exec->vtx.vert_count - 1,
444 				       NULL, 0, NULL);
445 
446 	 /* If using a real VBO, get new storage -- unless asked not to.
447           */
448          if (_mesa_is_bufferobj(exec->vtx.bufferobj) && !keepUnmapped) {
449             vbo_exec_vtx_map( exec );
450          }
451       }
452    }
453 
454    /* May have to unmap explicitly if we didn't draw:
455     */
456    if (keepUnmapped &&
457        _mesa_is_bufferobj(exec->vtx.bufferobj) &&
458        exec->vtx.buffer_map) {
459       vbo_exec_vtx_unmap( exec );
460    }
461 
462    if (keepUnmapped || exec->vtx.vertex_size == 0)
463       exec->vtx.max_vert = 0;
464    else
465       exec->vtx.max_vert = vbo_compute_max_verts(exec);
466 
467    exec->vtx.buffer_ptr = exec->vtx.buffer_map;
468    exec->vtx.prim_count = 0;
469    exec->vtx.vert_count = 0;
470 }
471