096e43c8169a3b15256a2c616e57c7dfc66ff733
[mesa.git] / src / mesa / vbo / vbo_save_draw.c
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
25 /* Author:
26 * Keith Whitwell <keithw@vmware.com>
27 */
28
29 #include <stdbool.h>
30 #include "main/arrayobj.h"
31 #include "main/glheader.h"
32 #include "main/bufferobj.h"
33 #include "main/context.h"
34 #include "main/imports.h"
35 #include "main/mtypes.h"
36 #include "main/macros.h"
37 #include "main/light.h"
38 #include "main/state.h"
39 #include "main/varray.h"
40 #include "util/bitscan.h"
41
42 #include "vbo_private.h"
43
44
45 static void
46 copy_vao(struct gl_context *ctx, const struct gl_vertex_array_object *vao,
47 GLbitfield mask, GLbitfield state, int shift, fi_type **data)
48 {
49 struct vbo_context *vbo = vbo_context(ctx);
50
51 mask &= vao->_Enabled;
52 while (mask) {
53 const int i = u_bit_scan(&mask);
54 const struct gl_array_attributes *attrib = &vao->VertexAttrib[i];
55 struct gl_array_attributes *currval = &vbo->current[shift + i];
56 const GLubyte size = attrib->Size;
57 const GLenum16 type = attrib->Type;
58 fi_type tmp[4];
59
60 COPY_CLEAN_4V_TYPE_AS_UNION(tmp, size, *data, type);
61
62 if (type != currval->Type ||
63 memcmp(currval->Ptr, tmp, 4 * sizeof(GLfloat)) != 0) {
64 memcpy((fi_type*)currval->Ptr, tmp, 4 * sizeof(GLfloat));
65
66 currval->Size = size;
67 currval->_ElementSize = size * sizeof(GLfloat);
68 currval->Type = type;
69 currval->Integer = vbo_attrtype_to_integer_flag(type);
70 currval->Doubles = vbo_attrtype_to_double_flag(type);
71 currval->Normalized = GL_FALSE;
72 currval->Format = GL_RGBA;
73
74 ctx->NewState |= state;
75 }
76
77 *data += size;
78 }
79 }
80
81 /**
82 * After playback, copy everything but the position from the
83 * last vertex to the saved state
84 */
85 static void
86 playback_copy_to_current(struct gl_context *ctx,
87 const struct vbo_save_vertex_list *node)
88 {
89 if (!node->current_data)
90 return;
91
92 fi_type *data = node->current_data;
93 /* Copy conventional attribs and generics except pos */
94 copy_vao(ctx, node->VAO[VP_MODE_SHADER], ~VERT_BIT_POS & VERT_BIT_ALL,
95 _NEW_CURRENT_ATTRIB, 0, &data);
96 /* Copy materials */
97 copy_vao(ctx, node->VAO[VP_MODE_FF], VERT_BIT_MAT_ALL,
98 _NEW_CURRENT_ATTRIB | _NEW_LIGHT, VBO_MATERIAL_SHIFT, &data);
99
100 /* Colormaterial -- this kindof sucks.
101 */
102 if (ctx->Light.ColorMaterialEnabled) {
103 _mesa_update_color_material(ctx, ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
104 }
105
106 /* CurrentExecPrimitive
107 */
108 if (node->prim_count) {
109 const struct _mesa_prim *prim = &node->prims[node->prim_count - 1];
110 if (prim->end)
111 ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
112 else
113 ctx->Driver.CurrentExecPrimitive = prim->mode;
114 }
115 }
116
117
118
119 /**
120 * Set the appropriate VAO to draw.
121 */
122 static void
123 bind_vertex_list(struct gl_context *ctx,
124 const struct vbo_save_vertex_list *node)
125 {
126 const gl_vertex_processing_mode mode = ctx->VertexProgram._VPMode;
127 _mesa_set_draw_vao(ctx, node->VAO[mode], _vbo_get_vao_filter(mode));
128 }
129
130
131 static void
132 loopback_vertex_list(struct gl_context *ctx,
133 const struct vbo_save_vertex_list *list)
134 {
135 struct gl_buffer_object *bo = list->VAO[0]->BufferBinding[0].BufferObj;
136 ctx->Driver.MapBufferRange(ctx, 0, bo->Size, GL_MAP_READ_BIT, /* ? */
137 bo, MAP_INTERNAL);
138
139 /* Note that the range of referenced vertices must be mapped already */
140 _vbo_loopback_vertex_list(ctx, list);
141
142 ctx->Driver.UnmapBuffer(ctx, bo, MAP_INTERNAL);
143 }
144
145
146 /**
147 * Execute the buffer and save copied verts.
148 * This is called from the display list code when executing
149 * a drawing command.
150 */
151 void
152 vbo_save_playback_vertex_list(struct gl_context *ctx, void *data)
153 {
154 const struct vbo_save_vertex_list *node =
155 (const struct vbo_save_vertex_list *) data;
156 struct vbo_context *vbo = vbo_context(ctx);
157 struct vbo_save_context *save = &vbo->save;
158 GLboolean remap_vertex_store = GL_FALSE;
159
160 if (save->vertex_store && save->vertex_store->buffer_map) {
161 /* The vertex store is currently mapped but we're about to replay
162 * a display list. This can happen when a nested display list is
163 * being build with GL_COMPILE_AND_EXECUTE.
164 * We never want to have mapped vertex buffers when we're drawing.
165 * Unmap the vertex store, execute the list, then remap the vertex
166 * store.
167 */
168 vbo_save_unmap_vertex_store(ctx, save->vertex_store);
169 remap_vertex_store = GL_TRUE;
170 }
171
172 FLUSH_CURRENT(ctx, 0);
173
174 if (node->prim_count > 0) {
175
176 if (_mesa_inside_begin_end(ctx) && node->prims[0].begin) {
177 /* Error: we're about to begin a new primitive but we're already
178 * inside a glBegin/End pair.
179 */
180 _mesa_error(ctx, GL_INVALID_OPERATION,
181 "draw operation inside glBegin/End");
182 goto end;
183 }
184 else if (save->replay_flags) {
185 /* Various degenerate cases: translate into immediate mode
186 * calls rather than trying to execute in place.
187 */
188 loopback_vertex_list(ctx, node);
189
190 goto end;
191 }
192
193 bind_vertex_list(ctx, node);
194
195 /* Need that at least one time. */
196 if (ctx->NewState)
197 _mesa_update_state(ctx);
198
199 /* XXX also need to check if shader enabled, but invalid */
200 if ((ctx->VertexProgram.Enabled &&
201 !_mesa_arb_vertex_program_enabled(ctx)) ||
202 (ctx->FragmentProgram.Enabled &&
203 !_mesa_arb_fragment_program_enabled(ctx))) {
204 _mesa_error(ctx, GL_INVALID_OPERATION,
205 "glBegin (invalid vertex/fragment program)");
206 return;
207 }
208
209 assert(ctx->NewState == 0);
210
211 if (node->vertex_count > 0) {
212 GLuint min_index = _vbo_save_get_min_index(node);
213 GLuint max_index = _vbo_save_get_max_index(node);
214 ctx->Driver.Draw(ctx, node->prims, node->prim_count, NULL, GL_TRUE,
215 min_index, max_index, NULL, 0, NULL);
216 }
217 }
218
219 /* Copy to current?
220 */
221 playback_copy_to_current(ctx, node);
222
223 end:
224 if (remap_vertex_store) {
225 save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
226 }
227 }