vbo_exec_draw.c revision d8407755
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 43static void 44vbo_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 struct _mesa_prim *prim = &exec->vtx.prim[i]; 57 printf(" prim %d: %s %d..%d %s %s\n", 58 i, 59 _mesa_lookup_prim_by_nr(prim->mode), 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 */ 76static GLuint 77vbo_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 unreachable("Unexpected primitive type"); 164 return 0; 165 } 166} 167 168 169 170/* TODO: populate these as the vertex is defined: 171 */ 172static void 173vbo_exec_bind_arrays(struct gl_context *ctx) 174{ 175 struct vbo_context *vbo = vbo_context(ctx); 176 struct gl_vertex_array_object *vao = vbo->VAO; 177 struct vbo_exec_context *exec = &vbo->exec; 178 179 GLintptr buffer_offset; 180 if (_mesa_is_bufferobj(exec->vtx.bufferobj)) { 181 assert(exec->vtx.bufferobj->Mappings[MAP_INTERNAL].Pointer); 182 buffer_offset = exec->vtx.bufferobj->Mappings[MAP_INTERNAL].Offset; 183 } else { 184 /* Ptr into ordinary app memory */ 185 buffer_offset = (GLbyte *)exec->vtx.buffer_map - (GLbyte *)NULL; 186 } 187 188 const gl_vertex_processing_mode mode = ctx->VertexProgram._VPMode; 189 190 /* Compute the bitmasks of vao_enabled arrays */ 191 GLbitfield vao_enabled = _vbo_get_vao_enabled_from_vbo(mode, exec->vtx.enabled); 192 193 /* At first disable arrays no longer needed */ 194 _mesa_disable_vertex_array_attribs(ctx, vao, VERT_BIT_ALL & ~vao_enabled); 195 assert((~vao_enabled & vao->Enabled) == 0); 196 197 /* Bind the buffer object */ 198 const GLuint stride = exec->vtx.vertex_size*sizeof(GLfloat); 199 _mesa_bind_vertex_buffer(ctx, vao, 0, exec->vtx.bufferobj, buffer_offset, 200 stride); 201 202 /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space 203 * Note that the position/generic0 aliasing is done in the VAO. 204 */ 205 const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode]; 206 /* Now set the enabled arrays */ 207 GLbitfield mask = vao_enabled; 208 while (mask) { 209 const int vao_attr = u_bit_scan(&mask); 210 const GLubyte vbo_attr = vao_to_vbo_map[vao_attr]; 211 212 const GLubyte size = exec->vtx.attrsz[vbo_attr]; 213 const GLenum16 type = exec->vtx.attrtype[vbo_attr]; 214 const GLuint offset = (GLuint)((GLbyte *)exec->vtx.attrptr[vbo_attr] - 215 (GLbyte *)exec->vtx.vertex); 216 assert(offset <= ctx->Const.MaxVertexAttribRelativeOffset); 217 218 /* Set and enable */ 219 _vbo_set_attrib_format(ctx, vao, vao_attr, buffer_offset, 220 size, type, offset); 221 222 /* The vao is initially created with all bindings set to 0. */ 223 assert(vao->VertexAttrib[vao_attr].BufferBindingIndex == 0); 224 } 225 _mesa_enable_vertex_array_attribs(ctx, vao, vao_enabled); 226 assert(vao_enabled == vao->Enabled); 227 assert(!_mesa_is_bufferobj(exec->vtx.bufferobj) || 228 (vao_enabled & ~vao->VertexAttribBufferMask) == 0); 229 230 _mesa_set_draw_vao(ctx, vao, _vbo_get_vao_filter(mode)); 231} 232 233 234/** 235 * Unmap the VBO. This is called before drawing. 236 */ 237static void 238vbo_exec_vtx_unmap(struct vbo_exec_context *exec) 239{ 240 if (_mesa_is_bufferobj(exec->vtx.bufferobj)) { 241 struct gl_context *ctx = exec->ctx; 242 243 if (ctx->Driver.FlushMappedBufferRange) { 244 GLintptr offset = exec->vtx.buffer_used - 245 exec->vtx.bufferobj->Mappings[MAP_INTERNAL].Offset; 246 GLsizeiptr length = (exec->vtx.buffer_ptr - exec->vtx.buffer_map) * 247 sizeof(float); 248 249 if (length) 250 ctx->Driver.FlushMappedBufferRange(ctx, offset, length, 251 exec->vtx.bufferobj, 252 MAP_INTERNAL); 253 } 254 255 exec->vtx.buffer_used += (exec->vtx.buffer_ptr - 256 exec->vtx.buffer_map) * sizeof(float); 257 258 assert(exec->vtx.buffer_used <= VBO_VERT_BUFFER_SIZE); 259 assert(exec->vtx.buffer_ptr != NULL); 260 261 ctx->Driver.UnmapBuffer(ctx, exec->vtx.bufferobj, MAP_INTERNAL); 262 exec->vtx.buffer_map = NULL; 263 exec->vtx.buffer_ptr = NULL; 264 exec->vtx.max_vert = 0; 265 } 266} 267 268 269/** 270 * Map the vertex buffer to begin storing glVertex, glColor, etc data. 271 */ 272void 273vbo_exec_vtx_map(struct vbo_exec_context *exec) 274{ 275 struct gl_context *ctx = exec->ctx; 276 const GLenum accessRange = GL_MAP_WRITE_BIT | /* for MapBufferRange */ 277 GL_MAP_INVALIDATE_RANGE_BIT | 278 GL_MAP_UNSYNCHRONIZED_BIT | 279 GL_MAP_FLUSH_EXPLICIT_BIT | 280 MESA_MAP_NOWAIT_BIT; 281 const GLenum usage = GL_STREAM_DRAW_ARB; 282 283 if (!_mesa_is_bufferobj(exec->vtx.bufferobj)) 284 return; 285 286 assert(!exec->vtx.buffer_map); 287 assert(!exec->vtx.buffer_ptr); 288 289 if (VBO_VERT_BUFFER_SIZE > exec->vtx.buffer_used + 1024) { 290 /* The VBO exists and there's room for more */ 291 if (exec->vtx.bufferobj->Size > 0) { 292 exec->vtx.buffer_map = (fi_type *) 293 ctx->Driver.MapBufferRange(ctx, 294 exec->vtx.buffer_used, 295 VBO_VERT_BUFFER_SIZE 296 - exec->vtx.buffer_used, 297 accessRange, 298 exec->vtx.bufferobj, 299 MAP_INTERNAL); 300 exec->vtx.buffer_ptr = exec->vtx.buffer_map; 301 } 302 else { 303 exec->vtx.buffer_ptr = exec->vtx.buffer_map = NULL; 304 } 305 } 306 307 if (!exec->vtx.buffer_map) { 308 /* Need to allocate a new VBO */ 309 exec->vtx.buffer_used = 0; 310 311 if (ctx->Driver.BufferData(ctx, GL_ARRAY_BUFFER_ARB, 312 VBO_VERT_BUFFER_SIZE, 313 NULL, usage, 314 GL_MAP_WRITE_BIT | 315 GL_DYNAMIC_STORAGE_BIT | 316 GL_CLIENT_STORAGE_BIT, 317 exec->vtx.bufferobj)) { 318 /* buffer allocation worked, now map the buffer */ 319 exec->vtx.buffer_map = 320 (fi_type *)ctx->Driver.MapBufferRange(ctx, 321 0, VBO_VERT_BUFFER_SIZE, 322 accessRange, 323 exec->vtx.bufferobj, 324 MAP_INTERNAL); 325 } 326 else { 327 _mesa_error(ctx, GL_OUT_OF_MEMORY, "VBO allocation"); 328 exec->vtx.buffer_map = NULL; 329 } 330 } 331 332 exec->vtx.buffer_ptr = exec->vtx.buffer_map; 333 334 if (!exec->vtx.buffer_map) { 335 /* out of memory */ 336 _mesa_install_exec_vtxfmt(ctx, &exec->vtxfmt_noop); 337 } 338 else { 339 if (_mesa_using_noop_vtxfmt(ctx->Exec)) { 340 /* The no-op functions are installed so switch back to regular 341 * functions. We do this test just to avoid frequent and needless 342 * calls to _mesa_install_exec_vtxfmt(). 343 */ 344 _mesa_install_exec_vtxfmt(ctx, &exec->vtxfmt); 345 } 346 } 347 348 if (0) 349 printf("map %d..\n", exec->vtx.buffer_used); 350} 351 352 353 354/** 355 * Execute the buffer and save copied verts. 356 * \param keep_unmapped if true, leave the VBO unmapped when we're done. 357 */ 358void 359vbo_exec_vtx_flush(struct vbo_exec_context *exec, GLboolean keepUnmapped) 360{ 361 if (0) 362 vbo_exec_debug_verts(exec); 363 364 if (exec->vtx.prim_count && 365 exec->vtx.vert_count) { 366 367 exec->vtx.copied.nr = vbo_copy_vertices(exec); 368 369 if (exec->vtx.copied.nr != exec->vtx.vert_count) { 370 struct gl_context *ctx = exec->ctx; 371 372 /* Before the update_state() as this may raise _NEW_VARYING_VP_INPUTS 373 * from _mesa_set_varying_vp_inputs(). 374 */ 375 vbo_exec_bind_arrays(ctx); 376 377 if (ctx->NewState) 378 _mesa_update_state(ctx); 379 380 vbo_exec_vtx_unmap(exec); 381 382 assert(ctx->NewState == 0); 383 384 if (0) 385 printf("%s %d %d\n", __func__, exec->vtx.prim_count, 386 exec->vtx.vert_count); 387 388 ctx->Driver.Draw(ctx, exec->vtx.prim, exec->vtx.prim_count, 389 NULL, GL_TRUE, 0, exec->vtx.vert_count - 1, 390 NULL, 0, NULL); 391 392 /* Get new storage -- unless asked not to. */ 393 if (!keepUnmapped) 394 vbo_exec_vtx_map(exec); 395 } 396 } 397 398 /* May have to unmap explicitly if we didn't draw: 399 */ 400 if (keepUnmapped && exec->vtx.buffer_map) { 401 vbo_exec_vtx_unmap(exec); 402 } 403 404 if (keepUnmapped || exec->vtx.vertex_size == 0) 405 exec->vtx.max_vert = 0; 406 else 407 exec->vtx.max_vert = vbo_compute_max_verts(exec); 408 409 exec->vtx.buffer_ptr = exec->vtx.buffer_map; 410 exec->vtx.prim_count = 0; 411 exec->vtx.vert_count = 0; 412} 413