Sync with trunk r63637.
[reactos.git] / dll / opengl / mesa / vbo / vbo_exec_array.c
1 /**************************************************************************
2 *
3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * Copyright 2009 VMware, Inc.
5 * 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
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 **************************************************************************/
28
29 #include <precomp.h>
30
31 /**
32 * All vertex buffers should be in an unmapped state when we're about
33 * to draw. This debug function checks that.
34 */
35 static void
36 check_buffers_are_unmapped(const struct gl_client_array **inputs)
37 {
38 #ifdef DEBUG
39 GLuint i;
40
41 for (i = 0; i < VBO_ATTRIB_MAX; i++) {
42 if (inputs[i]) {
43 struct gl_buffer_object *obj = inputs[i]->BufferObj;
44 assert(!_mesa_bufferobj_mapped(obj));
45 (void) obj;
46 }
47 }
48 #endif
49 }
50
51
52 /**
53 * A debug function that may be called from other parts of Mesa as
54 * needed during debugging.
55 */
56 void
57 vbo_check_buffers_are_unmapped(struct gl_context *ctx)
58 {
59 struct vbo_context *vbo = vbo_context(ctx);
60 struct vbo_exec_context *exec = &vbo->exec;
61 /* check the current vertex arrays */
62 check_buffers_are_unmapped(exec->array.inputs);
63 /* check the current glBegin/glVertex/glEnd-style VBO */
64 assert(!_mesa_bufferobj_mapped(exec->vtx.bufferobj));
65 }
66
67 int
68 vbo_sizeof_ib_type(GLenum type)
69 {
70 switch (type) {
71 case GL_UNSIGNED_INT:
72 return sizeof(GLuint);
73 case GL_UNSIGNED_SHORT:
74 return sizeof(GLushort);
75 case GL_UNSIGNED_BYTE:
76 return sizeof(GLubyte);
77 default:
78 assert(!"unsupported index data type");
79 /* In case assert is turned off */
80 return 0;
81 }
82 }
83
84
85 /**
86 * Compute min and max elements by scanning the index buffer for
87 * glDraw[Range]Elements() calls.
88 * If primitive restart is enabled, we need to ignore restart
89 * indexes when computing min/max.
90 */
91 void
92 vbo_get_minmax_index(struct gl_context *ctx,
93 const struct _mesa_prim *prim,
94 const struct _mesa_index_buffer *ib,
95 GLuint *min_index, GLuint *max_index)
96 {
97 const GLuint count = prim->count;
98 const void *indices;
99 GLuint i;
100
101 if (_mesa_is_bufferobj(ib->obj)) {
102 indices = ctx->Driver.MapBufferRange(ctx, (GLsizeiptr) ib->ptr,
103 count * vbo_sizeof_ib_type(ib->type),
104 GL_MAP_READ_BIT, ib->obj);
105 } else {
106 indices = ib->ptr;
107 }
108
109 switch (ib->type) {
110 case GL_UNSIGNED_INT: {
111 const GLuint *ui_indices = (const GLuint *)indices;
112 GLuint max_ui = 0;
113 GLuint min_ui = ~0U;
114 for (i = 0; i < count; i++) {
115 if (ui_indices[i] > max_ui) max_ui = ui_indices[i];
116 if (ui_indices[i] < min_ui) min_ui = ui_indices[i];
117 }
118 *min_index = min_ui;
119 *max_index = max_ui;
120 break;
121 }
122 case GL_UNSIGNED_SHORT: {
123 const GLushort *us_indices = (const GLushort *)indices;
124 GLuint max_us = 0;
125 GLuint min_us = ~0U;
126 for (i = 0; i < count; i++) {
127 if (us_indices[i] > max_us) max_us = us_indices[i];
128 if (us_indices[i] < min_us) min_us = us_indices[i];
129 }
130 *min_index = min_us;
131 *max_index = max_us;
132 break;
133 }
134 case GL_UNSIGNED_BYTE: {
135 const GLubyte *ub_indices = (const GLubyte *)indices;
136 GLuint max_ub = 0;
137 GLuint min_ub = ~0U;
138 for (i = 0; i < count; i++) {
139 if (ub_indices[i] > max_ub) max_ub = ub_indices[i];
140 if (ub_indices[i] < min_ub) min_ub = ub_indices[i];
141 }
142 *min_index = min_ub;
143 *max_index = max_ub;
144 break;
145 }
146 default:
147 assert(0);
148 break;
149 }
150
151 if (_mesa_is_bufferobj(ib->obj)) {
152 ctx->Driver.UnmapBuffer(ctx, ib->obj);
153 }
154 }
155
156
157 /**
158 * Check array data, looking for NaNs, etc.
159 */
160 static void
161 check_draw_arrays_data(struct gl_context *ctx, GLint start, GLsizei count)
162 {
163 /* TO DO */
164 }
165
166
167 /**
168 * Print info/data for glDrawArrays(), for debugging.
169 */
170 static void
171 print_draw_arrays(struct gl_context *ctx,
172 GLenum mode, GLint start, GLsizei count)
173 {
174 struct vbo_context *vbo = vbo_context(ctx);
175 struct vbo_exec_context *exec = &vbo->exec;
176 int i;
177
178 printf("vbo_exec_DrawArrays(mode 0x%x, start %d, count %d):\n",
179 mode, start, count);
180
181 for (i = 0; i < 32; i++) {
182 struct gl_buffer_object *bufObj = exec->array.inputs[i]->BufferObj;
183 GLuint bufName = bufObj->Name;
184 GLint stride = exec->array.inputs[i]->Stride;
185 printf("attr %2d: size %d stride %d enabled %d "
186 "ptr %p Bufobj %u\n",
187 i,
188 exec->array.inputs[i]->Size,
189 stride,
190 /*exec->array.inputs[i]->Enabled,*/
191 ctx->Array.VertexAttrib[VERT_ATTRIB(i)].Enabled,
192 exec->array.inputs[i]->Ptr,
193 bufName);
194
195 if (bufName) {
196 GLubyte *p = ctx->Driver.MapBufferRange(ctx, 0, bufObj->Size,
197 GL_MAP_READ_BIT, bufObj);
198 int offset = (int) (GLintptr) exec->array.inputs[i]->Ptr;
199 float *f = (float *) (p + offset);
200 int *k = (int *) f;
201 int i;
202 int n = (count * stride) / 4;
203 if (n > 32)
204 n = 32;
205 printf(" Data at offset %d:\n", offset);
206 for (i = 0; i < n; i++) {
207 printf(" float[%d] = 0x%08x %f\n", i, k[i], f[i]);
208 }
209 ctx->Driver.UnmapBuffer(ctx, bufObj);
210 }
211 }
212 }
213
214
215 /**
216 * Set the vbo->exec->inputs[] pointers to point to the enabled
217 * vertex arrays. This depends on the current vertex program/shader
218 * being executed because of whether or not generic vertex arrays
219 * alias the conventional vertex arrays.
220 * For arrays that aren't enabled, we set the input[attrib] pointer
221 * to point at a zero-stride current value "array".
222 */
223 static void
224 recalculate_input_bindings(struct gl_context *ctx)
225 {
226 struct vbo_context *vbo = vbo_context(ctx);
227 struct vbo_exec_context *exec = &vbo->exec;
228 struct gl_client_array *vertexAttrib = ctx->Array.VertexAttrib;
229 const struct gl_client_array **inputs = &exec->array.inputs[0];
230 GLbitfield64 const_inputs = 0x0;
231 GLuint i;
232
233 for (i = 0; i < VBO_ATTRIB_MAX; i++) {
234 if ((i < VERT_ATTRIB_MAX) && (vertexAttrib[VERT_ATTRIB(i)].Enabled))
235 inputs[i] = &vertexAttrib[VERT_ATTRIB(i)];
236 else {
237 inputs[i] = &vbo->currval[i];
238 const_inputs |= VERT_BIT(i);
239 }
240 }
241
242 ctx->NewState |= _NEW_ARRAY;
243 }
244
245
246 /**
247 * Examine the enabled vertex arrays to set the exec->array.inputs[] values.
248 * These will point to the arrays to actually use for drawing. Some will
249 * be user-provided arrays, other will be zero-stride const-valued arrays.
250 * Note that this might set the _NEW_ARRAY dirty flag so state validation
251 * must be done after this call.
252 */
253 void
254 vbo_bind_arrays(struct gl_context *ctx)
255 {
256 if (!ctx->Array.RebindArrays) {
257 return;
258 }
259
260 recalculate_input_bindings(ctx);
261 ctx->Array.RebindArrays = GL_FALSE;
262 }
263
264
265 /**
266 * Helper function called by the other DrawArrays() functions below.
267 * This is where we handle primitive restart for drawing non-indexed
268 * arrays. If primitive restart is enabled, it typically means
269 * splitting one DrawArrays() into two.
270 */
271 static void
272 vbo_draw_arrays(struct gl_context *ctx, GLenum mode, GLint start,
273 GLsizei count, GLuint numInstances)
274 {
275 struct vbo_context *vbo = vbo_context(ctx);
276 struct vbo_exec_context *exec = &vbo->exec;
277 struct _mesa_prim prim[2];
278
279 vbo_bind_arrays(ctx);
280
281 vbo_draw_method(exec, DRAW_ARRAYS);
282
283 /* Again... because we may have changed the bitmask of per-vertex varying
284 * attributes. If we regenerate the fixed-function vertex program now
285 * we may be able to prune down the number of vertex attributes which we
286 * need in the shader.
287 */
288 if (ctx->NewState)
289 _mesa_update_state(ctx);
290
291 /* init most fields to zero */
292 memset(prim, 0, sizeof(prim));
293 prim[0].begin = 1;
294 prim[0].end = 1;
295 prim[0].mode = mode;
296 prim[0].num_instances = numInstances;
297
298 /* no prim restart */
299 prim[0].start = start;
300 prim[0].count = count;
301
302 check_buffers_are_unmapped(exec->array.inputs);
303 vbo->draw_prims(ctx, exec->array.inputs, prim, 1, NULL,
304 GL_TRUE, start, start + count - 1);
305 }
306
307
308
309 /**
310 * Called from glDrawArrays when in immediate mode (not display list mode).
311 */
312 static void GLAPIENTRY
313 vbo_exec_DrawArrays(GLenum mode, GLint start, GLsizei count)
314 {
315 GET_CURRENT_CONTEXT(ctx);
316
317 if (MESA_VERBOSE & VERBOSE_DRAW)
318 _mesa_debug(ctx, "glDrawArrays(%s, %d, %d)\n",
319 _mesa_lookup_enum_by_nr(mode), start, count);
320
321 if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
322 return;
323
324 FLUSH_CURRENT( ctx, 0 );
325
326 if (!_mesa_valid_to_render(ctx, "glDrawArrays")) {
327 return;
328 }
329
330 if (0)
331 check_draw_arrays_data(ctx, start, count);
332
333 vbo_draw_arrays(ctx, mode, start, count, 1);
334
335 if (0)
336 print_draw_arrays(ctx, mode, start, count);
337 }
338
339
340 /**
341 * Map GL_ELEMENT_ARRAY_BUFFER and print contents.
342 * For debugging.
343 */
344 #if 0
345 static void
346 dump_element_buffer(struct gl_context *ctx, GLenum type)
347 {
348 const GLvoid *map =
349 ctx->Driver.MapBufferRange(ctx, 0,
350 ctx->Array.ArrayObj->ElementArrayBufferObj->Size,
351 GL_MAP_READ_BIT,
352 ctx->Array.ArrayObj->ElementArrayBufferObj);
353 switch (type) {
354 case GL_UNSIGNED_BYTE:
355 {
356 const GLubyte *us = (const GLubyte *) map;
357 GLint i;
358 for (i = 0; i < ctx->Array.ArrayObj->ElementArrayBufferObj->Size; i++) {
359 printf("%02x ", us[i]);
360 if (i % 32 == 31)
361 printf("\n");
362 }
363 printf("\n");
364 }
365 break;
366 case GL_UNSIGNED_SHORT:
367 {
368 const GLushort *us = (const GLushort *) map;
369 GLint i;
370 for (i = 0; i < ctx->Array.ArrayObj->ElementArrayBufferObj->Size / 2; i++) {
371 printf("%04x ", us[i]);
372 if (i % 16 == 15)
373 printf("\n");
374 }
375 printf("\n");
376 }
377 break;
378 case GL_UNSIGNED_INT:
379 {
380 const GLuint *us = (const GLuint *) map;
381 GLint i;
382 for (i = 0; i < ctx->Array.ArrayObj->ElementArrayBufferObj->Size / 4; i++) {
383 printf("%08x ", us[i]);
384 if (i % 8 == 7)
385 printf("\n");
386 }
387 printf("\n");
388 }
389 break;
390 default:
391 ;
392 }
393
394 ctx->Driver.UnmapBuffer(ctx, ctx->Array.ArrayObj->ElementArrayBufferObj);
395 }
396 #endif
397
398
399 /**
400 * Inner support for both _mesa_DrawElements and _mesa_DrawRangeElements.
401 * Do the rendering for a glDrawElements or glDrawRangeElements call after
402 * we've validated buffer bounds, etc.
403 */
404 static void
405 vbo_validated_drawrangeelements(struct gl_context *ctx, GLenum mode,
406 GLboolean index_bounds_valid,
407 GLuint start, GLuint end,
408 GLsizei count, GLenum type,
409 const GLvoid *indices, GLint numInstances)
410 {
411 struct vbo_context *vbo = vbo_context(ctx);
412 struct vbo_exec_context *exec = &vbo->exec;
413 struct _mesa_index_buffer ib;
414 struct _mesa_prim prim[1];
415
416 FLUSH_CURRENT( ctx, 0 );
417
418 if (!_mesa_valid_to_render(ctx, "glDraw[Range]Elements")) {
419 return;
420 }
421
422 vbo_bind_arrays( ctx );
423
424 vbo_draw_method(exec, DRAW_ARRAYS);
425
426 /* check for dirty state again */
427 if (ctx->NewState)
428 _mesa_update_state( ctx );
429
430 ib.count = count;
431 ib.type = type;
432 ib.obj = ctx->Array.ElementArrayBufferObj;
433 ib.ptr = indices;
434
435 prim[0].begin = 1;
436 prim[0].end = 1;
437 prim[0].weak = 0;
438 prim[0].pad = 0;
439 prim[0].mode = mode;
440 prim[0].start = 0;
441 prim[0].count = count;
442 prim[0].indexed = 1;
443 prim[0].num_instances = numInstances;
444
445 /* Need to give special consideration to rendering a range of
446 * indices starting somewhere above zero. Typically the
447 * application is issuing multiple DrawRangeElements() to draw
448 * successive primitives layed out linearly in the vertex arrays.
449 * Unless the vertex arrays are all in a VBO (or locked as with
450 * CVA), the OpenGL semantics imply that we need to re-read or
451 * re-upload the vertex data on each draw call.
452 *
453 * In the case of hardware tnl, we want to avoid starting the
454 * upload at zero, as it will mean every draw call uploads an
455 * increasing amount of not-used vertex data. Worse - in the
456 * software tnl module, all those vertices might be transformed and
457 * lit but never rendered.
458 *
459 * If we just upload or transform the vertices in start..end,
460 * however, the indices will be incorrect.
461 *
462 * At this level, we don't know exactly what the requirements of
463 * the backend are going to be, though it will likely boil down to
464 * either:
465 *
466 * 1) Do nothing, everything is in a VBO and is processed once
467 * only.
468 *
469 * 2) Adjust the indices and vertex arrays so that start becomes
470 * zero.
471 *
472 * Rather than doing anything here, I'll provide a helper function
473 * for the latter case elsewhere.
474 */
475
476 check_buffers_are_unmapped(exec->array.inputs);
477 vbo->draw_prims( ctx, exec->array.inputs, prim, 1, &ib,
478 index_bounds_valid, start, end );
479 }
480
481
482 /**
483 * Called by glDrawElements() in immediate mode.
484 */
485 static void GLAPIENTRY
486 vbo_exec_DrawElements(GLenum mode, GLsizei count, GLenum type,
487 const GLvoid *indices)
488 {
489 GET_CURRENT_CONTEXT(ctx);
490
491 if (MESA_VERBOSE & VERBOSE_DRAW)
492 _mesa_debug(ctx, "glDrawElements(%s, %u, %s, %p)\n",
493 _mesa_lookup_enum_by_nr(mode), count,
494 _mesa_lookup_enum_by_nr(type), indices);
495
496 if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices))
497 return;
498
499 vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
500 count, type, indices, 1);
501 }
502
503
504 /**
505 * Plug in the immediate-mode vertex array drawing commands into the
506 * givven vbo_exec_context object.
507 */
508 void
509 vbo_exec_array_init( struct vbo_exec_context *exec )
510 {
511 exec->vtxfmt.DrawArrays = vbo_exec_DrawArrays;
512 exec->vtxfmt.DrawElements = vbo_exec_DrawElements;
513 }
514
515
516 void
517 vbo_exec_array_destroy( struct vbo_exec_context *exec )
518 {
519 /* nothing to do */
520 }
521
522
523
524 /**
525 * The following functions are only used for OpenGL ES 1/2 support.
526 * And some aren't even supported (yet) in ES 1/2.
527 */
528
529
530 void GLAPIENTRY
531 _mesa_DrawArrays(GLenum mode, GLint first, GLsizei count)
532 {
533 vbo_exec_DrawArrays(mode, first, count);
534 }
535
536
537 void GLAPIENTRY
538 _mesa_DrawElements(GLenum mode, GLsizei count, GLenum type,
539 const GLvoid *indices)
540 {
541 vbo_exec_DrawElements(mode, count, type, indices);
542 }
543