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