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