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/arrayobj.h"
31 #include "main/glheader.h"
32 #include "main/bufferobj.h"
33 #include "main/context.h"
34 #include "main/enums.h"
35 #include "main/state.h"
36 #include "main/varray.h"
37 
38 #include "vbo_private.h"
39 
40 static void
vbo_exec_debug_verts(struct vbo_exec_context *exec)41 vbo_exec_debug_verts(struct vbo_exec_context *exec)
42 {
43    GLuint count = exec->vtx.vert_count;
44    GLuint i;
45 
46    printf("%s: %u vertices %d primitives, %d vertsize\n",
47           __func__,
48           count,
49           exec->vtx.prim_count,
50           exec->vtx.vertex_size);
51 
52    for (i = 0 ; i < exec->vtx.prim_count ; i++) {
53       printf("   prim %d: %s %d..%d %s %s\n",
54              i,
55              _mesa_lookup_prim_by_nr(exec->vtx.mode[i]),
56              exec->vtx.draw[i].start,
57              exec->vtx.draw[i].start + exec->vtx.draw[i].count,
58              exec->vtx.markers[i].begin ? "BEGIN" : "(wrap)",
59              exec->vtx.markers[i].end ? "END" : "(wrap)");
60    }
61 }
62 
63 
64 static GLuint
vbo_exec_copy_vertices(struct vbo_exec_context *exec)65 vbo_exec_copy_vertices(struct vbo_exec_context *exec)
66 {
67    struct gl_context *ctx = gl_context_from_vbo_exec(exec);
68    const GLuint sz = exec->vtx.vertex_size;
69    fi_type *dst = exec->vtx.copied.buffer;
70    unsigned last = exec->vtx.prim_count - 1;
71    unsigned start = exec->vtx.draw[last].start;
72    const fi_type *src = exec->vtx.buffer_map + start * sz;
73 
74    return vbo_copy_vertices(ctx, ctx->Driver.CurrentExecPrimitive,
75                             start,
76                             &exec->vtx.draw[last].count,
77                             exec->vtx.markers[last].begin,
78                             sz, false, dst, src);
79 }
80 
81 
82 
83 /* TODO: populate these as the vertex is defined:
84  */
85 static void
vbo_exec_bind_arrays(struct gl_context *ctx)86 vbo_exec_bind_arrays(struct gl_context *ctx)
87 {
88    struct vbo_context *vbo = vbo_context(ctx);
89    struct gl_vertex_array_object *vao = vbo->VAO;
90    struct vbo_exec_context *exec = &vbo->exec;
91 
92    GLintptr buffer_offset;
93    if (exec->vtx.bufferobj) {
94       assert(exec->vtx.bufferobj->Mappings[MAP_INTERNAL].Pointer);
95       buffer_offset = exec->vtx.bufferobj->Mappings[MAP_INTERNAL].Offset +
96                       exec->vtx.buffer_offset;
97    } else {
98       /* Ptr into ordinary app memory */
99       buffer_offset = (GLbyte *)exec->vtx.buffer_map - (GLbyte *)NULL;
100    }
101 
102    const gl_vertex_processing_mode mode = ctx->VertexProgram._VPMode;
103 
104    GLbitfield vao_enabled, vao_filter;
105    if (_mesa_hw_select_enabled(ctx)) {
106       /* HW GL_SELECT has fixed input */
107       vao_enabled = vao_filter = VERT_BIT_POS | VERT_BIT_SELECT_RESULT_OFFSET;
108    } else {
109       vao_enabled = _vbo_get_vao_enabled_from_vbo(mode, exec->vtx.enabled);
110       vao_filter = _vbo_get_vao_filter(mode);
111    }
112 
113    /* At first disable arrays no longer needed */
114    _mesa_disable_vertex_array_attribs(ctx, vao, VERT_BIT_ALL & ~vao_enabled);
115    assert((~vao_enabled & vao->Enabled) == 0);
116 
117    /* Bind the buffer object */
118    const GLuint stride = exec->vtx.vertex_size*sizeof(GLfloat);
119    _mesa_bind_vertex_buffer(ctx, vao, 0, exec->vtx.bufferobj, buffer_offset,
120                             stride, false, false);
121 
122    /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space
123     * Note that the position/generic0 aliasing is done in the VAO.
124     */
125    const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode];
126    /* Now set the enabled arrays */
127    GLbitfield mask = vao_enabled;
128    while (mask) {
129       const int vao_attr = u_bit_scan(&mask);
130       const GLubyte vbo_attr = vao_to_vbo_map[vao_attr];
131 
132       const GLubyte size = exec->vtx.attr[vbo_attr].size;
133       const GLenum16 type = exec->vtx.attr[vbo_attr].type;
134       const GLuint offset = (GLuint)((GLbyte *)exec->vtx.attrptr[vbo_attr] -
135                                      (GLbyte *)exec->vtx.vertex);
136       assert(offset <= ctx->Const.MaxVertexAttribRelativeOffset);
137 
138       /* Set and enable */
139       _vbo_set_attrib_format(ctx, vao, vao_attr, buffer_offset,
140                              size, type, offset);
141 
142       /* The vao is initially created with all bindings set to 0. */
143       assert(vao->VertexAttrib[vao_attr].BufferBindingIndex == 0);
144    }
145    _mesa_enable_vertex_array_attribs(ctx, vao, vao_enabled);
146    assert(vao_enabled == vao->Enabled);
147    assert(!exec->vtx.bufferobj ||
148           (vao_enabled & ~vao->VertexAttribBufferMask) == 0);
149 
150    _mesa_set_draw_vao(ctx, vao, vao_filter);
151 }
152 
153 
154 /**
155  * Unmap the VBO.  This is called before drawing.
156  */
157 static void
vbo_exec_vtx_unmap(struct vbo_exec_context *exec)158 vbo_exec_vtx_unmap(struct vbo_exec_context *exec)
159 {
160    if (exec->vtx.bufferobj) {
161       struct gl_context *ctx = gl_context_from_vbo_exec(exec);
162 
163       if (!ctx->Extensions.ARB_buffer_storage) {
164          GLintptr offset = exec->vtx.buffer_used -
165                            exec->vtx.bufferobj->Mappings[MAP_INTERNAL].Offset;
166          GLsizeiptr length = (exec->vtx.buffer_ptr - exec->vtx.buffer_map) *
167                              sizeof(float);
168 
169          if (length)
170             _mesa_bufferobj_flush_mapped_range(ctx, offset, length,
171                                                exec->vtx.bufferobj,
172                                                MAP_INTERNAL);
173       }
174 
175       exec->vtx.buffer_used += (exec->vtx.buffer_ptr -
176                                 exec->vtx.buffer_map) * sizeof(float);
177 
178       assert(exec->vtx.buffer_used <= ctx->Const.glBeginEndBufferSize);
179       assert(exec->vtx.buffer_ptr != NULL);
180 
181       _mesa_bufferobj_unmap(ctx, exec->vtx.bufferobj, MAP_INTERNAL);
182       exec->vtx.buffer_map = NULL;
183       exec->vtx.buffer_ptr = NULL;
184       exec->vtx.max_vert = 0;
185    }
186 }
187 
188 static bool
vbo_exec_buffer_has_space(struct vbo_exec_context *exec)189 vbo_exec_buffer_has_space(struct vbo_exec_context *exec)
190 {
191    struct gl_context *ctx = gl_context_from_vbo_exec(exec);
192 
193    return ctx->Const.glBeginEndBufferSize > exec->vtx.buffer_used + 1024;
194 }
195 
196 
197 /**
198  * Map the vertex buffer to begin storing glVertex, glColor, etc data.
199  */
200 void
vbo_exec_vtx_map(struct vbo_exec_context *exec)201 vbo_exec_vtx_map(struct vbo_exec_context *exec)
202 {
203    struct gl_context *ctx = gl_context_from_vbo_exec(exec);
204    const GLenum usage = GL_STREAM_DRAW_ARB;
205    GLenum accessRange = GL_MAP_WRITE_BIT |  /* for MapBufferRange */
206                         GL_MAP_UNSYNCHRONIZED_BIT;
207 
208    if (ctx->Extensions.ARB_buffer_storage) {
209       /* We sometimes read from the buffer, so map it for read too.
210        * Only the persistent mapping can do that, because the non-persistent
211        * mapping uses flags that are incompatible with GL_MAP_READ_BIT.
212        */
213       accessRange |= GL_MAP_PERSISTENT_BIT |
214                      GL_MAP_COHERENT_BIT |
215                      GL_MAP_READ_BIT;
216    } else {
217       accessRange |= GL_MAP_INVALIDATE_RANGE_BIT |
218                      GL_MAP_FLUSH_EXPLICIT_BIT |
219                      MESA_MAP_NOWAIT_BIT;
220    }
221 
222    if (!exec->vtx.bufferobj)
223       return;
224 
225    assert(!exec->vtx.buffer_map);
226    assert(!exec->vtx.buffer_ptr);
227 
228    if (vbo_exec_buffer_has_space(exec)) {
229       /* The VBO exists and there's room for more */
230       if (exec->vtx.bufferobj->Size > 0) {
231          exec->vtx.buffer_map = (fi_type *)
232             _mesa_bufferobj_map_range(ctx,
233                                       exec->vtx.buffer_used,
234                                       ctx->Const.glBeginEndBufferSize
235                                       - exec->vtx.buffer_used,
236                                       accessRange,
237                                       exec->vtx.bufferobj,
238                                       MAP_INTERNAL);
239          exec->vtx.buffer_ptr = exec->vtx.buffer_map;
240       }
241       else {
242          exec->vtx.buffer_ptr = exec->vtx.buffer_map = NULL;
243       }
244    }
245 
246    if (!exec->vtx.buffer_map) {
247       /* Need to allocate a new VBO */
248       exec->vtx.buffer_used = 0;
249 
250       if (_mesa_bufferobj_data(ctx, GL_ARRAY_BUFFER_ARB,
251                                ctx->Const.glBeginEndBufferSize,
252                                NULL, usage,
253                                GL_MAP_WRITE_BIT |
254                                (ctx->Extensions.ARB_buffer_storage ?
255                                 GL_MAP_PERSISTENT_BIT |
256                                 GL_MAP_COHERENT_BIT |
257                                 GL_MAP_READ_BIT : 0) |
258                                GL_DYNAMIC_STORAGE_BIT |
259                                GL_CLIENT_STORAGE_BIT,
260                                exec->vtx.bufferobj)) {
261          /* buffer allocation worked, now map the buffer */
262          exec->vtx.buffer_map =
263             (fi_type *)_mesa_bufferobj_map_range(ctx,
264                                                  0, ctx->Const.glBeginEndBufferSize,
265                                                  accessRange,
266                                                  exec->vtx.bufferobj,
267                                                  MAP_INTERNAL);
268       }
269       else {
270          _mesa_error(ctx, GL_OUT_OF_MEMORY, "VBO allocation");
271          exec->vtx.buffer_map = NULL;
272       }
273    }
274 
275    exec->vtx.buffer_ptr = exec->vtx.buffer_map;
276    exec->vtx.buffer_offset = 0;
277 
278    if (!exec->vtx.buffer_map) {
279       /* out of memory */
280       vbo_install_exec_vtxfmt_noop(ctx);
281    }
282    else {
283       if (_mesa_using_noop_vtxfmt(ctx->Exec)) {
284          /* The no-op functions are installed so switch back to regular
285           * functions.  We do this test just to avoid frequent and needless
286           * calls to vbo_install_exec_vtxfmt().
287           */
288          vbo_install_exec_vtxfmt(ctx);
289       }
290    }
291 
292    if (0)
293       printf("map %d..\n", exec->vtx.buffer_used);
294 }
295 
296 
297 
298 /**
299  * Execute the buffer and save copied verts.
300  */
301 void
vbo_exec_vtx_flush(struct vbo_exec_context *exec)302 vbo_exec_vtx_flush(struct vbo_exec_context *exec)
303 {
304    struct gl_context *ctx = gl_context_from_vbo_exec(exec);
305 
306    /* Only unmap if persistent mappings are unsupported. */
307    bool persistent_mapping = ctx->Extensions.ARB_buffer_storage &&
308                              exec->vtx.bufferobj &&
309                              exec->vtx.buffer_map;
310 
311    if (0)
312       vbo_exec_debug_verts(exec);
313 
314    if (exec->vtx.prim_count &&
315        exec->vtx.vert_count) {
316 
317       exec->vtx.copied.nr = vbo_exec_copy_vertices(exec);
318 
319       if (exec->vtx.copied.nr != exec->vtx.vert_count) {
320          /* Prepare and set the exec draws internal VAO for drawing. */
321          vbo_exec_bind_arrays(ctx);
322 
323          if (ctx->NewState)
324             _mesa_update_state(ctx);
325 
326          if (!persistent_mapping)
327             vbo_exec_vtx_unmap(exec);
328 
329          assert(ctx->NewState == 0);
330 
331          if (0)
332             printf("%s %d %d\n", __func__, exec->vtx.prim_count,
333                    exec->vtx.vert_count);
334 
335          ctx->Driver.DrawGalliumMultiMode(ctx, &exec->vtx.info,
336                                           exec->vtx.draw,
337                                           exec->vtx.mode,
338                                           exec->vtx.prim_count);
339 
340          /* Get new storage -- unless asked not to. */
341          if (!persistent_mapping)
342             vbo_exec_vtx_map(exec);
343       }
344    }
345 
346    if (persistent_mapping) {
347       exec->vtx.buffer_used += (exec->vtx.buffer_ptr - exec->vtx.buffer_map) *
348                                sizeof(float);
349       exec->vtx.buffer_map = exec->vtx.buffer_ptr;
350 
351       /* Set the buffer offset for the next draw. */
352       exec->vtx.buffer_offset = exec->vtx.buffer_used;
353 
354       if (!vbo_exec_buffer_has_space(exec)) {
355          /* This will allocate a new buffer. */
356          vbo_exec_vtx_unmap(exec);
357          vbo_exec_vtx_map(exec);
358       }
359    }
360 
361    if (exec->vtx.vertex_size == 0)
362       exec->vtx.max_vert = 0;
363    else
364       exec->vtx.max_vert = vbo_compute_max_verts(exec);
365 
366    exec->vtx.buffer_ptr = exec->vtx.buffer_map;
367    exec->vtx.prim_count = 0;
368    exec->vtx.vert_count = 0;
369 }
370