[QMGRPRXY]
[reactos.git] / reactos / dll / opengl / mesa / vbo / vbo_exec_draw.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.2
4 *
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Keith Whitwell <keith@tungstengraphics.com>
26 */
27
28 #include <precomp.h>
29
30 #if FEATURE_beginend
31
32
33 static void
34 vbo_exec_debug_verts( struct vbo_exec_context *exec )
35 {
36 GLuint count = exec->vtx.vert_count;
37 GLuint i;
38
39 printf("%s: %u vertices %d primitives, %d vertsize\n",
40 __FUNCTION__,
41 count,
42 exec->vtx.prim_count,
43 exec->vtx.vertex_size);
44
45 for (i = 0 ; i < exec->vtx.prim_count ; i++) {
46 struct _mesa_prim *prim = &exec->vtx.prim[i];
47 printf(" prim %d: %s%s %d..%d %s %s\n",
48 i,
49 _mesa_lookup_prim_by_nr(prim->mode),
50 prim->weak ? " (weak)" : "",
51 prim->start,
52 prim->start + prim->count,
53 prim->begin ? "BEGIN" : "(wrap)",
54 prim->end ? "END" : "(wrap)");
55 }
56 }
57
58
59 /*
60 * NOTE: Need to have calculated primitives by this point -- do it on the fly.
61 * NOTE: Old 'parity' issue is gone.
62 */
63 static GLuint
64 vbo_copy_vertices( struct vbo_exec_context *exec )
65 {
66 GLuint nr = exec->vtx.prim[exec->vtx.prim_count-1].count;
67 GLuint ovf, i;
68 GLuint sz = exec->vtx.vertex_size;
69 GLfloat *dst = exec->vtx.copied.buffer;
70 const GLfloat *src = (exec->vtx.buffer_map +
71 exec->vtx.prim[exec->vtx.prim_count-1].start *
72 exec->vtx.vertex_size);
73
74
75 switch (exec->ctx->Driver.CurrentExecPrimitive) {
76 case GL_POINTS:
77 return 0;
78 case GL_LINES:
79 ovf = nr&1;
80 for (i = 0 ; i < ovf ; i++)
81 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
82 return i;
83 case GL_TRIANGLES:
84 ovf = nr%3;
85 for (i = 0 ; i < ovf ; i++)
86 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
87 return i;
88 case GL_QUADS:
89 ovf = nr&3;
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_LINE_STRIP:
94 if (nr == 0) {
95 return 0;
96 }
97 else {
98 memcpy( dst, src+(nr-1)*sz, sz * sizeof(GLfloat) );
99 return 1;
100 }
101 case GL_LINE_LOOP:
102 case GL_TRIANGLE_FAN:
103 case GL_POLYGON:
104 if (nr == 0) {
105 return 0;
106 }
107 else if (nr == 1) {
108 memcpy( dst, src+0, sz * sizeof(GLfloat) );
109 return 1;
110 }
111 else {
112 memcpy( dst, src+0, sz * sizeof(GLfloat) );
113 memcpy( dst+sz, src+(nr-1)*sz, sz * sizeof(GLfloat) );
114 return 2;
115 }
116 case GL_TRIANGLE_STRIP:
117 /* no parity issue, but need to make sure the tri is not drawn twice */
118 if (nr & 1) {
119 exec->vtx.prim[exec->vtx.prim_count-1].count--;
120 }
121 /* fallthrough */
122 case GL_QUAD_STRIP:
123 switch (nr) {
124 case 0:
125 ovf = 0;
126 break;
127 case 1:
128 ovf = 1;
129 break;
130 default:
131 ovf = 2 + (nr & 1);
132 break;
133 }
134 for (i = 0 ; i < ovf ; i++)
135 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
136 return i;
137 case PRIM_OUTSIDE_BEGIN_END:
138 return 0;
139 default:
140 assert(0);
141 return 0;
142 }
143 }
144
145
146
147 /* TODO: populate these as the vertex is defined:
148 */
149 static void
150 vbo_exec_bind_arrays( struct gl_context *ctx )
151 {
152 struct vbo_context *vbo = vbo_context(ctx);
153 struct vbo_exec_context *exec = &vbo->exec;
154 struct gl_client_array *arrays = exec->vtx.arrays;
155 const GLuint count = exec->vtx.vert_count;
156 GLuint attr;
157 GLbitfield64 varying_inputs = 0x0;
158
159 /* Install the default (ie Current) attributes first, then overlay
160 * all active ones.
161 */
162 for (attr = 0; attr < VBO_ATTRIB_MAX; attr++) {
163 exec->vtx.inputs[attr] = &vbo->legacy_currval[attr];
164 }
165
166 /* Make all active attributes (including edgeflag) available as
167 * arrays of floats.
168 */
169 for (attr = 0; attr < VBO_ATTRIB_MAX ; attr++) {
170
171 if (exec->vtx.attrsz[attr]) {
172 GLsizeiptr offset = (GLbyte *)exec->vtx.attrptr[attr] -
173 (GLbyte *)exec->vtx.vertex;
174
175 /* override the default array set above */
176 ASSERT(attr < Elements(exec->vtx.inputs));
177 ASSERT(attr < Elements(exec->vtx.arrays)); /* arrays[] */
178 exec->vtx.inputs[attr] = &arrays[attr];
179
180 if (_mesa_is_bufferobj(exec->vtx.bufferobj)) {
181 /* a real buffer obj: Ptr is an offset, not a pointer*/
182 assert(exec->vtx.bufferobj->Pointer); /* buf should be mapped */
183 assert(offset >= 0);
184 arrays[attr].Ptr = (GLubyte *)exec->vtx.bufferobj->Offset + offset;
185 }
186 else {
187 /* Ptr into ordinary app memory */
188 arrays[attr].Ptr = (GLubyte *)exec->vtx.buffer_map + offset;
189 }
190 arrays[attr].Size = exec->vtx.attrsz[attr];
191 arrays[attr].StrideB = exec->vtx.vertex_size * sizeof(GLfloat);
192 arrays[attr].Stride = exec->vtx.vertex_size * sizeof(GLfloat);
193 arrays[attr].Type = GL_FLOAT;
194 arrays[attr].Enabled = 1;
195 arrays[attr]._ElementSize = arrays[attr].Size * sizeof(GLfloat);
196 _mesa_reference_buffer_object(ctx,
197 &arrays[attr].BufferObj,
198 exec->vtx.bufferobj);
199 arrays[attr]._MaxElement = count; /* ??? */
200
201 varying_inputs |= VERT_BIT(attr);
202 ctx->NewState |= _NEW_ARRAY;
203 }
204 }
205 }
206
207
208 /**
209 * Unmap the VBO. This is called before drawing.
210 */
211 static void
212 vbo_exec_vtx_unmap( struct vbo_exec_context *exec )
213 {
214 if (_mesa_is_bufferobj(exec->vtx.bufferobj)) {
215 struct gl_context *ctx = exec->ctx;
216
217 if (ctx->Driver.FlushMappedBufferRange) {
218 GLintptr offset = exec->vtx.buffer_used - exec->vtx.bufferobj->Offset;
219 GLsizeiptr length = (exec->vtx.buffer_ptr - exec->vtx.buffer_map) * sizeof(float);
220
221 if (length)
222 ctx->Driver.FlushMappedBufferRange(ctx, offset, length,
223 exec->vtx.bufferobj);
224 }
225
226 exec->vtx.buffer_used += (exec->vtx.buffer_ptr -
227 exec->vtx.buffer_map) * sizeof(float);
228
229 assert(exec->vtx.buffer_used <= VBO_VERT_BUFFER_SIZE);
230 assert(exec->vtx.buffer_ptr != NULL);
231
232 ctx->Driver.UnmapBuffer(ctx, exec->vtx.bufferobj);
233 exec->vtx.buffer_map = NULL;
234 exec->vtx.buffer_ptr = NULL;
235 exec->vtx.max_vert = 0;
236 }
237 }
238
239
240 /**
241 * Map the vertex buffer to begin storing glVertex, glColor, etc data.
242 */
243 void
244 vbo_exec_vtx_map( struct vbo_exec_context *exec )
245 {
246 struct gl_context *ctx = exec->ctx;
247 const GLenum accessRange = GL_MAP_WRITE_BIT | /* for MapBufferRange */
248 GL_MAP_INVALIDATE_RANGE_BIT |
249 GL_MAP_UNSYNCHRONIZED_BIT |
250 GL_MAP_FLUSH_EXPLICIT_BIT |
251 MESA_MAP_NOWAIT_BIT;
252 const GLenum usage = GL_STREAM_DRAW_ARB;
253
254 if (!_mesa_is_bufferobj(exec->vtx.bufferobj))
255 return;
256
257 assert(!exec->vtx.buffer_map);
258 assert(!exec->vtx.buffer_ptr);
259
260 if (VBO_VERT_BUFFER_SIZE > exec->vtx.buffer_used + 1024) {
261 /* The VBO exists and there's room for more */
262 if (exec->vtx.bufferobj->Size > 0) {
263 exec->vtx.buffer_map =
264 (GLfloat *)ctx->Driver.MapBufferRange(ctx,
265 exec->vtx.buffer_used,
266 (VBO_VERT_BUFFER_SIZE -
267 exec->vtx.buffer_used),
268 accessRange,
269 exec->vtx.bufferobj);
270 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
271 }
272 else {
273 exec->vtx.buffer_ptr = exec->vtx.buffer_map = NULL;
274 }
275 }
276
277 if (!exec->vtx.buffer_map) {
278 /* Need to allocate a new VBO */
279 exec->vtx.buffer_used = 0;
280
281 if (ctx->Driver.BufferData(ctx, GL_ARRAY_BUFFER_ARB,
282 VBO_VERT_BUFFER_SIZE,
283 NULL, usage, exec->vtx.bufferobj)) {
284 /* buffer allocation worked, now map the buffer */
285 exec->vtx.buffer_map =
286 (GLfloat *)ctx->Driver.MapBufferRange(ctx,
287 0, VBO_VERT_BUFFER_SIZE,
288 accessRange,
289 exec->vtx.bufferobj);
290 }
291 else {
292 _mesa_error(ctx, GL_OUT_OF_MEMORY, "VBO allocation");
293 exec->vtx.buffer_map = NULL;
294 }
295 }
296
297 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
298
299 if (!exec->vtx.buffer_map) {
300 /* out of memory */
301 _mesa_install_exec_vtxfmt( ctx, &exec->vtxfmt_noop );
302 }
303 else {
304 if (_mesa_using_noop_vtxfmt(ctx->Exec)) {
305 /* The no-op functions are installed so switch back to regular
306 * functions. We do this test just to avoid frequent and needless
307 * calls to _mesa_install_exec_vtxfmt().
308 */
309 _mesa_install_exec_vtxfmt(ctx, &exec->vtxfmt);
310 }
311 }
312
313 if (0)
314 printf("map %d..\n", exec->vtx.buffer_used);
315 }
316
317
318
319 /**
320 * Execute the buffer and save copied verts.
321 * \param keep_unmapped if true, leave the VBO unmapped when we're done.
322 */
323 void
324 vbo_exec_vtx_flush(struct vbo_exec_context *exec, GLboolean keepUnmapped)
325 {
326 if (0)
327 vbo_exec_debug_verts( exec );
328
329 if (exec->vtx.prim_count &&
330 exec->vtx.vert_count) {
331
332 exec->vtx.copied.nr = vbo_copy_vertices( exec );
333
334 if (exec->vtx.copied.nr != exec->vtx.vert_count) {
335 struct gl_context *ctx = exec->ctx;
336
337 vbo_exec_bind_arrays( ctx );
338
339 if (ctx->NewState)
340 _mesa_update_state( ctx );
341
342 if (_mesa_is_bufferobj(exec->vtx.bufferobj)) {
343 vbo_exec_vtx_unmap( exec );
344 }
345
346 if (0)
347 printf("%s %d %d\n", __FUNCTION__, exec->vtx.prim_count,
348 exec->vtx.vert_count);
349
350 vbo_context(ctx)->draw_prims( ctx,
351 exec->vtx.inputs,
352 exec->vtx.prim,
353 exec->vtx.prim_count,
354 NULL,
355 GL_TRUE,
356 0,
357 exec->vtx.vert_count - 1);
358
359 /* If using a real VBO, get new storage -- unless asked not to.
360 */
361 if (_mesa_is_bufferobj(exec->vtx.bufferobj) && !keepUnmapped) {
362 vbo_exec_vtx_map( exec );
363 }
364 }
365 }
366
367 /* May have to unmap explicitly if we didn't draw:
368 */
369 if (keepUnmapped &&
370 _mesa_is_bufferobj(exec->vtx.bufferobj) &&
371 exec->vtx.buffer_map) {
372 vbo_exec_vtx_unmap( exec );
373 }
374
375 if (keepUnmapped || exec->vtx.vertex_size == 0)
376 exec->vtx.max_vert = 0;
377 else
378 exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) /
379 (exec->vtx.vertex_size * sizeof(GLfloat)));
380
381 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
382 exec->vtx.prim_count = 0;
383 exec->vtx.vert_count = 0;
384 }
385
386
387 #endif /* FEATURE_beginend */