1848b8605Smrg/*
2848b8605Smrg * Mesa 3-D graphics library
3848b8605Smrg *
4848b8605Smrg * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5848b8605Smrg *
6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7848b8605Smrg * copy of this software and associated documentation files (the "Software"),
8848b8605Smrg * to deal in the Software without restriction, including without limitation
9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
11848b8605Smrg * Software is furnished to do so, subject to the following conditions:
12848b8605Smrg *
13848b8605Smrg * The above copyright notice and this permission notice shall be included
14848b8605Smrg * in all copies or substantial portions of the Software.
15848b8605Smrg *
16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
23848b8605Smrg */
24848b8605Smrg
25848b8605Smrg/* Author:
26848b8605Smrg *    Keith Whitwell <keithw@vmware.com>
27848b8605Smrg */
28848b8605Smrg
29b8e80941Smrg#include <stdbool.h>
30b8e80941Smrg#include "main/arrayobj.h"
31848b8605Smrg#include "main/glheader.h"
32848b8605Smrg#include "main/bufferobj.h"
33848b8605Smrg#include "main/context.h"
34848b8605Smrg#include "main/imports.h"
35848b8605Smrg#include "main/macros.h"
36848b8605Smrg#include "main/light.h"
37848b8605Smrg#include "main/state.h"
38b8e80941Smrg#include "main/varray.h"
39b8e80941Smrg#include "util/bitscan.h"
40848b8605Smrg
41b8e80941Smrg#include "vbo_private.h"
42848b8605Smrg
43848b8605Smrg
44848b8605Smrgstatic void
45b8e80941Smrgcopy_vao(struct gl_context *ctx, const struct gl_vertex_array_object *vao,
46b8e80941Smrg         GLbitfield mask, GLbitfield state, int shift, fi_type **data)
47848b8605Smrg{
48848b8605Smrg   struct vbo_context *vbo = vbo_context(ctx);
49848b8605Smrg
50b8e80941Smrg   mask &= vao->Enabled;
51b8e80941Smrg   while (mask) {
52b8e80941Smrg      const int i = u_bit_scan(&mask);
53b8e80941Smrg      const struct gl_array_attributes *attrib = &vao->VertexAttrib[i];
54b8e80941Smrg      struct gl_array_attributes *currval = &vbo->current[shift + i];
55b8e80941Smrg      const GLubyte size = attrib->Format.Size;
56b8e80941Smrg      const GLenum16 type = attrib->Format.Type;
57b8e80941Smrg      fi_type tmp[8];
58b8e80941Smrg      int dmul = 1;
59b8e80941Smrg
60b8e80941Smrg      if (type == GL_DOUBLE ||
61b8e80941Smrg          type == GL_UNSIGNED_INT64_ARB)
62b8e80941Smrg         dmul = 2;
63b8e80941Smrg
64b8e80941Smrg      if (dmul == 2)
65b8e80941Smrg         memcpy(tmp, *data, size * dmul * sizeof(GLfloat));
66848b8605Smrg      else
67b8e80941Smrg         COPY_CLEAN_4V_TYPE_AS_UNION(tmp, size, *data, type);
68848b8605Smrg
69b8e80941Smrg      if (type != currval->Format.Type ||
70b8e80941Smrg          memcmp(currval->Ptr, tmp, 4 * sizeof(GLfloat) * dmul) != 0) {
71b8e80941Smrg         memcpy((fi_type*)currval->Ptr, tmp, 4 * sizeof(GLfloat) * dmul);
72848b8605Smrg
73b8e80941Smrg         vbo_set_vertex_format(&currval->Format, size, type);
74848b8605Smrg
75b8e80941Smrg         ctx->NewState |= state;
76848b8605Smrg      }
77b8e80941Smrg
78b8e80941Smrg      *data += size;
79848b8605Smrg   }
80b8e80941Smrg}
81b8e80941Smrg
82b8e80941Smrg/**
83b8e80941Smrg * After playback, copy everything but the position from the
84b8e80941Smrg * last vertex to the saved state
85b8e80941Smrg */
86b8e80941Smrgstatic void
87b8e80941Smrgplayback_copy_to_current(struct gl_context *ctx,
88b8e80941Smrg                         const struct vbo_save_vertex_list *node)
89b8e80941Smrg{
90b8e80941Smrg   if (!node->current_data)
91b8e80941Smrg      return;
92b8e80941Smrg
93b8e80941Smrg   fi_type *data = node->current_data;
94b8e80941Smrg   /* Copy conventional attribs and generics except pos */
95b8e80941Smrg   copy_vao(ctx, node->VAO[VP_MODE_SHADER], ~VERT_BIT_POS & VERT_BIT_ALL,
96b8e80941Smrg            _NEW_CURRENT_ATTRIB, 0, &data);
97b8e80941Smrg   /* Copy materials */
98b8e80941Smrg   copy_vao(ctx, node->VAO[VP_MODE_FF], VERT_BIT_MAT_ALL,
99b8e80941Smrg            _NEW_CURRENT_ATTRIB | _NEW_LIGHT, VBO_MATERIAL_SHIFT, &data);
100848b8605Smrg
101848b8605Smrg   /* Colormaterial -- this kindof sucks.
102848b8605Smrg    */
103848b8605Smrg   if (ctx->Light.ColorMaterialEnabled) {
104848b8605Smrg      _mesa_update_color_material(ctx, ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
105848b8605Smrg   }
106848b8605Smrg
107848b8605Smrg   /* CurrentExecPrimitive
108848b8605Smrg    */
109848b8605Smrg   if (node->prim_count) {
110b8e80941Smrg      const struct _mesa_prim *prim = &node->prims[node->prim_count - 1];
111848b8605Smrg      if (prim->end)
112b8e80941Smrg         ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
113848b8605Smrg      else
114b8e80941Smrg         ctx->Driver.CurrentExecPrimitive = prim->mode;
115848b8605Smrg   }
116848b8605Smrg}
117848b8605Smrg
118848b8605Smrg
119848b8605Smrg
120848b8605Smrg/**
121b8e80941Smrg * Set the appropriate VAO to draw.
122848b8605Smrg */
123b8e80941Smrgstatic void
124b8e80941Smrgbind_vertex_list(struct gl_context *ctx,
125b8e80941Smrg                 const struct vbo_save_vertex_list *node)
126848b8605Smrg{
127b8e80941Smrg   const gl_vertex_processing_mode mode = ctx->VertexProgram._VPMode;
128b8e80941Smrg   _mesa_set_draw_vao(ctx, node->VAO[mode], _vbo_get_vao_filter(mode));
129848b8605Smrg}
130848b8605Smrg
131848b8605Smrg
132848b8605Smrgstatic void
133b8e80941Smrgloopback_vertex_list(struct gl_context *ctx,
134b8e80941Smrg                     const struct vbo_save_vertex_list *list)
135848b8605Smrg{
136b8e80941Smrg   struct gl_buffer_object *bo = list->VAO[0]->BufferBinding[0].BufferObj;
137b8e80941Smrg   ctx->Driver.MapBufferRange(ctx, 0, bo->Size, GL_MAP_READ_BIT, /* ? */
138b8e80941Smrg                              bo, MAP_INTERNAL);
139b8e80941Smrg
140b8e80941Smrg   /* Note that the range of referenced vertices must be mapped already */
141b8e80941Smrg   _vbo_loopback_vertex_list(ctx, list);
142b8e80941Smrg
143b8e80941Smrg   ctx->Driver.UnmapBuffer(ctx, bo, MAP_INTERNAL);
144848b8605Smrg}
145848b8605Smrg
146848b8605Smrg
147848b8605Smrg/**
148848b8605Smrg * Execute the buffer and save copied verts.
149848b8605Smrg * This is called from the display list code when executing
150848b8605Smrg * a drawing command.
151848b8605Smrg */
152848b8605Smrgvoid
153848b8605Smrgvbo_save_playback_vertex_list(struct gl_context *ctx, void *data)
154848b8605Smrg{
155848b8605Smrg   const struct vbo_save_vertex_list *node =
156848b8605Smrg      (const struct vbo_save_vertex_list *) data;
157b8e80941Smrg   struct vbo_context *vbo = vbo_context(ctx);
158b8e80941Smrg   struct vbo_save_context *save = &vbo->save;
159848b8605Smrg   GLboolean remap_vertex_store = GL_FALSE;
160848b8605Smrg
161b8e80941Smrg   if (save->vertex_store && save->vertex_store->buffer_map) {
162848b8605Smrg      /* The vertex store is currently mapped but we're about to replay
163848b8605Smrg       * a display list.  This can happen when a nested display list is
164848b8605Smrg       * being build with GL_COMPILE_AND_EXECUTE.
165848b8605Smrg       * We never want to have mapped vertex buffers when we're drawing.
166848b8605Smrg       * Unmap the vertex store, execute the list, then remap the vertex
167848b8605Smrg       * store.
168848b8605Smrg       */
169848b8605Smrg      vbo_save_unmap_vertex_store(ctx, save->vertex_store);
170848b8605Smrg      remap_vertex_store = GL_TRUE;
171848b8605Smrg   }
172848b8605Smrg
173b8e80941Smrg   FLUSH_FOR_DRAW(ctx);
174848b8605Smrg
175848b8605Smrg   if (node->prim_count > 0) {
176848b8605Smrg
177b8e80941Smrg      if (_mesa_inside_begin_end(ctx) && node->prims[0].begin) {
178848b8605Smrg         /* Error: we're about to begin a new primitive but we're already
179848b8605Smrg          * inside a glBegin/End pair.
180848b8605Smrg          */
181848b8605Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
182848b8605Smrg                     "draw operation inside glBegin/End");
183848b8605Smrg         goto end;
184848b8605Smrg      }
185848b8605Smrg      else if (save->replay_flags) {
186b8e80941Smrg         /* Various degenerate cases: translate into immediate mode
187b8e80941Smrg          * calls rather than trying to execute in place.
188b8e80941Smrg          */
189b8e80941Smrg         loopback_vertex_list(ctx, node);
190848b8605Smrg
191848b8605Smrg         goto end;
192848b8605Smrg      }
193b8e80941Smrg
194b8e80941Smrg      bind_vertex_list(ctx, node);
195b8e80941Smrg
196b8e80941Smrg      /* Need that at least one time. */
197848b8605Smrg      if (ctx->NewState)
198b8e80941Smrg         _mesa_update_state(ctx);
199848b8605Smrg
200848b8605Smrg      /* XXX also need to check if shader enabled, but invalid */
201b8e80941Smrg      if ((ctx->VertexProgram.Enabled &&
202b8e80941Smrg           !_mesa_arb_vertex_program_enabled(ctx)) ||
203b8e80941Smrg          (ctx->FragmentProgram.Enabled &&
204b8e80941Smrg           !_mesa_arb_fragment_program_enabled(ctx))) {
205848b8605Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
206848b8605Smrg                     "glBegin (invalid vertex/fragment program)");
207848b8605Smrg         return;
208848b8605Smrg      }
209848b8605Smrg
210b8e80941Smrg      assert(ctx->NewState == 0);
211848b8605Smrg
212b8e80941Smrg      if (node->vertex_count > 0) {
213b8e80941Smrg         GLuint min_index = _vbo_save_get_min_index(node);
214b8e80941Smrg         GLuint max_index = _vbo_save_get_max_index(node);
215b8e80941Smrg         ctx->Driver.Draw(ctx, node->prims, node->prim_count, NULL, GL_TRUE,
216b8e80941Smrg                          min_index, max_index, NULL, 0, NULL);
217848b8605Smrg      }
218848b8605Smrg   }
219848b8605Smrg
220848b8605Smrg   /* Copy to current?
221848b8605Smrg    */
222b8e80941Smrg   playback_copy_to_current(ctx, node);
223848b8605Smrg
224848b8605Smrgend:
225848b8605Smrg   if (remap_vertex_store) {
226848b8605Smrg      save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
227848b8605Smrg   }
228848b8605Smrg}
229