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