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