1 /**************************************************************************
2
3 Copyright 2002-2008 VMware, Inc.
4
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 "Software"),
9 to deal in the Software without restriction, including without limitation
10 on the rights to use, copy, modify, merge, publish, distribute, sub
11 license, and/or sell copies of the Software, and to permit persons to whom
12 the Software is furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice (including the next
15 paragraph) shall be included in all copies or substantial portions of the
16 Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 VMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26 **************************************************************************/
27
28 /*
29 * Authors:
30 * Keith Whitwell <keithw@vmware.com>
31 */
32
33
34
35 /* Display list compiler attempts to store lists of vertices with the
36 * same vertex layout. Additionally it attempts to minimize the need
37 * for execute-time fixup of these vertex lists, allowing them to be
38 * cached on hardware.
39 *
40 * There are still some circumstances where this can be thwarted, for
41 * example by building a list that consists of one very long primitive
42 * (eg Begin(Triangles), 1000 vertices, End), and calling that list
43 * from inside a different begin/end object (Begin(Lines), CallList,
44 * End).
45 *
46 * In that case the code will have to replay the list as individual
47 * commands through the Exec dispatch table, or fix up the copied
48 * vertices at execute-time.
49 *
50 * The other case where fixup is required is when a vertex attribute
51 * is introduced in the middle of a primitive. Eg:
52 * Begin(Lines)
53 * TexCoord1f() Vertex2f()
54 * TexCoord1f() Color3f() Vertex2f()
55 * End()
56 *
57 * If the current value of Color isn't known at compile-time, this
58 * primitive will require fixup.
59 *
60 *
61 * The list compiler currently doesn't attempt to compile lists
62 * containing EvalCoord or EvalPoint commands. On encountering one of
63 * these, compilation falls back to opcodes.
64 *
65 * This could be improved to fallback only when a mix of EvalCoord and
66 * Vertex commands are issued within a single primitive.
67 *
68 * The compilation process works as follows. All vertex attributes
69 * except position are copied to vbo_save_context::attrptr (see ATTR_UNION).
70 * 'attrptr' are pointers to vbo_save_context::vertex ordered according to the enabled
71 * attributes (se upgrade_vertex).
72 * When the position attribute is received, all the attributes are then
73 * copied to the vertex_store (see the end of ATTR_UNION).
74 * The vertex_store is simply an extensible float array.
75 * When the vertex list needs to be compiled (see compile_vertex_list),
76 * several transformations are performed:
77 * - some primitives are merged together (eg: two consecutive GL_TRIANGLES
78 * with 3 vertices can be merged in a single GL_TRIANGLES with 6 vertices).
79 * - an index buffer is built.
80 * - identical vertices are detected and only one is kept.
81 * At the end of this transformation, the index buffer and the vertex buffer
82 * are uploaded in vRAM in the same buffer object.
83 * This buffer object is shared between multiple display list to allow
84 * draw calls merging later.
85 *
86 * The layout of this buffer for two display lists is:
87 * V0A0|V0A1|V1A0|V1A1|P0I0|P0I1|V0A0V0A1V0A2|V1A1V1A1V1A2|...
88 * ` new list starts
89 * - VxAy: vertex x, attributes y
90 * - PxIy: draw x, index y
91 *
92 * To allow draw call merging, display list must use the same VAO, including
93 * the same Offset in the buffer object. To achieve this, the start values of
94 * the primitive are shifted and the indices adjusted (see offset_diff and
95 * start_offset in compile_vertex_list).
96 *
97 * Display list using the loopback code (see vbo_save_playback_vertex_list_loopback),
98 * can't be drawn with an index buffer so this transformation is disabled
99 * in this case.
100 */
101
102
103 #include "main/glheader.h"
104 #include "main/arrayobj.h"
105 #include "main/bufferobj.h"
106 #include "main/context.h"
107 #include "main/dlist.h"
108 #include "main/enums.h"
109 #include "main/eval.h"
110 #include "main/macros.h"
111 #include "main/draw_validate.h"
112 #include "main/api_arrayelt.h"
113 #include "main/vtxfmt.h"
114 #include "main/dispatch.h"
115 #include "main/state.h"
116 #include "main/varray.h"
117 #include "util/bitscan.h"
118 #include "util/u_memory.h"
119 #include "util/hash_table.h"
120 #include "util/u_prim.h"
121
122 #include "gallium/include/pipe/p_state.h"
123
124 #include "vbo_noop.h"
125 #include "vbo_private.h"
126
127
128 #ifdef ERROR
129 #undef ERROR
130 #endif
131
132 /* An interesting VBO number/name to help with debugging */
133 #define VBO_BUF_ID 12345
134
135 static void GLAPIENTRY
136 _save_Materialfv(GLenum face, GLenum pname, const GLfloat *params);
137
138 static void GLAPIENTRY
139 _save_EvalCoord1f(GLfloat u);
140
141 static void GLAPIENTRY
142 _save_EvalCoord2f(GLfloat u, GLfloat v);
143
144 static void
handle_out_of_memory(struct gl_context * ctx)145 handle_out_of_memory(struct gl_context *ctx)
146 {
147 struct vbo_save_context *save = &vbo_context(ctx)->save;
148 _mesa_noop_vtxfmt_init(ctx, &save->vtxfmt);
149 save->out_of_memory = true;
150 }
151
152 /*
153 * NOTE: Old 'parity' issue is gone, but copying can still be
154 * wrong-footed on replay.
155 */
156 static GLuint
copy_vertices(struct gl_context * ctx,const struct vbo_save_vertex_list * node,const fi_type * src_buffer)157 copy_vertices(struct gl_context *ctx,
158 const struct vbo_save_vertex_list *node,
159 const fi_type * src_buffer)
160 {
161 struct vbo_save_context *save = &vbo_context(ctx)->save;
162 struct _mesa_prim *prim = &node->cold->prims[node->cold->prim_count - 1];
163 GLuint sz = save->vertex_size;
164
165 if (prim->end || !prim->count || !sz)
166 return 0;
167
168 const fi_type *src = src_buffer + prim->start * sz;
169 assert(save->copied.buffer == NULL);
170 save->copied.buffer = malloc(sizeof(fi_type) * sz * prim->count);
171
172 unsigned r = vbo_copy_vertices(ctx, prim->mode, prim->start, &prim->count,
173 prim->begin, sz, true, save->copied.buffer, src);
174 if (!r) {
175 free(save->copied.buffer);
176 save->copied.buffer = NULL;
177 }
178 return r;
179 }
180
181
182 static struct vbo_save_primitive_store *
realloc_prim_store(struct vbo_save_primitive_store * store,int prim_count)183 realloc_prim_store(struct vbo_save_primitive_store *store, int prim_count)
184 {
185 if (store == NULL)
186 store = CALLOC_STRUCT(vbo_save_primitive_store);
187
188 uint32_t old_size = store->size;
189 store->size = prim_count;
190 assert (old_size < store->size);
191 store->prims = realloc(store->prims, store->size * sizeof(struct _mesa_prim));
192 memset(&store->prims[old_size], 0, (store->size - old_size) * sizeof(struct _mesa_prim));
193
194 return store;
195 }
196
197
198 static void
reset_counters(struct gl_context * ctx)199 reset_counters(struct gl_context *ctx)
200 {
201 struct vbo_save_context *save = &vbo_context(ctx)->save;
202
203 save->vertex_store->used = 0;
204 save->prim_store->used = 0;
205 save->dangling_attr_ref = GL_FALSE;
206 }
207
208 /**
209 * For a list of prims, try merging prims that can just be extensions of the
210 * previous prim.
211 */
212 static void
merge_prims(struct gl_context * ctx,struct _mesa_prim * prim_list,GLuint * prim_count)213 merge_prims(struct gl_context *ctx, struct _mesa_prim *prim_list,
214 GLuint *prim_count)
215 {
216 GLuint i;
217 struct _mesa_prim *prev_prim = prim_list;
218
219 for (i = 1; i < *prim_count; i++) {
220 struct _mesa_prim *this_prim = prim_list + i;
221
222 vbo_try_prim_conversion(&this_prim->mode, &this_prim->count);
223
224 if (vbo_merge_draws(ctx, true,
225 prev_prim->mode, this_prim->mode,
226 prev_prim->start, this_prim->start,
227 &prev_prim->count, this_prim->count,
228 prev_prim->basevertex, this_prim->basevertex,
229 &prev_prim->end,
230 this_prim->begin, this_prim->end)) {
231 /* We've found a prim that just extend the previous one. Tack it
232 * onto the previous one, and let this primitive struct get dropped.
233 */
234 continue;
235 }
236
237 /* If any previous primitives have been dropped, then we need to copy
238 * this later one into the next available slot.
239 */
240 prev_prim++;
241 if (prev_prim != this_prim)
242 *prev_prim = *this_prim;
243 }
244
245 *prim_count = prev_prim - prim_list + 1;
246 }
247
248
249 /**
250 * Convert GL_LINE_LOOP primitive into GL_LINE_STRIP so that drivers
251 * don't have to worry about handling the _mesa_prim::begin/end flags.
252 * See https://bugs.freedesktop.org/show_bug.cgi?id=81174
253 */
254 static void
convert_line_loop_to_strip(struct vbo_save_context * save,struct vbo_save_vertex_list * node)255 convert_line_loop_to_strip(struct vbo_save_context *save,
256 struct vbo_save_vertex_list *node)
257 {
258 struct _mesa_prim *prim = &node->cold->prims[node->cold->prim_count - 1];
259
260 assert(prim->mode == GL_LINE_LOOP);
261
262 if (prim->end) {
263 /* Copy the 0th vertex to end of the buffer and extend the
264 * vertex count by one to finish the line loop.
265 */
266 const GLuint sz = save->vertex_size;
267 /* 0th vertex: */
268 const fi_type *src = save->vertex_store->buffer_in_ram + prim->start * sz;
269 /* end of buffer: */
270 fi_type *dst = save->vertex_store->buffer_in_ram + (prim->start + prim->count) * sz;
271
272 memcpy(dst, src, sz * sizeof(float));
273
274 prim->count++;
275 node->cold->vertex_count++;
276 save->vertex_store->used += sz;
277 }
278
279 if (!prim->begin) {
280 /* Drawing the second or later section of a long line loop.
281 * Skip the 0th vertex.
282 */
283 prim->start++;
284 prim->count--;
285 }
286
287 prim->mode = GL_LINE_STRIP;
288 }
289
290
291 /* Compare the present vao if it has the same setup. */
292 static bool
compare_vao(gl_vertex_processing_mode mode,const struct gl_vertex_array_object * vao,const struct gl_buffer_object * bo,GLintptr buffer_offset,GLuint stride,GLbitfield64 vao_enabled,const GLubyte size[VBO_ATTRIB_MAX],const GLenum16 type[VBO_ATTRIB_MAX],const GLuint offset[VBO_ATTRIB_MAX])293 compare_vao(gl_vertex_processing_mode mode,
294 const struct gl_vertex_array_object *vao,
295 const struct gl_buffer_object *bo, GLintptr buffer_offset,
296 GLuint stride, GLbitfield64 vao_enabled,
297 const GLubyte size[VBO_ATTRIB_MAX],
298 const GLenum16 type[VBO_ATTRIB_MAX],
299 const GLuint offset[VBO_ATTRIB_MAX])
300 {
301 if (!vao)
302 return false;
303
304 /* If the enabled arrays are not the same we are not equal. */
305 if (vao_enabled != vao->Enabled)
306 return false;
307
308 /* Check the buffer binding at 0 */
309 if (vao->BufferBinding[0].BufferObj != bo)
310 return false;
311 /* BufferBinding[0].Offset != buffer_offset is checked per attribute */
312 if (vao->BufferBinding[0].Stride != stride)
313 return false;
314 assert(vao->BufferBinding[0].InstanceDivisor == 0);
315
316 /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space */
317 const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode];
318
319 /* Now check the enabled arrays */
320 GLbitfield mask = vao_enabled;
321 while (mask) {
322 const int attr = u_bit_scan(&mask);
323 const unsigned char vbo_attr = vao_to_vbo_map[attr];
324 const GLenum16 tp = type[vbo_attr];
325 const GLintptr off = offset[vbo_attr] + buffer_offset;
326 const struct gl_array_attributes *attrib = &vao->VertexAttrib[attr];
327 if (attrib->RelativeOffset + vao->BufferBinding[0].Offset != off)
328 return false;
329 if (attrib->Format.Type != tp)
330 return false;
331 if (attrib->Format.Size != size[vbo_attr])
332 return false;
333 assert(attrib->Format.Format == GL_RGBA);
334 assert(attrib->Format.Normalized == GL_FALSE);
335 assert(attrib->Format.Integer == vbo_attrtype_to_integer_flag(tp));
336 assert(attrib->Format.Doubles == vbo_attrtype_to_double_flag(tp));
337 assert(attrib->BufferBindingIndex == 0);
338 }
339
340 return true;
341 }
342
343
344 /* Create or reuse the vao for the vertex processing mode. */
345 static void
update_vao(struct gl_context * ctx,gl_vertex_processing_mode mode,struct gl_vertex_array_object ** vao,struct gl_buffer_object * bo,GLintptr buffer_offset,GLuint stride,GLbitfield64 vbo_enabled,const GLubyte size[VBO_ATTRIB_MAX],const GLenum16 type[VBO_ATTRIB_MAX],const GLuint offset[VBO_ATTRIB_MAX])346 update_vao(struct gl_context *ctx,
347 gl_vertex_processing_mode mode,
348 struct gl_vertex_array_object **vao,
349 struct gl_buffer_object *bo, GLintptr buffer_offset,
350 GLuint stride, GLbitfield64 vbo_enabled,
351 const GLubyte size[VBO_ATTRIB_MAX],
352 const GLenum16 type[VBO_ATTRIB_MAX],
353 const GLuint offset[VBO_ATTRIB_MAX])
354 {
355 /* Compute the bitmasks of vao_enabled arrays */
356 GLbitfield vao_enabled = _vbo_get_vao_enabled_from_vbo(mode, vbo_enabled);
357
358 /*
359 * Check if we can possibly reuse the exisiting one.
360 * In the long term we should reset them when something changes.
361 */
362 if (compare_vao(mode, *vao, bo, buffer_offset, stride,
363 vao_enabled, size, type, offset))
364 return;
365
366 /* The initial refcount is 1 */
367 _mesa_reference_vao(ctx, vao, NULL);
368 *vao = _mesa_new_vao(ctx, ~((GLuint)0));
369
370 /*
371 * assert(stride <= ctx->Const.MaxVertexAttribStride);
372 * MaxVertexAttribStride is not set for drivers that does not
373 * expose GL 44 or GLES 31.
374 */
375
376 /* Bind the buffer object at binding point 0 */
377 _mesa_bind_vertex_buffer(ctx, *vao, 0, bo, buffer_offset, stride, false,
378 false);
379
380 /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space
381 * Note that the position/generic0 aliasing is done in the VAO.
382 */
383 const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode];
384 /* Now set the enable arrays */
385 GLbitfield mask = vao_enabled;
386 while (mask) {
387 const int vao_attr = u_bit_scan(&mask);
388 const GLubyte vbo_attr = vao_to_vbo_map[vao_attr];
389 assert(offset[vbo_attr] <= ctx->Const.MaxVertexAttribRelativeOffset);
390
391 _vbo_set_attrib_format(ctx, *vao, vao_attr, buffer_offset,
392 size[vbo_attr], type[vbo_attr], offset[vbo_attr]);
393 _mesa_vertex_attrib_binding(ctx, *vao, vao_attr, 0);
394 }
395 _mesa_enable_vertex_array_attribs(ctx, *vao, vao_enabled);
396 assert(vao_enabled == (*vao)->Enabled);
397 assert((vao_enabled & ~(*vao)->VertexAttribBufferMask) == 0);
398
399 /* Finalize and freeze the VAO */
400 _mesa_set_vao_immutable(ctx, *vao);
401 }
402
403 static void wrap_filled_vertex(struct gl_context *ctx);
404
405 /* Grow the vertex storage to accomodate for vertex_count new vertices */
406 static void
grow_vertex_storage(struct gl_context * ctx,int vertex_count)407 grow_vertex_storage(struct gl_context *ctx, int vertex_count)
408 {
409 struct vbo_save_context *save = &vbo_context(ctx)->save;
410 assert (save->vertex_store);
411
412 int new_size = (save->vertex_store->used +
413 vertex_count * save->vertex_size) * sizeof(GLfloat);
414
415 /* Limit how much memory we allocate. */
416 if (save->prim_store->used > 0 &&
417 vertex_count > 0 &&
418 new_size > VBO_SAVE_BUFFER_SIZE) {
419 wrap_filled_vertex(ctx);
420 new_size = VBO_SAVE_BUFFER_SIZE;
421 }
422
423 if (new_size > save->vertex_store->buffer_in_ram_size) {
424 save->vertex_store->buffer_in_ram_size = new_size;
425 save->vertex_store->buffer_in_ram = realloc(save->vertex_store->buffer_in_ram,
426 save->vertex_store->buffer_in_ram_size);
427 if (save->vertex_store->buffer_in_ram == NULL)
428 handle_out_of_memory(ctx);
429 }
430
431 }
432
433 struct vertex_key {
434 unsigned vertex_size;
435 fi_type *vertex_attributes;
436 };
437
_hash_vertex_key(const void * key)438 static uint32_t _hash_vertex_key(const void *key)
439 {
440 struct vertex_key *k = (struct vertex_key*)key;
441 unsigned sz = k->vertex_size;
442 assert(sz);
443 return _mesa_hash_data(k->vertex_attributes, sz * sizeof(float));
444 }
445
_compare_vertex_key(const void * key1,const void * key2)446 static bool _compare_vertex_key(const void *key1, const void *key2)
447 {
448 struct vertex_key *k1 = (struct vertex_key*)key1;
449 struct vertex_key *k2 = (struct vertex_key*)key2;
450 /* All the compared vertices are going to be drawn with the same VAO,
451 * so we can compare the attributes. */
452 assert (k1->vertex_size == k2->vertex_size);
453 return memcmp(k1->vertex_attributes,
454 k2->vertex_attributes,
455 k1->vertex_size * sizeof(float)) == 0;
456 }
457
_free_entry(struct hash_entry * entry)458 static void _free_entry(struct hash_entry *entry)
459 {
460 free((void*)entry->key);
461 }
462
463 /* Add vertex to the vertex buffer and return its index. If this vertex is a duplicate
464 * of an existing vertex, return the original index instead.
465 */
466 static uint32_t
add_vertex(struct vbo_save_context * save,struct hash_table * hash_to_index,uint32_t index,fi_type * new_buffer,uint32_t * max_index)467 add_vertex(struct vbo_save_context *save, struct hash_table *hash_to_index,
468 uint32_t index, fi_type *new_buffer, uint32_t *max_index)
469 {
470 /* If vertex deduplication is disabled return the original index. */
471 if (!hash_to_index)
472 return index;
473
474 fi_type *vert = save->vertex_store->buffer_in_ram + save->vertex_size * index;
475
476 struct vertex_key *key = malloc(sizeof(struct vertex_key));
477 key->vertex_size = save->vertex_size;
478 key->vertex_attributes = vert;
479
480 struct hash_entry *entry = _mesa_hash_table_search(hash_to_index, key);
481 if (entry) {
482 free(key);
483 /* We found an existing vertex with the same hash, return its index. */
484 return (uintptr_t) entry->data;
485 } else {
486 /* This is a new vertex. Determine a new index and copy its attributes to the vertex
487 * buffer. Note that 'new_buffer' is created at each list compilation so we write vertices
488 * starting at index 0.
489 */
490 uint32_t n = _mesa_hash_table_num_entries(hash_to_index);
491 *max_index = MAX2(n, *max_index);
492
493 memcpy(&new_buffer[save->vertex_size * n],
494 vert,
495 save->vertex_size * sizeof(fi_type));
496
497 _mesa_hash_table_insert(hash_to_index, key, (void*)(uintptr_t)(n));
498
499 /* The index buffer is shared between list compilations, so add the base index to get
500 * the final index.
501 */
502 return n;
503 }
504 }
505
506
507 static uint32_t
get_vertex_count(struct vbo_save_context * save)508 get_vertex_count(struct vbo_save_context *save)
509 {
510 if (!save->vertex_size)
511 return 0;
512 return save->vertex_store->used / save->vertex_size;
513 }
514
515
516 /**
517 * Insert the active immediate struct onto the display list currently
518 * being built.
519 */
520 static void
compile_vertex_list(struct gl_context * ctx)521 compile_vertex_list(struct gl_context *ctx)
522 {
523 struct vbo_save_context *save = &vbo_context(ctx)->save;
524 struct vbo_save_vertex_list *node;
525
526 /* Allocate space for this structure in the display list currently
527 * being compiled.
528 */
529 node = (struct vbo_save_vertex_list *)
530 _mesa_dlist_alloc_vertex_list(ctx, !save->dangling_attr_ref && !save->no_current_update);
531
532 if (!node)
533 return;
534
535 memset(node, 0, sizeof(struct vbo_save_vertex_list));
536 node->cold = calloc(1, sizeof(*node->cold));
537
538 /* Make sure the pointer is aligned to the size of a pointer */
539 assert((GLintptr) node % sizeof(void *) == 0);
540
541 const GLsizei stride = save->vertex_size*sizeof(GLfloat);
542
543 node->cold->vertex_count = get_vertex_count(save);
544 node->cold->wrap_count = save->copied.nr;
545 node->cold->prims = malloc(sizeof(struct _mesa_prim) * save->prim_store->used);
546 memcpy(node->cold->prims, save->prim_store->prims, sizeof(struct _mesa_prim) * save->prim_store->used);
547 node->cold->ib.obj = NULL;
548 node->cold->prim_count = save->prim_store->used;
549
550 if (save->no_current_update) {
551 node->cold->current_data = NULL;
552 }
553 else {
554 GLuint current_size = save->vertex_size - save->attrsz[0];
555 node->cold->current_data = NULL;
556
557 if (current_size) {
558 node->cold->current_data = malloc(current_size * sizeof(GLfloat));
559 if (node->cold->current_data) {
560 const char *buffer = (const char *)save->vertex_store->buffer_in_ram;
561 unsigned attr_offset = save->attrsz[0] * sizeof(GLfloat);
562 unsigned vertex_offset = 0;
563
564 if (node->cold->vertex_count)
565 vertex_offset = (node->cold->vertex_count - 1) * stride;
566
567 memcpy(node->cold->current_data, buffer + vertex_offset + attr_offset,
568 current_size * sizeof(GLfloat));
569 } else {
570 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Current value allocation");
571 handle_out_of_memory(ctx);
572 }
573 }
574 }
575
576 assert(save->attrsz[VBO_ATTRIB_POS] != 0 || node->cold->vertex_count == 0);
577
578 if (save->dangling_attr_ref)
579 ctx->ListState.Current.UseLoopback = true;
580
581 /* Copy duplicated vertices
582 */
583 save->copied.nr = copy_vertices(ctx, node, save->vertex_store->buffer_in_ram);
584
585 if (node->cold->prims[node->cold->prim_count - 1].mode == GL_LINE_LOOP) {
586 convert_line_loop_to_strip(save, node);
587 }
588
589 merge_prims(ctx, node->cold->prims, &node->cold->prim_count);
590
591 GLintptr buffer_offset = 0;
592 GLuint start_offset = 0;
593
594 /* Create an index buffer. */
595 node->cold->min_index = node->cold->max_index = 0;
596 if (node->cold->vertex_count == 0 || node->cold->prim_count == 0)
597 goto end;
598
599 /* We won't modify node->prims, so use a const alias to avoid unintended
600 * writes to it. */
601 const struct _mesa_prim *original_prims = node->cold->prims;
602
603 int end = original_prims[node->cold->prim_count - 1].start +
604 original_prims[node->cold->prim_count - 1].count;
605 int total_vert_count = end - original_prims[0].start;
606
607 node->cold->min_index = node->cold->prims[0].start;
608 node->cold->max_index = end - 1;
609
610 int max_index_count = total_vert_count * 2;
611 uint32_t* indices = (uint32_t*) malloc(max_index_count * sizeof(uint32_t));
612 struct _mesa_prim *merged_prims = NULL;
613
614 int idx = 0;
615 struct hash_table *vertex_to_index = NULL;
616 fi_type *temp_vertices_buffer = NULL;
617
618 /* The loopback replay code doesn't use the index buffer, so we can't
619 * dedup vertices in this case.
620 */
621 if (!ctx->ListState.Current.UseLoopback) {
622 vertex_to_index = _mesa_hash_table_create(NULL, _hash_vertex_key, _compare_vertex_key);
623 temp_vertices_buffer = malloc(save->vertex_store->buffer_in_ram_size);
624 }
625
626 uint32_t max_index = 0;
627
628 int last_valid_prim = -1;
629 /* Construct indices array. */
630 for (unsigned i = 0; i < node->cold->prim_count; i++) {
631 assert(original_prims[i].basevertex == 0);
632 GLubyte mode = original_prims[i].mode;
633
634 int vertex_count = original_prims[i].count;
635 if (!vertex_count) {
636 continue;
637 }
638
639 /* Increase indices storage if the original estimation was too small. */
640 if (idx + 3 * vertex_count > max_index_count) {
641 max_index_count = max_index_count + 3 * vertex_count;
642 indices = (uint32_t*) realloc(indices, max_index_count * sizeof(uint32_t));
643 }
644
645 /* Line strips may get converted to lines */
646 if (mode == GL_LINE_STRIP)
647 mode = GL_LINES;
648
649 /* If 2 consecutive prims use the same mode => merge them. */
650 bool merge_prims = last_valid_prim >= 0 &&
651 mode == merged_prims[last_valid_prim].mode &&
652 mode != GL_LINE_LOOP && mode != GL_TRIANGLE_FAN &&
653 mode != GL_QUAD_STRIP && mode != GL_POLYGON &&
654 mode != GL_PATCHES;
655
656 /* To be able to merge consecutive triangle strips we need to insert
657 * a degenerate triangle.
658 */
659 if (merge_prims &&
660 mode == GL_TRIANGLE_STRIP) {
661 /* Insert a degenerate triangle */
662 assert(merged_prims[last_valid_prim].mode == GL_TRIANGLE_STRIP);
663 unsigned tri_count = merged_prims[last_valid_prim].count - 2;
664
665 indices[idx] = indices[idx - 1];
666 indices[idx + 1] = add_vertex(save, vertex_to_index, original_prims[i].start,
667 temp_vertices_buffer, &max_index);
668 idx += 2;
669 merged_prims[last_valid_prim].count += 2;
670
671 if (tri_count % 2) {
672 /* Add another index to preserve winding order */
673 indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start,
674 temp_vertices_buffer, &max_index);
675 merged_prims[last_valid_prim].count++;
676 }
677 }
678
679 int start = idx;
680
681 /* Convert line strips to lines if it'll allow if the previous
682 * prim mode is GL_LINES (so merge_prims is true) or if the next
683 * primitive mode is GL_LINES or GL_LINE_LOOP.
684 */
685 if (original_prims[i].mode == GL_LINE_STRIP &&
686 (merge_prims ||
687 (i < node->cold->prim_count - 1 &&
688 (original_prims[i + 1].mode == GL_LINE_STRIP ||
689 original_prims[i + 1].mode == GL_LINES)))) {
690 for (unsigned j = 0; j < vertex_count; j++) {
691 indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start + j,
692 temp_vertices_buffer, &max_index);
693 /* Repeat all but the first/last indices. */
694 if (j && j != vertex_count - 1) {
695 indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start + j,
696 temp_vertices_buffer, &max_index);
697 }
698 }
699 } else {
700 /* We didn't convert to LINES, so restore the original mode */
701 mode = original_prims[i].mode;
702
703 for (unsigned j = 0; j < vertex_count; j++) {
704 indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start + j,
705 temp_vertices_buffer, &max_index);
706 }
707 }
708
709 /* Duplicate the last vertex for incomplete primitives */
710 unsigned min_vert = u_prim_vertex_count(mode)->min;
711 for (unsigned j = vertex_count; j < min_vert; j++) {
712 indices[idx++] = add_vertex(save, vertex_to_index,
713 original_prims[i].start + vertex_count - 1,
714 temp_vertices_buffer, &max_index);
715 }
716
717 if (merge_prims) {
718 /* Update vertex count. */
719 merged_prims[last_valid_prim].count += idx - start;
720 } else {
721 /* Keep this primitive */
722 last_valid_prim += 1;
723 assert(last_valid_prim <= i);
724 merged_prims = realloc(merged_prims, (1 + last_valid_prim) * sizeof(struct _mesa_prim));
725 merged_prims[last_valid_prim] = original_prims[i];
726 merged_prims[last_valid_prim].start = start;
727 merged_prims[last_valid_prim].count = idx - start;
728 }
729 merged_prims[last_valid_prim].mode = mode;
730 }
731
732 assert(idx > 0 && idx <= max_index_count);
733
734 unsigned merged_prim_count = last_valid_prim + 1;
735 node->cold->ib.ptr = NULL;
736 node->cold->ib.count = idx;
737 node->cold->ib.index_size_shift = (GL_UNSIGNED_INT - GL_UNSIGNED_BYTE) >> 1;
738
739 /* How many bytes do we need to store the indices and the vertices */
740 total_vert_count = vertex_to_index ? (max_index + 1) : idx;
741 unsigned total_bytes_needed = idx * sizeof(uint32_t) +
742 total_vert_count * save->vertex_size * sizeof(fi_type);
743
744 const GLintptr old_offset = save->VAO[0] ?
745 save->VAO[0]->BufferBinding[0].Offset + save->VAO[0]->VertexAttrib[VERT_ATTRIB_POS].RelativeOffset : 0;
746 if (old_offset != save->current_bo_bytes_used && stride > 0) {
747 GLintptr offset_diff = save->current_bo_bytes_used - old_offset;
748 while (offset_diff > 0 &&
749 save->current_bo_bytes_used < save->current_bo->Size &&
750 offset_diff % stride != 0) {
751 save->current_bo_bytes_used++;
752 offset_diff = save->current_bo_bytes_used - old_offset;
753 }
754 }
755 buffer_offset = save->current_bo_bytes_used;
756
757 /* Can we reuse the previous bo or should we allocate a new one? */
758 int available_bytes = save->current_bo ? save->current_bo->Size - save->current_bo_bytes_used : 0;
759 if (total_bytes_needed > available_bytes) {
760 if (save->current_bo)
761 _mesa_reference_buffer_object(ctx, &save->current_bo, NULL);
762 save->current_bo = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID + 1);
763 bool success = ctx->Driver.BufferData(ctx,
764 GL_ELEMENT_ARRAY_BUFFER_ARB,
765 MAX2(total_bytes_needed, VBO_SAVE_BUFFER_SIZE),
766 NULL,
767 GL_STATIC_DRAW_ARB, GL_MAP_WRITE_BIT,
768 save->current_bo);
769 if (!success) {
770 _mesa_reference_buffer_object(ctx, &save->current_bo, NULL);
771 _mesa_error(ctx, GL_OUT_OF_MEMORY, "IB allocation");
772 handle_out_of_memory(ctx);
773 } else {
774 save->current_bo_bytes_used = 0;
775 available_bytes = save->current_bo->Size;
776 }
777 buffer_offset = 0;
778 } else {
779 assert(old_offset <= buffer_offset);
780 const GLintptr offset_diff = buffer_offset - old_offset;
781 if (offset_diff > 0 && stride > 0 && offset_diff % stride == 0) {
782 /* The vertex size is an exact multiple of the buffer offset.
783 * This means that we can use zero-based vertex attribute pointers
784 * and specify the start of the primitive with the _mesa_prim::start
785 * field. This results in issuing several draw calls with identical
786 * vertex attribute information. This can result in fewer state
787 * changes in drivers. In particular, the Gallium CSO module will
788 * filter out redundant vertex buffer changes.
789 */
790 /* We cannot immediately update the primitives as some methods below
791 * still need the uncorrected start vertices
792 */
793 start_offset = offset_diff/stride;
794 assert(old_offset == buffer_offset - offset_diff);
795 buffer_offset = old_offset;
796 }
797
798 /* Correct the primitive starts, we can only do this here as copy_vertices
799 * and convert_line_loop_to_strip above consume the uncorrected starts.
800 * On the other hand the _vbo_loopback_vertex_list call below needs the
801 * primitives to be corrected already.
802 */
803 for (unsigned i = 0; i < node->cold->prim_count; i++) {
804 node->cold->prims[i].start += start_offset;
805 }
806 /* start_offset shifts vertices (so v[0] becomes v[start_offset]), so we have
807 * to apply this transformation to all indices and max_index.
808 */
809 for (unsigned i = 0; i < idx; i++)
810 indices[i] += start_offset;
811 max_index += start_offset;
812 }
813
814 _mesa_reference_buffer_object(ctx, &node->cold->ib.obj, save->current_bo);
815
816 /* Upload the vertices first (see buffer_offset) */
817 ctx->Driver.BufferSubData(ctx,
818 save->current_bo_bytes_used,
819 total_vert_count * save->vertex_size * sizeof(fi_type),
820 vertex_to_index ? temp_vertices_buffer : save->vertex_store->buffer_in_ram,
821 node->cold->ib.obj);
822 save->current_bo_bytes_used += total_vert_count * save->vertex_size * sizeof(fi_type);
823
824 if (vertex_to_index) {
825 _mesa_hash_table_destroy(vertex_to_index, _free_entry);
826 free(temp_vertices_buffer);
827 }
828
829 /* Since we append the indices to an existing buffer, we need to adjust the start value of each
830 * primitive (not the indices themselves). */
831 if (!ctx->ListState.Current.UseLoopback) {
832 save->current_bo_bytes_used += align(save->current_bo_bytes_used, 4) - save->current_bo_bytes_used;
833 int indices_offset = save->current_bo_bytes_used / 4;
834 for (int i = 0; i < merged_prim_count; i++) {
835 merged_prims[i].start += indices_offset;
836 }
837 }
838
839 /* Then upload the indices. */
840 if (node->cold->ib.obj) {
841 ctx->Driver.BufferSubData(ctx,
842 save->current_bo_bytes_used,
843 idx * sizeof(uint32_t),
844 indices,
845 node->cold->ib.obj);
846 save->current_bo_bytes_used += idx * sizeof(uint32_t);
847 } else {
848 node->cold->vertex_count = 0;
849 node->cold->prim_count = 0;
850 }
851
852 /* Prepare for DrawGallium */
853 memset(&node->merged.info, 0, sizeof(struct pipe_draw_info));
854 /* The other info fields will be updated in vbo_save_playback_vertex_list */
855 node->merged.info.index_size = 4;
856 node->merged.info.instance_count = 1;
857 node->merged.info.index.gl_bo = node->cold->ib.obj;
858 if (merged_prim_count == 1) {
859 node->merged.info.mode = merged_prims[0].mode;
860 node->merged.start_count.start = merged_prims[0].start;
861 node->merged.start_count.count = merged_prims[0].count;
862 node->merged.start_count.index_bias = 0;
863 node->merged.mode = NULL;
864 } else {
865 node->merged.mode = malloc(merged_prim_count * sizeof(unsigned char));
866 node->merged.start_counts = malloc(merged_prim_count * sizeof(struct pipe_draw_start_count_bias));
867 for (unsigned i = 0; i < merged_prim_count; i++) {
868 node->merged.start_counts[i].start = merged_prims[i].start;
869 node->merged.start_counts[i].count = merged_prims[i].count;
870 node->merged.start_counts[i].index_bias = 0;
871 node->merged.mode[i] = merged_prims[i].mode;
872 }
873 }
874 node->merged.num_draws = merged_prim_count;
875 if (node->merged.num_draws > 1) {
876 bool same_mode = true;
877 for (unsigned i = 1; i < node->merged.num_draws && same_mode; i++) {
878 same_mode = node->merged.mode[i] == node->merged.mode[0];
879 }
880 if (same_mode) {
881 /* All primitives use the same mode, so we can simplify a bit */
882 node->merged.info.mode = node->merged.mode[0];
883 free(node->merged.mode);
884 node->merged.mode = NULL;
885 }
886 }
887
888 free(indices);
889 free(merged_prims);
890
891 end:
892
893 if (!save->current_bo) {
894 save->current_bo = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID + 1);
895 bool success = ctx->Driver.BufferData(ctx,
896 GL_ELEMENT_ARRAY_BUFFER_ARB,
897 VBO_SAVE_BUFFER_SIZE,
898 NULL,
899 GL_STATIC_DRAW_ARB, GL_MAP_WRITE_BIT,
900 save->current_bo);
901 if (!success)
902 handle_out_of_memory(ctx);
903 }
904
905 GLuint offsets[VBO_ATTRIB_MAX];
906 for (unsigned i = 0, offset = 0; i < VBO_ATTRIB_MAX; ++i) {
907 offsets[i] = offset;
908 offset += save->attrsz[i] * sizeof(GLfloat);
909 }
910 /* Create a pair of VAOs for the possible VERTEX_PROCESSING_MODEs
911 * Note that this may reuse the previous one of possible.
912 */
913 for (gl_vertex_processing_mode vpm = VP_MODE_FF; vpm < VP_MODE_MAX; ++vpm) {
914 /* create or reuse the vao */
915 update_vao(ctx, vpm, &save->VAO[vpm],
916 save->current_bo, buffer_offset, stride,
917 save->enabled, save->attrsz, save->attrtype, offsets);
918 /* Reference the vao in the dlist */
919 node->VAO[vpm] = NULL;
920 _mesa_reference_vao(ctx, &node->VAO[vpm], save->VAO[vpm]);
921 }
922
923 /* Prepare for DrawGalliumVertexState */
924 if (node->merged.num_draws && ctx->Driver.DrawGalliumVertexState) {
925 for (unsigned i = 0; i < VP_MODE_MAX; i++) {
926 uint32_t enabled_attribs = _vbo_get_vao_filter(i) &
927 node->VAO[i]->_EnabledWithMapMode;
928
929 node->merged.gallium.state[i] =
930 ctx->Driver.CreateGalliumVertexState(ctx, node->VAO[i],
931 node->cold->ib.obj,
932 enabled_attribs);
933 node->merged.gallium.private_refcount[i] = 0;
934 node->merged.gallium.enabled_attribs[i] = enabled_attribs;
935 }
936
937 node->merged.gallium.ctx = ctx;
938 node->merged.gallium.info.mode = node->merged.info.mode;
939 node->merged.gallium.info.take_vertex_state_ownership = false;
940 assert(node->merged.info.index_size == 4);
941 }
942
943 /* Deal with GL_COMPILE_AND_EXECUTE:
944 */
945 if (ctx->ExecuteFlag) {
946 struct _glapi_table *dispatch = GET_DISPATCH();
947
948 _glapi_set_dispatch(ctx->Exec);
949
950 /* _vbo_loopback_vertex_list doesn't use the index buffer, so we have to
951 * use buffer_in_ram (which contains all vertices) instead of current_bo
952 * (which contains deduplicated vertices *when* UseLoopback is false).
953 *
954 * The problem is that the VAO offset is based on current_bo's layout,
955 * so we have to use a temp value.
956 */
957 struct gl_vertex_array_object *vao = node->VAO[VP_MODE_SHADER];
958 GLintptr original = vao->BufferBinding[0].Offset;
959 /* 'start_offset' has been added to all primitives 'start', so undo it here. */
960 vao->BufferBinding[0].Offset = -(GLintptr)(start_offset * stride);
961 _vbo_loopback_vertex_list(ctx, node, save->vertex_store->buffer_in_ram);
962 vao->BufferBinding[0].Offset = original;
963
964 _glapi_set_dispatch(dispatch);
965 }
966
967 /* Reset our structures for the next run of vertices:
968 */
969 reset_counters(ctx);
970 }
971
972
973 /**
974 * This is called when we fill a vertex buffer before we hit a glEnd().
975 * We
976 * TODO -- If no new vertices have been stored, don't bother saving it.
977 */
978 static void
wrap_buffers(struct gl_context * ctx)979 wrap_buffers(struct gl_context *ctx)
980 {
981 struct vbo_save_context *save = &vbo_context(ctx)->save;
982 GLint i = save->prim_store->used - 1;
983 GLenum mode;
984
985 assert(i < (GLint) save->prim_store->size);
986 assert(i >= 0);
987
988 /* Close off in-progress primitive.
989 */
990 save->prim_store->prims[i].count = (get_vertex_count(save) - save->prim_store->prims[i].start);
991 mode = save->prim_store->prims[i].mode;
992
993 /* store the copied vertices, and allocate a new list.
994 */
995 compile_vertex_list(ctx);
996
997 /* Restart interrupted primitive
998 */
999 save->prim_store->prims[0].mode = mode;
1000 save->prim_store->prims[0].begin = 0;
1001 save->prim_store->prims[0].end = 0;
1002 save->prim_store->prims[0].start = 0;
1003 save->prim_store->prims[0].count = 0;
1004 save->prim_store->used = 1;
1005 }
1006
1007
1008 /**
1009 * Called only when buffers are wrapped as the result of filling the
1010 * vertex_store struct.
1011 */
1012 static void
wrap_filled_vertex(struct gl_context * ctx)1013 wrap_filled_vertex(struct gl_context *ctx)
1014 {
1015 struct vbo_save_context *save = &vbo_context(ctx)->save;
1016 unsigned numComponents;
1017
1018 /* Emit a glEnd to close off the last vertex list.
1019 */
1020 wrap_buffers(ctx);
1021
1022 assert(save->vertex_store->used == 0 && save->vertex_store->used == 0);
1023
1024 /* Copy stored stored vertices to start of new list.
1025 */
1026 numComponents = save->copied.nr * save->vertex_size;
1027
1028 fi_type *buffer_ptr = save->vertex_store->buffer_in_ram;
1029 if (numComponents) {
1030 assert(save->copied.buffer);
1031 memcpy(buffer_ptr,
1032 save->copied.buffer,
1033 numComponents * sizeof(fi_type));
1034 free(save->copied.buffer);
1035 save->copied.buffer = NULL;
1036 }
1037 save->vertex_store->used = numComponents;
1038 }
1039
1040
1041 static void
copy_to_current(struct gl_context * ctx)1042 copy_to_current(struct gl_context *ctx)
1043 {
1044 struct vbo_save_context *save = &vbo_context(ctx)->save;
1045 GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
1046
1047 while (enabled) {
1048 const int i = u_bit_scan64(&enabled);
1049 assert(save->attrsz[i]);
1050
1051 if (save->attrtype[i] == GL_DOUBLE ||
1052 save->attrtype[i] == GL_UNSIGNED_INT64_ARB)
1053 memcpy(save->current[i], save->attrptr[i], save->attrsz[i] * sizeof(GLfloat));
1054 else
1055 COPY_CLEAN_4V_TYPE_AS_UNION(save->current[i], save->attrsz[i],
1056 save->attrptr[i], save->attrtype[i]);
1057 }
1058 }
1059
1060
1061 static void
copy_from_current(struct gl_context * ctx)1062 copy_from_current(struct gl_context *ctx)
1063 {
1064 struct vbo_save_context *save = &vbo_context(ctx)->save;
1065 GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
1066
1067 while (enabled) {
1068 const int i = u_bit_scan64(&enabled);
1069
1070 switch (save->attrsz[i]) {
1071 case 4:
1072 save->attrptr[i][3] = save->current[i][3];
1073 FALLTHROUGH;
1074 case 3:
1075 save->attrptr[i][2] = save->current[i][2];
1076 FALLTHROUGH;
1077 case 2:
1078 save->attrptr[i][1] = save->current[i][1];
1079 FALLTHROUGH;
1080 case 1:
1081 save->attrptr[i][0] = save->current[i][0];
1082 break;
1083 case 0:
1084 unreachable("Unexpected vertex attribute size");
1085 }
1086 }
1087 }
1088
1089
1090 /**
1091 * Called when we increase the size of a vertex attribute. For example,
1092 * if we've seen one or more glTexCoord2f() calls and now we get a
1093 * glTexCoord3f() call.
1094 * Flush existing data, set new attrib size, replay copied vertices.
1095 */
1096 static void
upgrade_vertex(struct gl_context * ctx,GLuint attr,GLuint newsz)1097 upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz)
1098 {
1099 struct vbo_save_context *save = &vbo_context(ctx)->save;
1100 GLuint oldsz;
1101 GLuint i;
1102 fi_type *tmp;
1103
1104 /* Store the current run of vertices, and emit a GL_END. Emit a
1105 * BEGIN in the new buffer.
1106 */
1107 if (save->vertex_store->used)
1108 wrap_buffers(ctx);
1109 else
1110 assert(save->copied.nr == 0);
1111
1112 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
1113 * when the attribute already exists in the vertex and is having
1114 * its size increased.
1115 */
1116 copy_to_current(ctx);
1117
1118 /* Fix up sizes:
1119 */
1120 oldsz = save->attrsz[attr];
1121 save->attrsz[attr] = newsz;
1122 save->enabled |= BITFIELD64_BIT(attr);
1123
1124 save->vertex_size += newsz - oldsz;
1125
1126 /* Recalculate all the attrptr[] values:
1127 */
1128 tmp = save->vertex;
1129 for (i = 0; i < VBO_ATTRIB_MAX; i++) {
1130 if (save->attrsz[i]) {
1131 save->attrptr[i] = tmp;
1132 tmp += save->attrsz[i];
1133 }
1134 else {
1135 save->attrptr[i] = NULL; /* will not be dereferenced. */
1136 }
1137 }
1138
1139 /* Copy from current to repopulate the vertex with correct values.
1140 */
1141 copy_from_current(ctx);
1142
1143 /* Replay stored vertices to translate them to new format here.
1144 *
1145 * If there are copied vertices and the new (upgraded) attribute
1146 * has not been defined before, this list is somewhat degenerate,
1147 * and will need fixup at runtime.
1148 */
1149 if (save->copied.nr) {
1150 assert(save->copied.buffer);
1151 const fi_type *data = save->copied.buffer;
1152 grow_vertex_storage(ctx, save->copied.nr);
1153 fi_type *dest = save->vertex_store->buffer_in_ram;
1154
1155 /* Need to note this and fix up at runtime (or loopback):
1156 */
1157 if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
1158 assert(oldsz == 0);
1159 save->dangling_attr_ref = GL_TRUE;
1160 }
1161
1162 for (i = 0; i < save->copied.nr; i++) {
1163 GLbitfield64 enabled = save->enabled;
1164 while (enabled) {
1165 const int j = u_bit_scan64(&enabled);
1166 assert(save->attrsz[j]);
1167 if (j == attr) {
1168 int k;
1169 const fi_type *src = oldsz ? data : save->current[attr];
1170 int copy = oldsz ? oldsz : newsz;
1171 for (k = 0; k < copy; k++)
1172 dest[k] = src[k];
1173 for (; k < newsz; k++) {
1174 switch (save->attrtype[j]) {
1175 case GL_FLOAT:
1176 dest[k] = FLOAT_AS_UNION(k == 3);
1177 break;
1178 case GL_INT:
1179 dest[k] = INT_AS_UNION(k == 3);
1180 break;
1181 case GL_UNSIGNED_INT:
1182 dest[k] = UINT_AS_UNION(k == 3);
1183 break;
1184 default:
1185 dest[k] = FLOAT_AS_UNION(k == 3);
1186 assert(!"Unexpected type in upgrade_vertex");
1187 break;
1188 }
1189 }
1190 dest += newsz;
1191 data += oldsz;
1192 } else {
1193 GLint sz = save->attrsz[j];
1194 for (int k = 0; k < sz; k++)
1195 dest[k] = data[k];
1196 data += sz;
1197 dest += sz;
1198 }
1199 }
1200 }
1201
1202 save->vertex_store->used += save->vertex_size * save->copied.nr;
1203 free(save->copied.buffer);
1204 save->copied.buffer = NULL;
1205 }
1206 }
1207
1208
1209 /**
1210 * This is called when the size of a vertex attribute changes.
1211 * For example, after seeing one or more glTexCoord2f() calls we
1212 * get a glTexCoord4f() or glTexCoord1f() call.
1213 */
1214 static void
fixup_vertex(struct gl_context * ctx,GLuint attr,GLuint sz,GLenum newType)1215 fixup_vertex(struct gl_context *ctx, GLuint attr,
1216 GLuint sz, GLenum newType)
1217 {
1218 struct vbo_save_context *save = &vbo_context(ctx)->save;
1219
1220 if (sz > save->attrsz[attr] ||
1221 newType != save->attrtype[attr]) {
1222 /* New size is larger. Need to flush existing vertices and get
1223 * an enlarged vertex format.
1224 */
1225 upgrade_vertex(ctx, attr, sz);
1226 }
1227 else if (sz < save->active_sz[attr]) {
1228 GLuint i;
1229 const fi_type *id = vbo_get_default_vals_as_union(save->attrtype[attr]);
1230
1231 /* New size is equal or smaller - just need to fill in some
1232 * zeros.
1233 */
1234 for (i = sz; i <= save->attrsz[attr]; i++)
1235 save->attrptr[attr][i - 1] = id[i - 1];
1236 }
1237
1238 save->active_sz[attr] = sz;
1239
1240 grow_vertex_storage(ctx, 1);
1241 }
1242
1243
1244 /**
1245 * Reset the current size of all vertex attributes to the default
1246 * value of 0. This signals that we haven't yet seen any per-vertex
1247 * commands such as glNormal3f() or glTexCoord2f().
1248 */
1249 static void
reset_vertex(struct gl_context * ctx)1250 reset_vertex(struct gl_context *ctx)
1251 {
1252 struct vbo_save_context *save = &vbo_context(ctx)->save;
1253
1254 while (save->enabled) {
1255 const int i = u_bit_scan64(&save->enabled);
1256 assert(save->attrsz[i]);
1257 save->attrsz[i] = 0;
1258 save->active_sz[i] = 0;
1259 }
1260
1261 save->vertex_size = 0;
1262 }
1263
1264
1265 /**
1266 * If index=0, does glVertexAttrib*() alias glVertex() to emit a vertex?
1267 * It depends on a few things, including whether we're inside or outside
1268 * of glBegin/glEnd.
1269 */
1270 static inline bool
is_vertex_position(const struct gl_context * ctx,GLuint index)1271 is_vertex_position(const struct gl_context *ctx, GLuint index)
1272 {
1273 return (index == 0 &&
1274 _mesa_attr_zero_aliases_vertex(ctx) &&
1275 _mesa_inside_dlist_begin_end(ctx));
1276 }
1277
1278
1279
1280 #define ERROR(err) _mesa_compile_error(ctx, err, __func__);
1281
1282
1283 /* Only one size for each attribute may be active at once. Eg. if
1284 * Color3f is installed/active, then Color4f may not be, even if the
1285 * vertex actually contains 4 color coordinates. This is because the
1286 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
1287 * of the chooser function when switching between Color4f and Color3f.
1288 */
1289 #define ATTR_UNION(A, N, T, C, V0, V1, V2, V3) \
1290 do { \
1291 struct vbo_save_context *save = &vbo_context(ctx)->save; \
1292 int sz = (sizeof(C) / sizeof(GLfloat)); \
1293 \
1294 if (save->active_sz[A] != N) \
1295 fixup_vertex(ctx, A, N * sz, T); \
1296 \
1297 { \
1298 C *dest = (C *)save->attrptr[A]; \
1299 if (N>0) dest[0] = V0; \
1300 if (N>1) dest[1] = V1; \
1301 if (N>2) dest[2] = V2; \
1302 if (N>3) dest[3] = V3; \
1303 save->attrtype[A] = T; \
1304 } \
1305 \
1306 if ((A) == VBO_ATTRIB_POS) { \
1307 fi_type *buffer_ptr = save->vertex_store->buffer_in_ram + \
1308 save->vertex_store->used; \
1309 \
1310 for (int i = 0; i < save->vertex_size; i++) \
1311 buffer_ptr[i] = save->vertex[i]; \
1312 \
1313 save->vertex_store->used += save->vertex_size; \
1314 unsigned used_next = (save->vertex_store->used + \
1315 save->vertex_size) * sizeof(float); \
1316 if (used_next > save->vertex_store->buffer_in_ram_size) { \
1317 grow_vertex_storage(ctx, get_vertex_count(save)); \
1318 assert(used_next <= \
1319 save->vertex_store->buffer_in_ram_size); \
1320 } \
1321 } \
1322 } while (0)
1323
1324 #define TAG(x) _save_##x
1325
1326 #include "vbo_attrib_tmp.h"
1327
1328
1329 #define MAT( ATTR, N, face, params ) \
1330 do { \
1331 if (face != GL_BACK) \
1332 MAT_ATTR( ATTR, N, params ); /* front */ \
1333 if (face != GL_FRONT) \
1334 MAT_ATTR( ATTR + 1, N, params ); /* back */ \
1335 } while (0)
1336
1337
1338 /**
1339 * Save a glMaterial call found between glBegin/End.
1340 * glMaterial calls outside Begin/End are handled in dlist.c.
1341 */
1342 static void GLAPIENTRY
_save_Materialfv(GLenum face,GLenum pname,const GLfloat * params)1343 _save_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
1344 {
1345 GET_CURRENT_CONTEXT(ctx);
1346
1347 if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
1348 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(face)");
1349 return;
1350 }
1351
1352 switch (pname) {
1353 case GL_EMISSION:
1354 MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params);
1355 break;
1356 case GL_AMBIENT:
1357 MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
1358 break;
1359 case GL_DIFFUSE:
1360 MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
1361 break;
1362 case GL_SPECULAR:
1363 MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params);
1364 break;
1365 case GL_SHININESS:
1366 if (*params < 0 || *params > ctx->Const.MaxShininess) {
1367 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glMaterial(shininess)");
1368 }
1369 else {
1370 MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params);
1371 }
1372 break;
1373 case GL_COLOR_INDEXES:
1374 MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params);
1375 break;
1376 case GL_AMBIENT_AND_DIFFUSE:
1377 MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
1378 MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
1379 break;
1380 default:
1381 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(pname)");
1382 return;
1383 }
1384 }
1385
1386
1387 /* Cope with EvalCoord/CallList called within a begin/end object:
1388 * -- Flush current buffer
1389 * -- Fallback to opcodes for the rest of the begin/end object.
1390 */
1391 static void
dlist_fallback(struct gl_context * ctx)1392 dlist_fallback(struct gl_context *ctx)
1393 {
1394 struct vbo_save_context *save = &vbo_context(ctx)->save;
1395
1396 if (save->vertex_store->used || save->prim_store->used) {
1397 if (save->prim_store->used > 0 && save->vertex_store->used > 0) {
1398 assert(save->vertex_size);
1399 /* Close off in-progress primitive. */
1400 GLint i = save->prim_store->used - 1;
1401 save->prim_store->prims[i].count =
1402 get_vertex_count(save) -
1403 save->prim_store->prims[i].start;
1404 }
1405
1406 /* Need to replay this display list with loopback,
1407 * unfortunately, otherwise this primitive won't be handled
1408 * properly:
1409 */
1410 save->dangling_attr_ref = GL_TRUE;
1411
1412 compile_vertex_list(ctx);
1413 }
1414
1415 copy_to_current(ctx);
1416 reset_vertex(ctx);
1417 if (save->out_of_memory) {
1418 _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
1419 }
1420 else {
1421 _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1422 }
1423 ctx->Driver.SaveNeedFlush = GL_FALSE;
1424 }
1425
1426
1427 static void GLAPIENTRY
_save_EvalCoord1f(GLfloat u)1428 _save_EvalCoord1f(GLfloat u)
1429 {
1430 GET_CURRENT_CONTEXT(ctx);
1431 dlist_fallback(ctx);
1432 CALL_EvalCoord1f(ctx->Save, (u));
1433 }
1434
1435 static void GLAPIENTRY
_save_EvalCoord1fv(const GLfloat * v)1436 _save_EvalCoord1fv(const GLfloat * v)
1437 {
1438 GET_CURRENT_CONTEXT(ctx);
1439 dlist_fallback(ctx);
1440 CALL_EvalCoord1fv(ctx->Save, (v));
1441 }
1442
1443 static void GLAPIENTRY
_save_EvalCoord2f(GLfloat u,GLfloat v)1444 _save_EvalCoord2f(GLfloat u, GLfloat v)
1445 {
1446 GET_CURRENT_CONTEXT(ctx);
1447 dlist_fallback(ctx);
1448 CALL_EvalCoord2f(ctx->Save, (u, v));
1449 }
1450
1451 static void GLAPIENTRY
_save_EvalCoord2fv(const GLfloat * v)1452 _save_EvalCoord2fv(const GLfloat * v)
1453 {
1454 GET_CURRENT_CONTEXT(ctx);
1455 dlist_fallback(ctx);
1456 CALL_EvalCoord2fv(ctx->Save, (v));
1457 }
1458
1459 static void GLAPIENTRY
_save_EvalPoint1(GLint i)1460 _save_EvalPoint1(GLint i)
1461 {
1462 GET_CURRENT_CONTEXT(ctx);
1463 dlist_fallback(ctx);
1464 CALL_EvalPoint1(ctx->Save, (i));
1465 }
1466
1467 static void GLAPIENTRY
_save_EvalPoint2(GLint i,GLint j)1468 _save_EvalPoint2(GLint i, GLint j)
1469 {
1470 GET_CURRENT_CONTEXT(ctx);
1471 dlist_fallback(ctx);
1472 CALL_EvalPoint2(ctx->Save, (i, j));
1473 }
1474
1475 static void GLAPIENTRY
_save_CallList(GLuint l)1476 _save_CallList(GLuint l)
1477 {
1478 GET_CURRENT_CONTEXT(ctx);
1479 dlist_fallback(ctx);
1480 CALL_CallList(ctx->Save, (l));
1481 }
1482
1483 static void GLAPIENTRY
_save_CallLists(GLsizei n,GLenum type,const GLvoid * v)1484 _save_CallLists(GLsizei n, GLenum type, const GLvoid * v)
1485 {
1486 GET_CURRENT_CONTEXT(ctx);
1487 dlist_fallback(ctx);
1488 CALL_CallLists(ctx->Save, (n, type, v));
1489 }
1490
1491
1492
1493 /**
1494 * Called when a glBegin is getting compiled into a display list.
1495 * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
1496 */
1497 void
vbo_save_NotifyBegin(struct gl_context * ctx,GLenum mode,bool no_current_update)1498 vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode,
1499 bool no_current_update)
1500 {
1501 struct vbo_save_context *save = &vbo_context(ctx)->save;
1502 const GLuint i = save->prim_store->used++;
1503
1504 ctx->Driver.CurrentSavePrimitive = mode;
1505
1506 if (!save->prim_store || i >= save->prim_store->size) {
1507 save->prim_store = realloc_prim_store(save->prim_store, i * 2);
1508 }
1509 save->prim_store->prims[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK;
1510 save->prim_store->prims[i].begin = 1;
1511 save->prim_store->prims[i].end = 0;
1512 save->prim_store->prims[i].start = get_vertex_count(save);
1513 save->prim_store->prims[i].count = 0;
1514
1515 save->no_current_update = no_current_update;
1516
1517 _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
1518
1519 /* We need to call vbo_save_SaveFlushVertices() if there's state change */
1520 ctx->Driver.SaveNeedFlush = GL_TRUE;
1521 }
1522
1523
1524 static void GLAPIENTRY
_save_End(void)1525 _save_End(void)
1526 {
1527 GET_CURRENT_CONTEXT(ctx);
1528 struct vbo_save_context *save = &vbo_context(ctx)->save;
1529 const GLint i = save->prim_store->used - 1;
1530
1531 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1532 save->prim_store->prims[i].end = 1;
1533 save->prim_store->prims[i].count = (get_vertex_count(save) - save->prim_store->prims[i].start);
1534
1535 /* Swap out this vertex format while outside begin/end. Any color,
1536 * etc. received between here and the next begin will be compiled
1537 * as opcodes.
1538 */
1539 if (save->out_of_memory) {
1540 _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
1541 }
1542 else {
1543 _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1544 }
1545 }
1546
1547
1548 static void GLAPIENTRY
_save_Begin(GLenum mode)1549 _save_Begin(GLenum mode)
1550 {
1551 GET_CURRENT_CONTEXT(ctx);
1552 (void) mode;
1553 _mesa_compile_error(ctx, GL_INVALID_OPERATION, "Recursive glBegin");
1554 }
1555
1556
1557 static void GLAPIENTRY
_save_PrimitiveRestartNV(void)1558 _save_PrimitiveRestartNV(void)
1559 {
1560 GET_CURRENT_CONTEXT(ctx);
1561 struct vbo_save_context *save = &vbo_context(ctx)->save;
1562
1563 if (save->prim_store->used == 0) {
1564 /* We're not inside a glBegin/End pair, so calling glPrimitiverRestartNV
1565 * is an error.
1566 */
1567 _mesa_compile_error(ctx, GL_INVALID_OPERATION,
1568 "glPrimitiveRestartNV called outside glBegin/End");
1569 } else {
1570 /* get current primitive mode */
1571 GLenum curPrim = save->prim_store->prims[save->prim_store->used - 1].mode;
1572 bool no_current_update = save->no_current_update;
1573
1574 /* restart primitive */
1575 CALL_End(ctx->CurrentServerDispatch, ());
1576 vbo_save_NotifyBegin(ctx, curPrim, no_current_update);
1577 }
1578 }
1579
1580
1581 /* Unlike the functions above, these are to be hooked into the vtxfmt
1582 * maintained in ctx->ListState, active when the list is known or
1583 * suspected to be outside any begin/end primitive.
1584 * Note: OBE = Outside Begin/End
1585 */
1586 static void GLAPIENTRY
_save_OBE_Rectf(GLfloat x1,GLfloat y1,GLfloat x2,GLfloat y2)1587 _save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
1588 {
1589 GET_CURRENT_CONTEXT(ctx);
1590 struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1591
1592 vbo_save_NotifyBegin(ctx, GL_QUADS, false);
1593 CALL_Vertex2f(dispatch, (x1, y1));
1594 CALL_Vertex2f(dispatch, (x2, y1));
1595 CALL_Vertex2f(dispatch, (x2, y2));
1596 CALL_Vertex2f(dispatch, (x1, y2));
1597 CALL_End(dispatch, ());
1598 }
1599
1600
1601 static void GLAPIENTRY
_save_OBE_Rectd(GLdouble x1,GLdouble y1,GLdouble x2,GLdouble y2)1602 _save_OBE_Rectd(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2)
1603 {
1604 _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1605 }
1606
1607 static void GLAPIENTRY
_save_OBE_Rectdv(const GLdouble * v1,const GLdouble * v2)1608 _save_OBE_Rectdv(const GLdouble *v1, const GLdouble *v2)
1609 {
1610 _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1611 }
1612
1613 static void GLAPIENTRY
_save_OBE_Rectfv(const GLfloat * v1,const GLfloat * v2)1614 _save_OBE_Rectfv(const GLfloat *v1, const GLfloat *v2)
1615 {
1616 _save_OBE_Rectf(v1[0], v1[1], v2[0], v2[1]);
1617 }
1618
1619 static void GLAPIENTRY
_save_OBE_Recti(GLint x1,GLint y1,GLint x2,GLint y2)1620 _save_OBE_Recti(GLint x1, GLint y1, GLint x2, GLint y2)
1621 {
1622 _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1623 }
1624
1625 static void GLAPIENTRY
_save_OBE_Rectiv(const GLint * v1,const GLint * v2)1626 _save_OBE_Rectiv(const GLint *v1, const GLint *v2)
1627 {
1628 _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1629 }
1630
1631 static void GLAPIENTRY
_save_OBE_Rects(GLshort x1,GLshort y1,GLshort x2,GLshort y2)1632 _save_OBE_Rects(GLshort x1, GLshort y1, GLshort x2, GLshort y2)
1633 {
1634 _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1635 }
1636
1637 static void GLAPIENTRY
_save_OBE_Rectsv(const GLshort * v1,const GLshort * v2)1638 _save_OBE_Rectsv(const GLshort *v1, const GLshort *v2)
1639 {
1640 _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1641 }
1642
1643 static void GLAPIENTRY
_save_OBE_DrawArrays(GLenum mode,GLint start,GLsizei count)1644 _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
1645 {
1646 GET_CURRENT_CONTEXT(ctx);
1647 struct gl_vertex_array_object *vao = ctx->Array.VAO;
1648 struct vbo_save_context *save = &vbo_context(ctx)->save;
1649 GLint i;
1650
1651 if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1652 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)");
1653 return;
1654 }
1655 if (count < 0) {
1656 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count<0)");
1657 return;
1658 }
1659
1660 if (save->out_of_memory)
1661 return;
1662
1663 grow_vertex_storage(ctx, count);
1664
1665 /* Make sure to process any VBO binding changes */
1666 _mesa_update_state(ctx);
1667
1668 _mesa_vao_map_arrays(ctx, vao, GL_MAP_READ_BIT);
1669
1670 vbo_save_NotifyBegin(ctx, mode, true);
1671
1672 for (i = 0; i < count; i++)
1673 _mesa_array_element(ctx, start + i);
1674 CALL_End(ctx->CurrentServerDispatch, ());
1675
1676 _mesa_vao_unmap_arrays(ctx, vao);
1677 }
1678
1679
1680 static void GLAPIENTRY
_save_OBE_MultiDrawArrays(GLenum mode,const GLint * first,const GLsizei * count,GLsizei primcount)1681 _save_OBE_MultiDrawArrays(GLenum mode, const GLint *first,
1682 const GLsizei *count, GLsizei primcount)
1683 {
1684 GET_CURRENT_CONTEXT(ctx);
1685 GLint i;
1686
1687 if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1688 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMultiDrawArrays(mode)");
1689 return;
1690 }
1691
1692 if (primcount < 0) {
1693 _mesa_compile_error(ctx, GL_INVALID_VALUE,
1694 "glMultiDrawArrays(primcount<0)");
1695 return;
1696 }
1697
1698 unsigned vertcount = 0;
1699 for (i = 0; i < primcount; i++) {
1700 if (count[i] < 0) {
1701 _mesa_compile_error(ctx, GL_INVALID_VALUE,
1702 "glMultiDrawArrays(count[i]<0)");
1703 return;
1704 }
1705 vertcount += count[i];
1706 }
1707
1708 grow_vertex_storage(ctx, vertcount);
1709
1710 for (i = 0; i < primcount; i++) {
1711 if (count[i] > 0) {
1712 _save_OBE_DrawArrays(mode, first[i], count[i]);
1713 }
1714 }
1715 }
1716
1717
1718 static void
array_element(struct gl_context * ctx,GLint basevertex,GLuint elt,unsigned index_size_shift)1719 array_element(struct gl_context *ctx,
1720 GLint basevertex, GLuint elt, unsigned index_size_shift)
1721 {
1722 /* Section 10.3.5 Primitive Restart:
1723 * [...]
1724 * When one of the *BaseVertex drawing commands specified in section 10.5
1725 * is used, the primitive restart comparison occurs before the basevertex
1726 * offset is added to the array index.
1727 */
1728 /* If PrimitiveRestart is enabled and the index is the RestartIndex
1729 * then we call PrimitiveRestartNV and return.
1730 */
1731 if (ctx->Array._PrimitiveRestart[index_size_shift] &&
1732 elt == ctx->Array._RestartIndex[index_size_shift]) {
1733 CALL_PrimitiveRestartNV(ctx->CurrentServerDispatch, ());
1734 return;
1735 }
1736
1737 _mesa_array_element(ctx, basevertex + elt);
1738 }
1739
1740
1741 /* Could do better by copying the arrays and element list intact and
1742 * then emitting an indexed prim at runtime.
1743 */
1744 static void GLAPIENTRY
_save_OBE_DrawElementsBaseVertex(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices,GLint basevertex)1745 _save_OBE_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
1746 const GLvoid * indices, GLint basevertex)
1747 {
1748 GET_CURRENT_CONTEXT(ctx);
1749 struct vbo_save_context *save = &vbo_context(ctx)->save;
1750 struct gl_vertex_array_object *vao = ctx->Array.VAO;
1751 struct gl_buffer_object *indexbuf = vao->IndexBufferObj;
1752 GLint i;
1753
1754 if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1755 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)");
1756 return;
1757 }
1758 if (count < 0) {
1759 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1760 return;
1761 }
1762 if (type != GL_UNSIGNED_BYTE &&
1763 type != GL_UNSIGNED_SHORT &&
1764 type != GL_UNSIGNED_INT) {
1765 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1766 return;
1767 }
1768
1769 if (save->out_of_memory)
1770 return;
1771
1772 grow_vertex_storage(ctx, count);
1773
1774 /* Make sure to process any VBO binding changes */
1775 _mesa_update_state(ctx);
1776
1777 _mesa_vao_map(ctx, vao, GL_MAP_READ_BIT);
1778
1779 if (indexbuf)
1780 indices =
1781 ADD_POINTERS(indexbuf->Mappings[MAP_INTERNAL].Pointer, indices);
1782
1783 vbo_save_NotifyBegin(ctx, mode, true);
1784
1785 switch (type) {
1786 case GL_UNSIGNED_BYTE:
1787 for (i = 0; i < count; i++)
1788 array_element(ctx, basevertex, ((GLubyte *) indices)[i], 0);
1789 break;
1790 case GL_UNSIGNED_SHORT:
1791 for (i = 0; i < count; i++)
1792 array_element(ctx, basevertex, ((GLushort *) indices)[i], 1);
1793 break;
1794 case GL_UNSIGNED_INT:
1795 for (i = 0; i < count; i++)
1796 array_element(ctx, basevertex, ((GLuint *) indices)[i], 2);
1797 break;
1798 default:
1799 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)");
1800 break;
1801 }
1802
1803 CALL_End(ctx->CurrentServerDispatch, ());
1804
1805 _mesa_vao_unmap(ctx, vao);
1806 }
1807
1808 static void GLAPIENTRY
_save_OBE_DrawElements(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices)1809 _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
1810 const GLvoid * indices)
1811 {
1812 _save_OBE_DrawElementsBaseVertex(mode, count, type, indices, 0);
1813 }
1814
1815
1816 static void GLAPIENTRY
_save_OBE_DrawRangeElements(GLenum mode,GLuint start,GLuint end,GLsizei count,GLenum type,const GLvoid * indices)1817 _save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
1818 GLsizei count, GLenum type,
1819 const GLvoid * indices)
1820 {
1821 GET_CURRENT_CONTEXT(ctx);
1822 struct vbo_save_context *save = &vbo_context(ctx)->save;
1823
1824 if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1825 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)");
1826 return;
1827 }
1828 if (count < 0) {
1829 _mesa_compile_error(ctx, GL_INVALID_VALUE,
1830 "glDrawRangeElements(count<0)");
1831 return;
1832 }
1833 if (type != GL_UNSIGNED_BYTE &&
1834 type != GL_UNSIGNED_SHORT &&
1835 type != GL_UNSIGNED_INT) {
1836 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)");
1837 return;
1838 }
1839 if (end < start) {
1840 _mesa_compile_error(ctx, GL_INVALID_VALUE,
1841 "glDrawRangeElements(end < start)");
1842 return;
1843 }
1844
1845 if (save->out_of_memory)
1846 return;
1847
1848 _save_OBE_DrawElements(mode, count, type, indices);
1849 }
1850
1851
1852 static void GLAPIENTRY
_save_OBE_MultiDrawElements(GLenum mode,const GLsizei * count,GLenum type,const GLvoid * const * indices,GLsizei primcount)1853 _save_OBE_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type,
1854 const GLvoid * const *indices, GLsizei primcount)
1855 {
1856 GET_CURRENT_CONTEXT(ctx);
1857 struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1858 GLsizei i;
1859
1860 int vertcount = 0;
1861 for (i = 0; i < primcount; i++) {
1862 vertcount += count[i];
1863 }
1864 grow_vertex_storage(ctx, vertcount);
1865
1866 for (i = 0; i < primcount; i++) {
1867 if (count[i] > 0) {
1868 CALL_DrawElements(dispatch, (mode, count[i], type, indices[i]));
1869 }
1870 }
1871 }
1872
1873
1874 static void GLAPIENTRY
_save_OBE_MultiDrawElementsBaseVertex(GLenum mode,const GLsizei * count,GLenum type,const GLvoid * const * indices,GLsizei primcount,const GLint * basevertex)1875 _save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
1876 GLenum type,
1877 const GLvoid * const *indices,
1878 GLsizei primcount,
1879 const GLint *basevertex)
1880 {
1881 GET_CURRENT_CONTEXT(ctx);
1882 struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1883 GLsizei i;
1884
1885 int vertcount = 0;
1886 for (i = 0; i < primcount; i++) {
1887 vertcount += count[i];
1888 }
1889 grow_vertex_storage(ctx, vertcount);
1890
1891 for (i = 0; i < primcount; i++) {
1892 if (count[i] > 0) {
1893 CALL_DrawElementsBaseVertex(dispatch, (mode, count[i], type,
1894 indices[i],
1895 basevertex[i]));
1896 }
1897 }
1898 }
1899
1900
1901 static void
vtxfmt_init(struct gl_context * ctx)1902 vtxfmt_init(struct gl_context *ctx)
1903 {
1904 struct vbo_save_context *save = &vbo_context(ctx)->save;
1905 GLvertexformat *vfmt = &save->vtxfmt;
1906
1907 #define NAME_AE(x) _ae_##x
1908 #define NAME_CALLLIST(x) _save_##x
1909 #define NAME(x) _save_##x
1910 #define NAME_ES(x) _save_##x##ARB
1911
1912 #include "vbo_init_tmp.h"
1913 }
1914
1915
1916 /**
1917 * Initialize the dispatch table with the VBO functions for display
1918 * list compilation.
1919 */
1920 void
vbo_initialize_save_dispatch(const struct gl_context * ctx,struct _glapi_table * exec)1921 vbo_initialize_save_dispatch(const struct gl_context *ctx,
1922 struct _glapi_table *exec)
1923 {
1924 SET_DrawArrays(exec, _save_OBE_DrawArrays);
1925 SET_MultiDrawArrays(exec, _save_OBE_MultiDrawArrays);
1926 SET_DrawElements(exec, _save_OBE_DrawElements);
1927 SET_DrawElementsBaseVertex(exec, _save_OBE_DrawElementsBaseVertex);
1928 SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements);
1929 SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements);
1930 SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex);
1931 SET_Rectf(exec, _save_OBE_Rectf);
1932 SET_Rectd(exec, _save_OBE_Rectd);
1933 SET_Rectdv(exec, _save_OBE_Rectdv);
1934 SET_Rectfv(exec, _save_OBE_Rectfv);
1935 SET_Recti(exec, _save_OBE_Recti);
1936 SET_Rectiv(exec, _save_OBE_Rectiv);
1937 SET_Rects(exec, _save_OBE_Rects);
1938 SET_Rectsv(exec, _save_OBE_Rectsv);
1939
1940 /* Note: other glDraw functins aren't compiled into display lists */
1941 }
1942
1943
1944
1945 void
vbo_save_SaveFlushVertices(struct gl_context * ctx)1946 vbo_save_SaveFlushVertices(struct gl_context *ctx)
1947 {
1948 struct vbo_save_context *save = &vbo_context(ctx)->save;
1949
1950 /* Noop when we are actually active:
1951 */
1952 if (ctx->Driver.CurrentSavePrimitive <= PRIM_MAX)
1953 return;
1954
1955 if (save->vertex_store->used || save->prim_store->used)
1956 compile_vertex_list(ctx);
1957
1958 copy_to_current(ctx);
1959 reset_vertex(ctx);
1960 ctx->Driver.SaveNeedFlush = GL_FALSE;
1961 }
1962
1963
1964 /**
1965 * Called from glNewList when we're starting to compile a display list.
1966 */
1967 void
vbo_save_NewList(struct gl_context * ctx,GLuint list,GLenum mode)1968 vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode)
1969 {
1970 struct vbo_save_context *save = &vbo_context(ctx)->save;
1971
1972 (void) list;
1973 (void) mode;
1974
1975 if (!save->prim_store)
1976 save->prim_store = realloc_prim_store(NULL, 8);
1977
1978 if (!save->vertex_store)
1979 save->vertex_store = CALLOC_STRUCT(vbo_save_vertex_store);
1980
1981 reset_vertex(ctx);
1982 ctx->Driver.SaveNeedFlush = GL_FALSE;
1983 }
1984
1985
1986 /**
1987 * Called from glEndList when we're finished compiling a display list.
1988 */
1989 void
vbo_save_EndList(struct gl_context * ctx)1990 vbo_save_EndList(struct gl_context *ctx)
1991 {
1992 struct vbo_save_context *save = &vbo_context(ctx)->save;
1993
1994 /* EndList called inside a (saved) Begin/End pair?
1995 */
1996 if (_mesa_inside_dlist_begin_end(ctx)) {
1997 if (save->prim_store->used > 0) {
1998 GLint i = save->prim_store->used - 1;
1999 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
2000 save->prim_store->prims[i].end = 0;
2001 save->prim_store->prims[i].count = get_vertex_count(save) - save->prim_store->prims[i].start;
2002 }
2003
2004 /* Make sure this vertex list gets replayed by the "loopback"
2005 * mechanism:
2006 */
2007 save->dangling_attr_ref = GL_TRUE;
2008 vbo_save_SaveFlushVertices(ctx);
2009
2010 /* Swap out this vertex format while outside begin/end. Any color,
2011 * etc. received between here and the next begin will be compiled
2012 * as opcodes.
2013 */
2014 _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
2015 }
2016
2017 assert(save->vertex_size == 0);
2018 }
2019
2020 /**
2021 * Called during context creation/init.
2022 */
2023 static void
current_init(struct gl_context * ctx)2024 current_init(struct gl_context *ctx)
2025 {
2026 struct vbo_save_context *save = &vbo_context(ctx)->save;
2027 GLint i;
2028
2029 for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_EDGEFLAG; i++) {
2030 const GLuint j = i - VBO_ATTRIB_POS;
2031 assert(j < VERT_ATTRIB_MAX);
2032 save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
2033 save->current[i] = (fi_type *) ctx->ListState.CurrentAttrib[j];
2034 }
2035
2036 for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
2037 const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
2038 assert(j < MAT_ATTRIB_MAX);
2039 save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
2040 save->current[i] = (fi_type *) ctx->ListState.CurrentMaterial[j];
2041 }
2042 }
2043
2044
2045 /**
2046 * Initialize the display list compiler. Called during context creation.
2047 */
2048 void
vbo_save_api_init(struct vbo_save_context * save)2049 vbo_save_api_init(struct vbo_save_context *save)
2050 {
2051 struct gl_context *ctx = gl_context_from_vbo_save(save);
2052
2053 vtxfmt_init(ctx);
2054 current_init(ctx);
2055 }
2056