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