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 (at) vmware.com> 26 */ 27 28 #include <stdbool.h> 29 #include <stdio.h> 30 #include "main/glheader.h" 31 #include "main/bufferobj.h" 32 #include "main/context.h" 33 #include "main/enums.h" 34 #include "main/state.h" 35 #include "main/vtxfmt.h" 36 37 #include "vbo_context.h" 38 #include "vbo_noop.h" 39 40 41 static void 42 vbo_exec_debug_verts(struct vbo_exec_context *exec) 43 { 44 GLuint count = exec->vtx.vert_count; 45 GLuint i; 46 47 printf("%s: %u vertices %d primitives, %d vertsize\n", 48 __func__, 49 count, 50 exec->vtx.prim_count, 51 exec->vtx.vertex_size); 52 53 for (i = 0 ; i < exec->vtx.prim_count ; i++) { 54 struct _mesa_prim *prim = &exec->vtx.prim[i]; 55 printf(" prim %d: %s%s %d..%d %s %s\n", 56 i, 57 _mesa_lookup_prim_by_nr(prim->mode), 58 prim->weak ? " (weak)" : "", 59 prim->start, 60 prim->start + prim->count, 61 prim->begin ? "BEGIN" : "(wrap)", 62 prim->end ? "END" : "(wrap)"); 63 } 64 } 65 66 67 /** 68 * Copy zero, one or two vertices from the current vertex buffer into 69 * the temporary "copy" buffer. 70 * This is used when a single primitive overflows a vertex buffer and 71 * we need to continue the primitive in a new vertex buffer. 72 * The temporary "copy" buffer holds the vertices which need to get 73 * copied from the old buffer to the new one. 74 */ 75 static GLuint 76 vbo_copy_vertices(struct vbo_exec_context *exec) 77 { 78 struct _mesa_prim *last_prim = &exec->vtx.prim[exec->vtx.prim_count - 1]; 79 const GLuint nr = last_prim->count; 80 GLuint ovf, i; 81 const GLuint sz = exec->vtx.vertex_size; 82 fi_type *dst = exec->vtx.copied.buffer; 83 const fi_type *src = exec->vtx.buffer_map + last_prim->start * sz; 84 85 switch (exec->ctx->Driver.CurrentExecPrimitive) { 86 case GL_POINTS: 87 return 0; 88 case GL_LINES: 89 ovf = nr&1; 90 for (i = 0 ; i < ovf ; i++) 91 memcpy(dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat)); 92 return i; 93 case GL_TRIANGLES: 94 ovf = nr%3; 95 for (i = 0 ; i < ovf ; i++) 96 memcpy(dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat)); 97 return i; 98 case GL_QUADS: 99 ovf = nr&3; 100 for (i = 0 ; i < ovf ; i++) 101 memcpy(dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat)); 102 return i; 103 case GL_LINE_STRIP: 104 if (nr == 0) { 105 return 0; 106 } 107 else { 108 memcpy(dst, src+(nr-1)*sz, sz * sizeof(GLfloat)); 109 return 1; 110 } 111 case GL_LINE_LOOP: 112 if (last_prim->begin == 0) { 113 /* We're dealing with the second or later section of a split/wrapped 114 * GL_LINE_LOOP. Since we're converting line loops to line strips, 115 * we've already increment the last_prim->start counter by one to 116 * skip the 0th vertex in the loop. We need to undo that (effectively 117 * subtract one from last_prim->start) so that we copy the 0th vertex 118 * to the next vertex buffer. 119 */ 120 assert(last_prim->start > 0); 121 src -= sz; 122 } 123 /* fall-through */ 124 case GL_TRIANGLE_FAN: 125 case GL_POLYGON: 126 if (nr == 0) { 127 return 0; 128 } 129 else if (nr == 1) { 130 memcpy(dst, src+0, sz * sizeof(GLfloat)); 131 return 1; 132 } 133 else { 134 memcpy(dst, src+0, sz * sizeof(GLfloat)); 135 memcpy(dst+sz, src+(nr-1)*sz, sz * sizeof(GLfloat)); 136 return 2; 137 } 138 case GL_TRIANGLE_STRIP: 139 /* no parity issue, but need to make sure the tri is not drawn twice */ 140 if (nr & 1) { 141 last_prim->count--; 142 } 143 /* fallthrough */ 144 case GL_QUAD_STRIP: 145 switch (nr) { 146 case 0: 147 ovf = 0; 148 break; 149 case 1: 150 ovf = 1; 151 break; 152 default: 153 ovf = 2 + (nr & 1); 154 break; 155 } 156 for (i = 0 ; i < ovf ; i++) 157 memcpy(dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat)); 158 return i; 159 case PRIM_OUTSIDE_BEGIN_END: 160 return 0; 161 default: 162 assert(0); 163 return 0; 164 } 165 } 166 167 168 169 /* TODO: populate these as the vertex is defined: 170 */ 171 static void 172 vbo_exec_bind_arrays(struct gl_context *ctx) 173 { 174 struct vbo_context *vbo = vbo_context(ctx); 175 struct vbo_exec_context *exec = &vbo->exec; 176 struct gl_vertex_array *arrays = exec->vtx.arrays; 177 const GLubyte *map; 178 GLuint attr; 179 GLbitfield varying_inputs = 0x0; 180 bool swap_pos = false; 181 182 /* Install the default (ie Current) attributes first */ 183 for (attr = 0; attr < VERT_ATTRIB_FF_MAX; attr++) { 184 exec->vtx.inputs[attr] = &vbo->currval[VBO_ATTRIB_POS+attr]; 185 } 186 187 /* Overlay other active attributes */ 188 switch (get_program_mode(exec->ctx)) { 189 case VP_NONE: 190 for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) { 191 assert(VERT_ATTRIB_GENERIC(attr) < ARRAY_SIZE(exec->vtx.inputs)); 192 exec->vtx.inputs[VERT_ATTRIB_GENERIC(attr)] = 193 &vbo->currval[VBO_ATTRIB_MAT_FRONT_AMBIENT+attr]; 194 } 195 map = vbo->map_vp_none; 196 break; 197 case VP_ARB: 198 for (attr = 0; attr < VERT_ATTRIB_GENERIC_MAX; attr++) { 199 assert(VERT_ATTRIB_GENERIC(attr) < ARRAY_SIZE(exec->vtx.inputs)); 200 exec->vtx.inputs[VERT_ATTRIB_GENERIC(attr)] = 201 &vbo->currval[VBO_ATTRIB_GENERIC0+attr]; 202 } 203 map = vbo->map_vp_arb; 204 205 /* check if VERT_ATTRIB_POS is not read but VERT_BIT_GENERIC0 is read. 206 * In that case we effectively need to route the data from 207 * glVertexAttrib(0, val) calls to feed into the GENERIC0 input. 208 * The original state gets essentially restored below. 209 */ 210 const GLbitfield64 inputs_read = 211 ctx->VertexProgram._Current->info.inputs_read; 212 if ((inputs_read & VERT_BIT_POS) == 0 && 213 (inputs_read & VERT_BIT_GENERIC0)) { 214 swap_pos = true; 215 exec->vtx.inputs[VERT_ATTRIB_GENERIC0] = exec->vtx.inputs[0]; 216 exec->vtx.attrsz[VERT_ATTRIB_GENERIC0] = exec->vtx.attrsz[0]; 217 exec->vtx.attrtype[VERT_ATTRIB_GENERIC0] = exec->vtx.attrtype[0]; 218 exec->vtx.attrptr[VERT_ATTRIB_GENERIC0] = exec->vtx.attrptr[0]; 219 exec->vtx.attrsz[0] = 0; 220 } 221 break; 222 default: 223 assert(0); 224 } 225 226 for (attr = 0; attr < VERT_ATTRIB_MAX ; attr++) { 227 const GLuint src = map[attr]; 228 229 if (exec->vtx.attrsz[src]) { 230 GLsizeiptr offset = (GLbyte *)exec->vtx.attrptr[src] - 231 (GLbyte *)exec->vtx.vertex; 232 233 /* override the default array set above */ 234 assert(attr < ARRAY_SIZE(exec->vtx.inputs)); 235 assert(attr < ARRAY_SIZE(exec->vtx.arrays)); /* arrays[] */ 236 exec->vtx.inputs[attr] = &arrays[attr]; 237 238 if (_mesa_is_bufferobj(exec->vtx.bufferobj)) { 239 /* a real buffer obj: Ptr is an offset, not a pointer */ 240 assert(exec->vtx.bufferobj->Mappings[MAP_INTERNAL].Pointer); 241 assert(offset >= 0); 242 arrays[attr].Ptr = (GLubyte *) 243 exec->vtx.bufferobj->Mappings[MAP_INTERNAL].Offset + offset; 244 } 245 else { 246 /* Ptr into ordinary app memory */ 247 arrays[attr].Ptr = (GLubyte *)exec->vtx.buffer_map + offset; 248 } 249 arrays[attr].Size = exec->vtx.attrsz[src]; 250 arrays[attr].StrideB = exec->vtx.vertex_size * sizeof(GLfloat); 251 arrays[attr].Type = exec->vtx.attrtype[src]; 252 arrays[attr].Integer = 253 vbo_attrtype_to_integer_flag(exec->vtx.attrtype[src]); 254 arrays[attr].Format = GL_RGBA; 255 arrays[attr]._ElementSize = arrays[attr].Size * sizeof(GLfloat); 256 _mesa_reference_buffer_object(ctx, 257 &arrays[attr].BufferObj, 258 exec->vtx.bufferobj); 259 260 varying_inputs |= VERT_BIT(attr); 261 } 262 } 263 264 /* In case we swapped the position and generic0 attribute. 265 * Restore the original setting of the vtx.* variables. 266 * They are still needed with the original order and settings in case 267 * of a split primitive. 268 */ 269 if (swap_pos) { 270 exec->vtx.attrsz[0] = exec->vtx.attrsz[VERT_ATTRIB_GENERIC0]; 271 exec->vtx.attrsz[VERT_ATTRIB_GENERIC0] = 0; 272 } 273 274 _mesa_set_varying_vp_inputs(ctx, varying_inputs); 275 ctx->NewDriverState |= ctx->DriverFlags.NewArray; 276 } 277 278 279 /** 280 * Unmap the VBO. This is called before drawing. 281 */ 282 static void 283 vbo_exec_vtx_unmap(struct vbo_exec_context *exec) 284 { 285 if (_mesa_is_bufferobj(exec->vtx.bufferobj)) { 286 struct gl_context *ctx = exec->ctx; 287 288 if (ctx->Driver.FlushMappedBufferRange) { 289 GLintptr offset = exec->vtx.buffer_used - 290 exec->vtx.bufferobj->Mappings[MAP_INTERNAL].Offset; 291 GLsizeiptr length = (exec->vtx.buffer_ptr - exec->vtx.buffer_map) * 292 sizeof(float); 293 294 if (length) 295 ctx->Driver.FlushMappedBufferRange(ctx, offset, length, 296 exec->vtx.bufferobj, 297 MAP_INTERNAL); 298 } 299 300 exec->vtx.buffer_used += (exec->vtx.buffer_ptr - 301 exec->vtx.buffer_map) * sizeof(float); 302 303 assert(exec->vtx.buffer_used <= VBO_VERT_BUFFER_SIZE); 304 assert(exec->vtx.buffer_ptr != NULL); 305 306 ctx->Driver.UnmapBuffer(ctx, exec->vtx.bufferobj, MAP_INTERNAL); 307 exec->vtx.buffer_map = NULL; 308 exec->vtx.buffer_ptr = NULL; 309 exec->vtx.max_vert = 0; 310 } 311 } 312 313 314 /** 315 * Map the vertex buffer to begin storing glVertex, glColor, etc data. 316 */ 317 void 318 vbo_exec_vtx_map(struct vbo_exec_context *exec) 319 { 320 struct gl_context *ctx = exec->ctx; 321 const GLenum accessRange = GL_MAP_WRITE_BIT | /* for MapBufferRange */ 322 GL_MAP_INVALIDATE_RANGE_BIT | 323 GL_MAP_UNSYNCHRONIZED_BIT | 324 GL_MAP_FLUSH_EXPLICIT_BIT | 325 MESA_MAP_NOWAIT_BIT; 326 const GLenum usage = GL_STREAM_DRAW_ARB; 327 328 if (!_mesa_is_bufferobj(exec->vtx.bufferobj)) 329 return; 330 331 assert(!exec->vtx.buffer_map); 332 assert(!exec->vtx.buffer_ptr); 333 334 if (VBO_VERT_BUFFER_SIZE > exec->vtx.buffer_used + 1024) { 335 /* The VBO exists and there's room for more */ 336 if (exec->vtx.bufferobj->Size > 0) { 337 exec->vtx.buffer_map = (fi_type *) 338 ctx->Driver.MapBufferRange(ctx, 339 exec->vtx.buffer_used, 340 VBO_VERT_BUFFER_SIZE 341 - exec->vtx.buffer_used, 342 accessRange, 343 exec->vtx.bufferobj, 344 MAP_INTERNAL); 345 exec->vtx.buffer_ptr = exec->vtx.buffer_map; 346 } 347 else { 348 exec->vtx.buffer_ptr = exec->vtx.buffer_map = NULL; 349 } 350 } 351 352 if (!exec->vtx.buffer_map) { 353 /* Need to allocate a new VBO */ 354 exec->vtx.buffer_used = 0; 355 356 if (ctx->Driver.BufferData(ctx, GL_ARRAY_BUFFER_ARB, 357 VBO_VERT_BUFFER_SIZE, 358 NULL, usage, 359 GL_MAP_WRITE_BIT | 360 GL_DYNAMIC_STORAGE_BIT | 361 GL_CLIENT_STORAGE_BIT, 362 exec->vtx.bufferobj)) { 363 /* buffer allocation worked, now map the buffer */ 364 exec->vtx.buffer_map = 365 (fi_type *)ctx->Driver.MapBufferRange(ctx, 366 0, VBO_VERT_BUFFER_SIZE, 367 accessRange, 368 exec->vtx.bufferobj, 369 MAP_INTERNAL); 370 } 371 else { 372 _mesa_error(ctx, GL_OUT_OF_MEMORY, "VBO allocation"); 373 exec->vtx.buffer_map = NULL; 374 } 375 } 376 377 exec->vtx.buffer_ptr = exec->vtx.buffer_map; 378 379 if (!exec->vtx.buffer_map) { 380 /* out of memory */ 381 _mesa_install_exec_vtxfmt(ctx, &exec->vtxfmt_noop); 382 } 383 else { 384 if (_mesa_using_noop_vtxfmt(ctx->Exec)) { 385 /* The no-op functions are installed so switch back to regular 386 * functions. We do this test just to avoid frequent and needless 387 * calls to _mesa_install_exec_vtxfmt(). 388 */ 389 _mesa_install_exec_vtxfmt(ctx, &exec->vtxfmt); 390 } 391 } 392 393 if (0) 394 printf("map %d..\n", exec->vtx.buffer_used); 395 } 396 397 398 399 /** 400 * Execute the buffer and save copied verts. 401 * \param keep_unmapped if true, leave the VBO unmapped when we're done. 402 */ 403 void 404 vbo_exec_vtx_flush(struct vbo_exec_context *exec, GLboolean keepUnmapped) 405 { 406 if (0) 407 vbo_exec_debug_verts(exec); 408 409 if (exec->vtx.prim_count && 410 exec->vtx.vert_count) { 411 412 exec->vtx.copied.nr = vbo_copy_vertices(exec); 413 414 if (exec->vtx.copied.nr != exec->vtx.vert_count) { 415 struct gl_context *ctx = exec->ctx; 416 417 /* Before the update_state() as this may raise _NEW_VARYING_VP_INPUTS 418 * from _mesa_set_varying_vp_inputs(). 419 */ 420 vbo_exec_bind_arrays(ctx); 421 422 if (ctx->NewState) 423 _mesa_update_state(ctx); 424 425 vbo_exec_vtx_unmap(exec); 426 427 if (0) 428 printf("%s %d %d\n", __func__, exec->vtx.prim_count, 429 exec->vtx.vert_count); 430 431 vbo_context(ctx)->draw_prims(ctx, 432 exec->vtx.prim, 433 exec->vtx.prim_count, 434 NULL, 435 GL_TRUE, 436 0, 437 exec->vtx.vert_count - 1, 438 NULL, 0, NULL); 439 440 /* Get new storage -- unless asked not to. */ 441 if (!keepUnmapped) 442 vbo_exec_vtx_map(exec); 443 } 444 } 445 446 /* May have to unmap explicitly if we didn't draw: 447 */ 448 if (keepUnmapped && exec->vtx.buffer_map) { 449 vbo_exec_vtx_unmap(exec); 450 } 451 452 if (keepUnmapped || exec->vtx.vertex_size == 0) 453 exec->vtx.max_vert = 0; 454 else 455 exec->vtx.max_vert = vbo_compute_max_verts(exec); 456 457 exec->vtx.buffer_ptr = exec->vtx.buffer_map; 458 exec->vtx.prim_count = 0; 459 exec->vtx.vert_count = 0; 460 } 461