17117f1b4Smrg/* 27117f1b4Smrg * Mesa 3-D graphics library 37117f1b4Smrg * 4c1f859d4Smrg * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 57117f1b4Smrg * 67117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 77117f1b4Smrg * copy of this software and associated documentation files (the "Software"), 87117f1b4Smrg * to deal in the Software without restriction, including without limitation 97117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 107117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the 117117f1b4Smrg * Software is furnished to do so, subject to the following conditions: 127117f1b4Smrg * 137117f1b4Smrg * The above copyright notice and this permission notice shall be included 147117f1b4Smrg * in all copies or substantial portions of the Software. 157117f1b4Smrg * 167117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 177117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 187117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19b167d5e7Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20b167d5e7Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21b167d5e7Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22b167d5e7Smrg * OTHER DEALINGS IN THE SOFTWARE. 237117f1b4Smrg * 247117f1b4Smrg * Authors: 25b167d5e7Smrg * Keith Whitwell <keithw@vmware.com> 267117f1b4Smrg */ 277117f1b4Smrg 287e995a2eSmrg#include <stdbool.h> 297e995a2eSmrg#include <stdio.h> 307e995a2eSmrg#include "main/arrayobj.h" 31c1f859d4Smrg#include "main/glheader.h" 32c1f859d4Smrg#include "main/bufferobj.h" 33b167d5e7Smrg#include "main/context.h" 34c1f859d4Smrg#include "main/enums.h" 35c1f859d4Smrg#include "main/state.h" 367e995a2eSmrg#include "main/varray.h" 37b167d5e7Smrg#include "main/vtxfmt.h" 387117f1b4Smrg 39b167d5e7Smrg#include "vbo_noop.h" 407e995a2eSmrg#include "vbo_private.h" 4156e89960Smrg 4256e89960Smrg 4356e89960Smrgstatic void 447e995a2eSmrgvbo_exec_debug_verts(struct vbo_exec_context *exec) 457117f1b4Smrg{ 467117f1b4Smrg GLuint count = exec->vtx.vert_count; 477117f1b4Smrg GLuint i; 487117f1b4Smrg 491f16d945Smrg printf("%s: %u vertices %d primitives, %d vertsize\n", 507e995a2eSmrg __func__, 517e995a2eSmrg count, 527e995a2eSmrg exec->vtx.prim_count, 537e995a2eSmrg exec->vtx.vertex_size); 547117f1b4Smrg 557117f1b4Smrg for (i = 0 ; i < exec->vtx.prim_count ; i++) { 567e995a2eSmrg printf(" prim %d: %s %d..%d %s %s\n", 577e995a2eSmrg i, 581463c08dSmrg _mesa_lookup_prim_by_nr(exec->vtx.mode[i]), 591463c08dSmrg exec->vtx.draw[i].start, 601463c08dSmrg exec->vtx.draw[i].start + exec->vtx.draw[i].count, 611463c08dSmrg exec->vtx.markers[i].begin ? "BEGIN" : "(wrap)", 621463c08dSmrg exec->vtx.markers[i].end ? "END" : "(wrap)"); 637117f1b4Smrg } 647117f1b4Smrg} 657117f1b4Smrg 667117f1b4Smrg 6756e89960Smrgstatic GLuint 681463c08dSmrgvbo_exec_copy_vertices(struct vbo_exec_context *exec) 697117f1b4Smrg{ 701463c08dSmrg struct gl_context *ctx = gl_context_from_vbo_exec(exec); 717e995a2eSmrg const GLuint sz = exec->vtx.vertex_size; 727e995a2eSmrg fi_type *dst = exec->vtx.copied.buffer; 731463c08dSmrg unsigned last = exec->vtx.prim_count - 1; 741463c08dSmrg unsigned start = exec->vtx.draw[last].start; 751463c08dSmrg const fi_type *src = exec->vtx.buffer_map + start * sz; 761463c08dSmrg 771463c08dSmrg return vbo_copy_vertices(ctx, ctx->Driver.CurrentExecPrimitive, 781463c08dSmrg start, 791463c08dSmrg &exec->vtx.draw[last].count, 801463c08dSmrg exec->vtx.markers[last].begin, 811463c08dSmrg sz, false, dst, src); 827117f1b4Smrg} 837117f1b4Smrg 847117f1b4Smrg 857117f1b4Smrg 867117f1b4Smrg/* TODO: populate these as the vertex is defined: 877117f1b4Smrg */ 8856e89960Smrgstatic void 897e995a2eSmrgvbo_exec_bind_arrays(struct gl_context *ctx) 907117f1b4Smrg{ 917117f1b4Smrg struct vbo_context *vbo = vbo_context(ctx); 927e995a2eSmrg struct gl_vertex_array_object *vao = vbo->VAO; 937117f1b4Smrg struct vbo_exec_context *exec = &vbo->exec; 947e995a2eSmrg 957e995a2eSmrg GLintptr buffer_offset; 961463c08dSmrg if (exec->vtx.bufferobj) { 977e995a2eSmrg assert(exec->vtx.bufferobj->Mappings[MAP_INTERNAL].Pointer); 981463c08dSmrg buffer_offset = exec->vtx.bufferobj->Mappings[MAP_INTERNAL].Offset + 991463c08dSmrg exec->vtx.buffer_offset; 1007e995a2eSmrg } else { 1017e995a2eSmrg /* Ptr into ordinary app memory */ 1027e995a2eSmrg buffer_offset = (GLbyte *)exec->vtx.buffer_map - (GLbyte *)NULL; 1037117f1b4Smrg } 1047117f1b4Smrg 1057e995a2eSmrg const gl_vertex_processing_mode mode = ctx->VertexProgram._VPMode; 1067e995a2eSmrg 1077e995a2eSmrg /* Compute the bitmasks of vao_enabled arrays */ 1087e995a2eSmrg GLbitfield vao_enabled = _vbo_get_vao_enabled_from_vbo(mode, exec->vtx.enabled); 1097e995a2eSmrg 1107e995a2eSmrg /* At first disable arrays no longer needed */ 111d8407755Smaya _mesa_disable_vertex_array_attribs(ctx, vao, VERT_BIT_ALL & ~vao_enabled); 112d8407755Smaya assert((~vao_enabled & vao->Enabled) == 0); 1137e995a2eSmrg 1147e995a2eSmrg /* Bind the buffer object */ 1157e995a2eSmrg const GLuint stride = exec->vtx.vertex_size*sizeof(GLfloat); 1167e995a2eSmrg _mesa_bind_vertex_buffer(ctx, vao, 0, exec->vtx.bufferobj, buffer_offset, 1171463c08dSmrg stride, false, false); 11856e89960Smrg 1197e995a2eSmrg /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space 1207e995a2eSmrg * Note that the position/generic0 aliasing is done in the VAO. 1217e995a2eSmrg */ 1227e995a2eSmrg const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode]; 1237e995a2eSmrg /* Now set the enabled arrays */ 124d8407755Smaya GLbitfield mask = vao_enabled; 1257e995a2eSmrg while (mask) { 1267e995a2eSmrg const int vao_attr = u_bit_scan(&mask); 1277e995a2eSmrg const GLubyte vbo_attr = vao_to_vbo_map[vao_attr]; 1287e995a2eSmrg 1291463c08dSmrg const GLubyte size = exec->vtx.attr[vbo_attr].size; 1301463c08dSmrg const GLenum16 type = exec->vtx.attr[vbo_attr].type; 1317e995a2eSmrg const GLuint offset = (GLuint)((GLbyte *)exec->vtx.attrptr[vbo_attr] - 1327e995a2eSmrg (GLbyte *)exec->vtx.vertex); 1337e995a2eSmrg assert(offset <= ctx->Const.MaxVertexAttribRelativeOffset); 1347e995a2eSmrg 1357e995a2eSmrg /* Set and enable */ 1367e995a2eSmrg _vbo_set_attrib_format(ctx, vao, vao_attr, buffer_offset, 1377e995a2eSmrg size, type, offset); 1387e995a2eSmrg 1397e995a2eSmrg /* The vao is initially created with all bindings set to 0. */ 1407e995a2eSmrg assert(vao->VertexAttrib[vao_attr].BufferBindingIndex == 0); 1417e995a2eSmrg } 142d8407755Smaya _mesa_enable_vertex_array_attribs(ctx, vao, vao_enabled); 143d8407755Smaya assert(vao_enabled == vao->Enabled); 1441463c08dSmrg assert(!exec->vtx.bufferobj || 1457e995a2eSmrg (vao_enabled & ~vao->VertexAttribBufferMask) == 0); 1467e995a2eSmrg 1477e995a2eSmrg _mesa_set_draw_vao(ctx, vao, _vbo_get_vao_filter(mode)); 1487117f1b4Smrg} 1497117f1b4Smrg 1507117f1b4Smrg 151ac997013Sriastradh/** 152ac997013Sriastradh * Unmap the VBO. This is called before drawing. 153ac997013Sriastradh */ 15456e89960Smrgstatic void 1557e995a2eSmrgvbo_exec_vtx_unmap(struct vbo_exec_context *exec) 15656e89960Smrg{ 1571463c08dSmrg if (exec->vtx.bufferobj) { 1581463c08dSmrg struct gl_context *ctx = gl_context_from_vbo_exec(exec); 1597e995a2eSmrg 1601463c08dSmrg if (ctx->Driver.FlushMappedBufferRange && 1611463c08dSmrg !ctx->Extensions.ARB_buffer_storage) { 162b167d5e7Smrg GLintptr offset = exec->vtx.buffer_used - 163b167d5e7Smrg exec->vtx.bufferobj->Mappings[MAP_INTERNAL].Offset; 164b167d5e7Smrg GLsizeiptr length = (exec->vtx.buffer_ptr - exec->vtx.buffer_map) * 165b167d5e7Smrg sizeof(float); 16656e89960Smrg 16756e89960Smrg if (length) 168b167d5e7Smrg ctx->Driver.FlushMappedBufferRange(ctx, offset, length, 169b167d5e7Smrg exec->vtx.bufferobj, 170b167d5e7Smrg MAP_INTERNAL); 17156e89960Smrg } 17256e89960Smrg 17356e89960Smrg exec->vtx.buffer_used += (exec->vtx.buffer_ptr - 17456e89960Smrg exec->vtx.buffer_map) * sizeof(float); 17556e89960Smrg 1761463c08dSmrg assert(exec->vtx.buffer_used <= ctx->Const.glBeginEndBufferSize); 17756e89960Smrg assert(exec->vtx.buffer_ptr != NULL); 1787e995a2eSmrg 179b167d5e7Smrg ctx->Driver.UnmapBuffer(ctx, exec->vtx.bufferobj, MAP_INTERNAL); 18056e89960Smrg exec->vtx.buffer_map = NULL; 18156e89960Smrg exec->vtx.buffer_ptr = NULL; 18256e89960Smrg exec->vtx.max_vert = 0; 18356e89960Smrg } 18456e89960Smrg} 18556e89960Smrg 1861463c08dSmrgstatic bool 1871463c08dSmrgvbo_exec_buffer_has_space(struct vbo_exec_context *exec) 1881463c08dSmrg{ 1891463c08dSmrg struct gl_context *ctx = gl_context_from_vbo_exec(exec); 1901463c08dSmrg 1911463c08dSmrg return ctx->Const.glBeginEndBufferSize > exec->vtx.buffer_used + 1024; 1921463c08dSmrg} 1931463c08dSmrg 19456e89960Smrg 195ac997013Sriastradh/** 196ac997013Sriastradh * Map the vertex buffer to begin storing glVertex, glColor, etc data. 197ac997013Sriastradh */ 19856e89960Smrgvoid 1997e995a2eSmrgvbo_exec_vtx_map(struct vbo_exec_context *exec) 20056e89960Smrg{ 2011463c08dSmrg struct gl_context *ctx = gl_context_from_vbo_exec(exec); 20256e89960Smrg const GLenum usage = GL_STREAM_DRAW_ARB; 2031463c08dSmrg GLenum accessRange = GL_MAP_WRITE_BIT | /* for MapBufferRange */ 2041463c08dSmrg GL_MAP_UNSYNCHRONIZED_BIT; 2051463c08dSmrg 2061463c08dSmrg if (ctx->Extensions.ARB_buffer_storage) { 2071463c08dSmrg /* We sometimes read from the buffer, so map it for read too. 2081463c08dSmrg * Only the persistent mapping can do that, because the non-persistent 2091463c08dSmrg * mapping uses flags that are incompatible with GL_MAP_READ_BIT. 2101463c08dSmrg */ 2111463c08dSmrg accessRange |= GL_MAP_PERSISTENT_BIT | 2121463c08dSmrg GL_MAP_COHERENT_BIT | 2131463c08dSmrg GL_MAP_READ_BIT; 2141463c08dSmrg } else { 2151463c08dSmrg accessRange |= GL_MAP_INVALIDATE_RANGE_BIT | 2161463c08dSmrg GL_MAP_FLUSH_EXPLICIT_BIT | 2171463c08dSmrg MESA_MAP_NOWAIT_BIT; 2181463c08dSmrg } 2197e995a2eSmrg 2201463c08dSmrg if (!exec->vtx.bufferobj) 22156e89960Smrg return; 22256e89960Smrg 223ac997013Sriastradh assert(!exec->vtx.buffer_map); 224ac997013Sriastradh assert(!exec->vtx.buffer_ptr); 22556e89960Smrg 2261463c08dSmrg if (vbo_exec_buffer_has_space(exec)) { 227ac997013Sriastradh /* The VBO exists and there's room for more */ 228b167d5e7Smrg if (exec->vtx.bufferobj->Size > 0) { 2297e995a2eSmrg exec->vtx.buffer_map = (fi_type *) 2307e995a2eSmrg ctx->Driver.MapBufferRange(ctx, 2317e995a2eSmrg exec->vtx.buffer_used, 2321463c08dSmrg ctx->Const.glBeginEndBufferSize 2337e995a2eSmrg - exec->vtx.buffer_used, 2347e995a2eSmrg accessRange, 2357e995a2eSmrg exec->vtx.bufferobj, 2367e995a2eSmrg MAP_INTERNAL); 237b167d5e7Smrg exec->vtx.buffer_ptr = exec->vtx.buffer_map; 238b167d5e7Smrg } 239b167d5e7Smrg else { 240b167d5e7Smrg exec->vtx.buffer_ptr = exec->vtx.buffer_map = NULL; 241b167d5e7Smrg } 24256e89960Smrg } 2437e995a2eSmrg 24456e89960Smrg if (!exec->vtx.buffer_map) { 245ac997013Sriastradh /* Need to allocate a new VBO */ 24656e89960Smrg exec->vtx.buffer_used = 0; 24756e89960Smrg 248b167d5e7Smrg if (ctx->Driver.BufferData(ctx, GL_ARRAY_BUFFER_ARB, 2491463c08dSmrg ctx->Const.glBeginEndBufferSize, 250b167d5e7Smrg NULL, usage, 251b167d5e7Smrg GL_MAP_WRITE_BIT | 2521463c08dSmrg (ctx->Extensions.ARB_buffer_storage ? 2531463c08dSmrg GL_MAP_PERSISTENT_BIT | 2541463c08dSmrg GL_MAP_COHERENT_BIT | 2551463c08dSmrg GL_MAP_READ_BIT : 0) | 256b167d5e7Smrg GL_DYNAMIC_STORAGE_BIT | 257b167d5e7Smrg GL_CLIENT_STORAGE_BIT, 258b167d5e7Smrg exec->vtx.bufferobj)) { 259b167d5e7Smrg /* buffer allocation worked, now map the buffer */ 260b167d5e7Smrg exec->vtx.buffer_map = 2617e995a2eSmrg (fi_type *)ctx->Driver.MapBufferRange(ctx, 2621463c08dSmrg 0, ctx->Const.glBeginEndBufferSize, 26356e89960Smrg accessRange, 264b167d5e7Smrg exec->vtx.bufferobj, 265b167d5e7Smrg MAP_INTERNAL); 266b167d5e7Smrg } 267b167d5e7Smrg else { 268b167d5e7Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "VBO allocation"); 269b167d5e7Smrg exec->vtx.buffer_map = NULL; 270b167d5e7Smrg } 271b167d5e7Smrg } 272b167d5e7Smrg 273b167d5e7Smrg exec->vtx.buffer_ptr = exec->vtx.buffer_map; 2741463c08dSmrg exec->vtx.buffer_offset = 0; 275b167d5e7Smrg 276b167d5e7Smrg if (!exec->vtx.buffer_map) { 277b167d5e7Smrg /* out of memory */ 2787e995a2eSmrg _mesa_install_exec_vtxfmt(ctx, &exec->vtxfmt_noop); 279b167d5e7Smrg } 280b167d5e7Smrg else { 281b167d5e7Smrg if (_mesa_using_noop_vtxfmt(ctx->Exec)) { 282b167d5e7Smrg /* The no-op functions are installed so switch back to regular 283b167d5e7Smrg * functions. We do this test just to avoid frequent and needless 284b167d5e7Smrg * calls to _mesa_install_exec_vtxfmt(). 285b167d5e7Smrg */ 286b167d5e7Smrg _mesa_install_exec_vtxfmt(ctx, &exec->vtxfmt); 287b167d5e7Smrg } 28856e89960Smrg } 28956e89960Smrg 29056e89960Smrg if (0) 2911f16d945Smrg printf("map %d..\n", exec->vtx.buffer_used); 29256e89960Smrg} 29356e89960Smrg 29456e89960Smrg 29556e89960Smrg 2967117f1b4Smrg/** 2977117f1b4Smrg * Execute the buffer and save copied verts. 2987117f1b4Smrg */ 29956e89960Smrgvoid 3001463c08dSmrgvbo_exec_vtx_flush(struct vbo_exec_context *exec) 3017117f1b4Smrg{ 3021463c08dSmrg struct gl_context *ctx = gl_context_from_vbo_exec(exec); 3031463c08dSmrg 3041463c08dSmrg /* Only unmap if persistent mappings are unsupported. */ 3051463c08dSmrg bool persistent_mapping = ctx->Extensions.ARB_buffer_storage && 3061463c08dSmrg exec->vtx.bufferobj && 3071463c08dSmrg exec->vtx.buffer_map; 3081463c08dSmrg 3097117f1b4Smrg if (0) 3107e995a2eSmrg vbo_exec_debug_verts(exec); 3117117f1b4Smrg 3127e995a2eSmrg if (exec->vtx.prim_count && 3137117f1b4Smrg exec->vtx.vert_count) { 3147117f1b4Smrg 3151463c08dSmrg exec->vtx.copied.nr = vbo_exec_copy_vertices(exec); 3167117f1b4Smrg 3177117f1b4Smrg if (exec->vtx.copied.nr != exec->vtx.vert_count) { 3181463c08dSmrg /* Prepare and set the exec draws internal VAO for drawing. */ 3197e995a2eSmrg vbo_exec_bind_arrays(ctx); 3207117f1b4Smrg 32156e89960Smrg if (ctx->NewState) 3227e995a2eSmrg _mesa_update_state(ctx); 32356e89960Smrg 3241463c08dSmrg if (!persistent_mapping) 3251463c08dSmrg vbo_exec_vtx_unmap(exec); 3267e995a2eSmrg 3277e995a2eSmrg assert(ctx->NewState == 0); 328c1f859d4Smrg 32956e89960Smrg if (0) 3307e995a2eSmrg printf("%s %d %d\n", __func__, exec->vtx.prim_count, 3317e995a2eSmrg exec->vtx.vert_count); 3327e995a2eSmrg 3331463c08dSmrg ctx->Driver.DrawGalliumMultiMode(ctx, &exec->vtx.info, 3341463c08dSmrg exec->vtx.draw, 3351463c08dSmrg exec->vtx.mode, 3361463c08dSmrg exec->vtx.prim_count); 3377e995a2eSmrg 3387e995a2eSmrg /* Get new storage -- unless asked not to. */ 3391463c08dSmrg if (!persistent_mapping) 3407e995a2eSmrg vbo_exec_vtx_map(exec); 3417117f1b4Smrg } 3427117f1b4Smrg } 3437117f1b4Smrg 3441463c08dSmrg if (persistent_mapping) { 3451463c08dSmrg exec->vtx.buffer_used += (exec->vtx.buffer_ptr - exec->vtx.buffer_map) * 3461463c08dSmrg sizeof(float); 3471463c08dSmrg exec->vtx.buffer_map = exec->vtx.buffer_ptr; 3481463c08dSmrg 3491463c08dSmrg /* Set the buffer offset for the next draw. */ 3501463c08dSmrg exec->vtx.buffer_offset = exec->vtx.buffer_used; 3511463c08dSmrg 3521463c08dSmrg if (!vbo_exec_buffer_has_space(exec)) { 3531463c08dSmrg /* This will allocate a new buffer. */ 3541463c08dSmrg vbo_exec_vtx_unmap(exec); 3551463c08dSmrg vbo_exec_vtx_map(exec); 3561463c08dSmrg } 35756e89960Smrg } 35856e89960Smrg 3591463c08dSmrg if (exec->vtx.vertex_size == 0) 36056e89960Smrg exec->vtx.max_vert = 0; 36156e89960Smrg else 3627e995a2eSmrg exec->vtx.max_vert = vbo_compute_max_verts(exec); 36356e89960Smrg 36456e89960Smrg exec->vtx.buffer_ptr = exec->vtx.buffer_map; 3657117f1b4Smrg exec->vtx.prim_count = 0; 3667117f1b4Smrg exec->vtx.vert_count = 0; 3677117f1b4Smrg} 368