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