1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2020 Advanced Micro Devices, Inc. 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21bf215546Sopenharmony_ci * IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci/* This implements vertex array state tracking for glthread. It's separate 25bf215546Sopenharmony_ci * from the rest of Mesa. Only minimum functionality is implemented here 26bf215546Sopenharmony_ci * to serve glthread. 27bf215546Sopenharmony_ci */ 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci#include "main/glthread.h" 30bf215546Sopenharmony_ci#include "main/glformats.h" 31bf215546Sopenharmony_ci#include "main/mtypes.h" 32bf215546Sopenharmony_ci#include "main/hash.h" 33bf215546Sopenharmony_ci#include "main/dispatch.h" 34bf215546Sopenharmony_ci#include "main/varray.h" 35bf215546Sopenharmony_ci 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_civoid 38bf215546Sopenharmony_ci_mesa_glthread_reset_vao(struct glthread_vao *vao) 39bf215546Sopenharmony_ci{ 40bf215546Sopenharmony_ci static unsigned default_elem_size[VERT_ATTRIB_MAX] = { 41bf215546Sopenharmony_ci [VERT_ATTRIB_NORMAL] = 12, 42bf215546Sopenharmony_ci [VERT_ATTRIB_COLOR1] = 12, 43bf215546Sopenharmony_ci [VERT_ATTRIB_FOG] = 4, 44bf215546Sopenharmony_ci [VERT_ATTRIB_COLOR_INDEX] = 4, 45bf215546Sopenharmony_ci [VERT_ATTRIB_EDGEFLAG] = 1, 46bf215546Sopenharmony_ci [VERT_ATTRIB_POINT_SIZE] = 4, 47bf215546Sopenharmony_ci }; 48bf215546Sopenharmony_ci 49bf215546Sopenharmony_ci vao->CurrentElementBufferName = 0; 50bf215546Sopenharmony_ci vao->UserEnabled = 0; 51bf215546Sopenharmony_ci vao->Enabled = 0; 52bf215546Sopenharmony_ci vao->BufferEnabled = 0; 53bf215546Sopenharmony_ci vao->UserPointerMask = 0; 54bf215546Sopenharmony_ci vao->NonZeroDivisorMask = 0; 55bf215546Sopenharmony_ci 56bf215546Sopenharmony_ci for (unsigned i = 0; i < ARRAY_SIZE(vao->Attrib); i++) { 57bf215546Sopenharmony_ci unsigned elem_size = default_elem_size[i]; 58bf215546Sopenharmony_ci if (!elem_size) 59bf215546Sopenharmony_ci elem_size = 16; 60bf215546Sopenharmony_ci 61bf215546Sopenharmony_ci vao->Attrib[i].ElementSize = elem_size; 62bf215546Sopenharmony_ci vao->Attrib[i].RelativeOffset = 0; 63bf215546Sopenharmony_ci vao->Attrib[i].BufferIndex = i; 64bf215546Sopenharmony_ci vao->Attrib[i].Stride = elem_size; 65bf215546Sopenharmony_ci vao->Attrib[i].Divisor = 0; 66bf215546Sopenharmony_ci vao->Attrib[i].EnabledAttribCount = 0; 67bf215546Sopenharmony_ci vao->Attrib[i].Pointer = NULL; 68bf215546Sopenharmony_ci } 69bf215546Sopenharmony_ci} 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_cistatic struct glthread_vao * 72bf215546Sopenharmony_cilookup_vao(struct gl_context *ctx, GLuint id) 73bf215546Sopenharmony_ci{ 74bf215546Sopenharmony_ci struct glthread_state *glthread = &ctx->GLThread; 75bf215546Sopenharmony_ci struct glthread_vao *vao; 76bf215546Sopenharmony_ci 77bf215546Sopenharmony_ci assert(id != 0); 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_ci if (glthread->LastLookedUpVAO && 80bf215546Sopenharmony_ci glthread->LastLookedUpVAO->Name == id) { 81bf215546Sopenharmony_ci vao = glthread->LastLookedUpVAO; 82bf215546Sopenharmony_ci } else { 83bf215546Sopenharmony_ci vao = _mesa_HashLookupLocked(glthread->VAOs, id); 84bf215546Sopenharmony_ci if (!vao) 85bf215546Sopenharmony_ci return NULL; 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_ci glthread->LastLookedUpVAO = vao; 88bf215546Sopenharmony_ci } 89bf215546Sopenharmony_ci 90bf215546Sopenharmony_ci return vao; 91bf215546Sopenharmony_ci} 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_civoid 94bf215546Sopenharmony_ci_mesa_glthread_BindVertexArray(struct gl_context *ctx, GLuint id) 95bf215546Sopenharmony_ci{ 96bf215546Sopenharmony_ci struct glthread_state *glthread = &ctx->GLThread; 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_ci if (id == 0) { 99bf215546Sopenharmony_ci glthread->CurrentVAO = &glthread->DefaultVAO; 100bf215546Sopenharmony_ci } else { 101bf215546Sopenharmony_ci struct glthread_vao *vao = lookup_vao(ctx, id); 102bf215546Sopenharmony_ci 103bf215546Sopenharmony_ci if (vao) 104bf215546Sopenharmony_ci glthread->CurrentVAO = vao; 105bf215546Sopenharmony_ci } 106bf215546Sopenharmony_ci} 107bf215546Sopenharmony_ci 108bf215546Sopenharmony_civoid 109bf215546Sopenharmony_ci_mesa_glthread_DeleteVertexArrays(struct gl_context *ctx, 110bf215546Sopenharmony_ci GLsizei n, const GLuint *ids) 111bf215546Sopenharmony_ci{ 112bf215546Sopenharmony_ci struct glthread_state *glthread = &ctx->GLThread; 113bf215546Sopenharmony_ci 114bf215546Sopenharmony_ci if (!ids) 115bf215546Sopenharmony_ci return; 116bf215546Sopenharmony_ci 117bf215546Sopenharmony_ci for (int i = 0; i < n; i++) { 118bf215546Sopenharmony_ci /* IDs equal to 0 should be silently ignored. */ 119bf215546Sopenharmony_ci if (!ids[i]) 120bf215546Sopenharmony_ci continue; 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_ci struct glthread_vao *vao = lookup_vao(ctx, ids[i]); 123bf215546Sopenharmony_ci if (!vao) 124bf215546Sopenharmony_ci continue; 125bf215546Sopenharmony_ci 126bf215546Sopenharmony_ci /* If the array object is currently bound, the spec says "the binding 127bf215546Sopenharmony_ci * for that object reverts to zero and the default vertex array 128bf215546Sopenharmony_ci * becomes current." 129bf215546Sopenharmony_ci */ 130bf215546Sopenharmony_ci if (glthread->CurrentVAO == vao) 131bf215546Sopenharmony_ci glthread->CurrentVAO = &glthread->DefaultVAO; 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_ci if (glthread->LastLookedUpVAO == vao) 134bf215546Sopenharmony_ci glthread->LastLookedUpVAO = NULL; 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_ci /* The ID is immediately freed for re-use */ 137bf215546Sopenharmony_ci _mesa_HashRemoveLocked(glthread->VAOs, vao->Name); 138bf215546Sopenharmony_ci free(vao); 139bf215546Sopenharmony_ci } 140bf215546Sopenharmony_ci} 141bf215546Sopenharmony_ci 142bf215546Sopenharmony_civoid 143bf215546Sopenharmony_ci_mesa_glthread_GenVertexArrays(struct gl_context *ctx, 144bf215546Sopenharmony_ci GLsizei n, GLuint *arrays) 145bf215546Sopenharmony_ci{ 146bf215546Sopenharmony_ci struct glthread_state *glthread = &ctx->GLThread; 147bf215546Sopenharmony_ci 148bf215546Sopenharmony_ci if (!arrays) 149bf215546Sopenharmony_ci return; 150bf215546Sopenharmony_ci 151bf215546Sopenharmony_ci /* The IDs have been generated at this point. Create VAOs for glthread. */ 152bf215546Sopenharmony_ci for (int i = 0; i < n; i++) { 153bf215546Sopenharmony_ci GLuint id = arrays[i]; 154bf215546Sopenharmony_ci struct glthread_vao *vao; 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci vao = calloc(1, sizeof(*vao)); 157bf215546Sopenharmony_ci if (!vao) 158bf215546Sopenharmony_ci continue; /* Is that all we can do? */ 159bf215546Sopenharmony_ci 160bf215546Sopenharmony_ci vao->Name = id; 161bf215546Sopenharmony_ci _mesa_glthread_reset_vao(vao); 162bf215546Sopenharmony_ci _mesa_HashInsertLocked(glthread->VAOs, id, vao, true); 163bf215546Sopenharmony_ci } 164bf215546Sopenharmony_ci} 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_ci/* If vaobj is NULL, use the currently-bound VAO. */ 167bf215546Sopenharmony_cistatic inline struct glthread_vao * 168bf215546Sopenharmony_ciget_vao(struct gl_context *ctx, const GLuint *vaobj) 169bf215546Sopenharmony_ci{ 170bf215546Sopenharmony_ci if (vaobj) 171bf215546Sopenharmony_ci return lookup_vao(ctx, *vaobj); 172bf215546Sopenharmony_ci 173bf215546Sopenharmony_ci return ctx->GLThread.CurrentVAO; 174bf215546Sopenharmony_ci} 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_cistatic void 177bf215546Sopenharmony_ciupdate_primitive_restart(struct gl_context *ctx) 178bf215546Sopenharmony_ci{ 179bf215546Sopenharmony_ci struct glthread_state *glthread = &ctx->GLThread; 180bf215546Sopenharmony_ci 181bf215546Sopenharmony_ci glthread->_PrimitiveRestart = glthread->PrimitiveRestart || 182bf215546Sopenharmony_ci glthread->PrimitiveRestartFixedIndex; 183bf215546Sopenharmony_ci glthread->_RestartIndex[0] = 184bf215546Sopenharmony_ci _mesa_get_prim_restart_index(glthread->PrimitiveRestartFixedIndex, 185bf215546Sopenharmony_ci glthread->RestartIndex, 1); 186bf215546Sopenharmony_ci glthread->_RestartIndex[1] = 187bf215546Sopenharmony_ci _mesa_get_prim_restart_index(glthread->PrimitiveRestartFixedIndex, 188bf215546Sopenharmony_ci glthread->RestartIndex, 2); 189bf215546Sopenharmony_ci glthread->_RestartIndex[3] = 190bf215546Sopenharmony_ci _mesa_get_prim_restart_index(glthread->PrimitiveRestartFixedIndex, 191bf215546Sopenharmony_ci glthread->RestartIndex, 4); 192bf215546Sopenharmony_ci} 193bf215546Sopenharmony_ci 194bf215546Sopenharmony_civoid 195bf215546Sopenharmony_ci_mesa_glthread_set_prim_restart(struct gl_context *ctx, GLenum cap, bool value) 196bf215546Sopenharmony_ci{ 197bf215546Sopenharmony_ci switch (cap) { 198bf215546Sopenharmony_ci case GL_PRIMITIVE_RESTART: 199bf215546Sopenharmony_ci ctx->GLThread.PrimitiveRestart = value; 200bf215546Sopenharmony_ci break; 201bf215546Sopenharmony_ci case GL_PRIMITIVE_RESTART_FIXED_INDEX: 202bf215546Sopenharmony_ci ctx->GLThread.PrimitiveRestartFixedIndex = value; 203bf215546Sopenharmony_ci break; 204bf215546Sopenharmony_ci } 205bf215546Sopenharmony_ci 206bf215546Sopenharmony_ci update_primitive_restart(ctx); 207bf215546Sopenharmony_ci} 208bf215546Sopenharmony_ci 209bf215546Sopenharmony_civoid 210bf215546Sopenharmony_ci_mesa_glthread_PrimitiveRestartIndex(struct gl_context *ctx, GLuint index) 211bf215546Sopenharmony_ci{ 212bf215546Sopenharmony_ci ctx->GLThread.RestartIndex = index; 213bf215546Sopenharmony_ci update_primitive_restart(ctx); 214bf215546Sopenharmony_ci} 215bf215546Sopenharmony_ci 216bf215546Sopenharmony_cistatic inline void 217bf215546Sopenharmony_cienable_buffer(struct glthread_vao *vao, unsigned binding_index) 218bf215546Sopenharmony_ci{ 219bf215546Sopenharmony_ci int attrib_count = ++vao->Attrib[binding_index].EnabledAttribCount; 220bf215546Sopenharmony_ci 221bf215546Sopenharmony_ci if (attrib_count == 1) 222bf215546Sopenharmony_ci vao->BufferEnabled |= 1 << binding_index; 223bf215546Sopenharmony_ci else if (attrib_count == 2) 224bf215546Sopenharmony_ci vao->BufferInterleaved |= 1 << binding_index; 225bf215546Sopenharmony_ci} 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_cistatic inline void 228bf215546Sopenharmony_cidisable_buffer(struct glthread_vao *vao, unsigned binding_index) 229bf215546Sopenharmony_ci{ 230bf215546Sopenharmony_ci int attrib_count = --vao->Attrib[binding_index].EnabledAttribCount; 231bf215546Sopenharmony_ci 232bf215546Sopenharmony_ci if (attrib_count == 0) 233bf215546Sopenharmony_ci vao->BufferEnabled &= ~(1 << binding_index); 234bf215546Sopenharmony_ci else if (attrib_count == 1) 235bf215546Sopenharmony_ci vao->BufferInterleaved &= ~(1 << binding_index); 236bf215546Sopenharmony_ci else 237bf215546Sopenharmony_ci assert(attrib_count >= 0); 238bf215546Sopenharmony_ci} 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_civoid 241bf215546Sopenharmony_ci_mesa_glthread_ClientState(struct gl_context *ctx, GLuint *vaobj, 242bf215546Sopenharmony_ci gl_vert_attrib attrib, bool enable) 243bf215546Sopenharmony_ci{ 244bf215546Sopenharmony_ci /* The primitive restart client state uses a special value. */ 245bf215546Sopenharmony_ci if (attrib == VERT_ATTRIB_PRIMITIVE_RESTART_NV) { 246bf215546Sopenharmony_ci ctx->GLThread.PrimitiveRestart = enable; 247bf215546Sopenharmony_ci update_primitive_restart(ctx); 248bf215546Sopenharmony_ci return; 249bf215546Sopenharmony_ci } 250bf215546Sopenharmony_ci 251bf215546Sopenharmony_ci if (attrib >= VERT_ATTRIB_MAX) 252bf215546Sopenharmony_ci return; 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_ci struct glthread_vao *vao = get_vao(ctx, vaobj); 255bf215546Sopenharmony_ci if (!vao) 256bf215546Sopenharmony_ci return; 257bf215546Sopenharmony_ci 258bf215546Sopenharmony_ci const unsigned attrib_bit = 1u << attrib; 259bf215546Sopenharmony_ci 260bf215546Sopenharmony_ci if (enable && !(vao->UserEnabled & attrib_bit)) { 261bf215546Sopenharmony_ci vao->UserEnabled |= attrib_bit; 262bf215546Sopenharmony_ci 263bf215546Sopenharmony_ci /* The generic0 attribute supersedes the position attribute. We need to 264bf215546Sopenharmony_ci * update BufferBindingEnabled accordingly. 265bf215546Sopenharmony_ci */ 266bf215546Sopenharmony_ci if (attrib == VERT_ATTRIB_POS) { 267bf215546Sopenharmony_ci if (!(vao->UserEnabled & VERT_BIT_GENERIC0)) 268bf215546Sopenharmony_ci enable_buffer(vao, vao->Attrib[VERT_ATTRIB_POS].BufferIndex); 269bf215546Sopenharmony_ci } else { 270bf215546Sopenharmony_ci enable_buffer(vao, vao->Attrib[attrib].BufferIndex); 271bf215546Sopenharmony_ci 272bf215546Sopenharmony_ci if (attrib == VERT_ATTRIB_GENERIC0 && vao->UserEnabled & VERT_BIT_POS) 273bf215546Sopenharmony_ci disable_buffer(vao, vao->Attrib[VERT_ATTRIB_POS].BufferIndex); 274bf215546Sopenharmony_ci } 275bf215546Sopenharmony_ci } else if (!enable && (vao->UserEnabled & attrib_bit)) { 276bf215546Sopenharmony_ci vao->UserEnabled &= ~attrib_bit; 277bf215546Sopenharmony_ci 278bf215546Sopenharmony_ci /* The generic0 attribute supersedes the position attribute. We need to 279bf215546Sopenharmony_ci * update BufferBindingEnabled accordingly. 280bf215546Sopenharmony_ci */ 281bf215546Sopenharmony_ci if (attrib == VERT_ATTRIB_POS) { 282bf215546Sopenharmony_ci if (!(vao->UserEnabled & VERT_BIT_GENERIC0)) 283bf215546Sopenharmony_ci disable_buffer(vao, vao->Attrib[VERT_ATTRIB_POS].BufferIndex); 284bf215546Sopenharmony_ci } else { 285bf215546Sopenharmony_ci disable_buffer(vao, vao->Attrib[attrib].BufferIndex); 286bf215546Sopenharmony_ci 287bf215546Sopenharmony_ci if (attrib == VERT_ATTRIB_GENERIC0 && vao->UserEnabled & VERT_BIT_POS) 288bf215546Sopenharmony_ci enable_buffer(vao, vao->Attrib[VERT_ATTRIB_POS].BufferIndex); 289bf215546Sopenharmony_ci } 290bf215546Sopenharmony_ci } 291bf215546Sopenharmony_ci 292bf215546Sopenharmony_ci /* The generic0 attribute supersedes the position attribute. */ 293bf215546Sopenharmony_ci vao->Enabled = vao->UserEnabled; 294bf215546Sopenharmony_ci if (vao->Enabled & VERT_BIT_GENERIC0) 295bf215546Sopenharmony_ci vao->Enabled &= ~VERT_BIT_POS; 296bf215546Sopenharmony_ci} 297bf215546Sopenharmony_ci 298bf215546Sopenharmony_cistatic void 299bf215546Sopenharmony_ciset_attrib_binding(struct glthread_state *glthread, struct glthread_vao *vao, 300bf215546Sopenharmony_ci gl_vert_attrib attrib, unsigned new_binding_index) 301bf215546Sopenharmony_ci{ 302bf215546Sopenharmony_ci unsigned old_binding_index = vao->Attrib[attrib].BufferIndex; 303bf215546Sopenharmony_ci 304bf215546Sopenharmony_ci if (old_binding_index != new_binding_index) { 305bf215546Sopenharmony_ci vao->Attrib[attrib].BufferIndex = new_binding_index; 306bf215546Sopenharmony_ci 307bf215546Sopenharmony_ci if (vao->Enabled & (1u << attrib)) { 308bf215546Sopenharmony_ci /* Update BufferBindingEnabled. */ 309bf215546Sopenharmony_ci enable_buffer(vao, new_binding_index); 310bf215546Sopenharmony_ci disable_buffer(vao, old_binding_index); 311bf215546Sopenharmony_ci } 312bf215546Sopenharmony_ci } 313bf215546Sopenharmony_ci} 314bf215546Sopenharmony_ci 315bf215546Sopenharmony_civoid _mesa_glthread_AttribDivisor(struct gl_context *ctx, const GLuint *vaobj, 316bf215546Sopenharmony_ci gl_vert_attrib attrib, GLuint divisor) 317bf215546Sopenharmony_ci{ 318bf215546Sopenharmony_ci if (attrib >= VERT_ATTRIB_MAX) 319bf215546Sopenharmony_ci return; 320bf215546Sopenharmony_ci 321bf215546Sopenharmony_ci struct glthread_vao *vao = get_vao(ctx, vaobj); 322bf215546Sopenharmony_ci if (!vao) 323bf215546Sopenharmony_ci return; 324bf215546Sopenharmony_ci 325bf215546Sopenharmony_ci vao->Attrib[attrib].Divisor = divisor; 326bf215546Sopenharmony_ci 327bf215546Sopenharmony_ci set_attrib_binding(&ctx->GLThread, vao, attrib, attrib); 328bf215546Sopenharmony_ci 329bf215546Sopenharmony_ci if (divisor) 330bf215546Sopenharmony_ci vao->NonZeroDivisorMask |= 1u << attrib; 331bf215546Sopenharmony_ci else 332bf215546Sopenharmony_ci vao->NonZeroDivisorMask &= ~(1u << attrib); 333bf215546Sopenharmony_ci} 334bf215546Sopenharmony_ci 335bf215546Sopenharmony_cistatic unsigned 336bf215546Sopenharmony_cielement_size(GLint size, GLenum type) 337bf215546Sopenharmony_ci{ 338bf215546Sopenharmony_ci if (size == GL_BGRA) 339bf215546Sopenharmony_ci size = 4; 340bf215546Sopenharmony_ci 341bf215546Sopenharmony_ci return _mesa_bytes_per_vertex_attrib(size, type); 342bf215546Sopenharmony_ci} 343bf215546Sopenharmony_ci 344bf215546Sopenharmony_cistatic void 345bf215546Sopenharmony_ciattrib_pointer(struct glthread_state *glthread, struct glthread_vao *vao, 346bf215546Sopenharmony_ci GLuint buffer, gl_vert_attrib attrib, 347bf215546Sopenharmony_ci GLint size, GLenum type, GLsizei stride, 348bf215546Sopenharmony_ci const void *pointer) 349bf215546Sopenharmony_ci{ 350bf215546Sopenharmony_ci if (attrib >= VERT_ATTRIB_MAX) 351bf215546Sopenharmony_ci return; 352bf215546Sopenharmony_ci 353bf215546Sopenharmony_ci unsigned elem_size = element_size(size, type); 354bf215546Sopenharmony_ci 355bf215546Sopenharmony_ci vao->Attrib[attrib].ElementSize = elem_size; 356bf215546Sopenharmony_ci vao->Attrib[attrib].Stride = stride ? stride : elem_size; 357bf215546Sopenharmony_ci vao->Attrib[attrib].Pointer = pointer; 358bf215546Sopenharmony_ci vao->Attrib[attrib].RelativeOffset = 0; 359bf215546Sopenharmony_ci 360bf215546Sopenharmony_ci set_attrib_binding(glthread, vao, attrib, attrib); 361bf215546Sopenharmony_ci 362bf215546Sopenharmony_ci if (buffer != 0) 363bf215546Sopenharmony_ci vao->UserPointerMask &= ~(1u << attrib); 364bf215546Sopenharmony_ci else 365bf215546Sopenharmony_ci vao->UserPointerMask |= 1u << attrib; 366bf215546Sopenharmony_ci} 367bf215546Sopenharmony_ci 368bf215546Sopenharmony_civoid 369bf215546Sopenharmony_ci_mesa_glthread_AttribPointer(struct gl_context *ctx, gl_vert_attrib attrib, 370bf215546Sopenharmony_ci GLint size, GLenum type, GLsizei stride, 371bf215546Sopenharmony_ci const void *pointer) 372bf215546Sopenharmony_ci{ 373bf215546Sopenharmony_ci struct glthread_state *glthread = &ctx->GLThread; 374bf215546Sopenharmony_ci 375bf215546Sopenharmony_ci attrib_pointer(glthread, glthread->CurrentVAO, 376bf215546Sopenharmony_ci glthread->CurrentArrayBufferName, 377bf215546Sopenharmony_ci attrib, size, type, stride, pointer); 378bf215546Sopenharmony_ci} 379bf215546Sopenharmony_ci 380bf215546Sopenharmony_civoid 381bf215546Sopenharmony_ci_mesa_glthread_DSAAttribPointer(struct gl_context *ctx, GLuint vaobj, 382bf215546Sopenharmony_ci GLuint buffer, gl_vert_attrib attrib, 383bf215546Sopenharmony_ci GLint size, GLenum type, GLsizei stride, 384bf215546Sopenharmony_ci GLintptr offset) 385bf215546Sopenharmony_ci{ 386bf215546Sopenharmony_ci struct glthread_state *glthread = &ctx->GLThread; 387bf215546Sopenharmony_ci struct glthread_vao *vao; 388bf215546Sopenharmony_ci 389bf215546Sopenharmony_ci vao = lookup_vao(ctx, vaobj); 390bf215546Sopenharmony_ci if (!vao) 391bf215546Sopenharmony_ci return; 392bf215546Sopenharmony_ci 393bf215546Sopenharmony_ci attrib_pointer(glthread, vao, buffer, attrib, size, type, stride, 394bf215546Sopenharmony_ci (const void*)offset); 395bf215546Sopenharmony_ci} 396bf215546Sopenharmony_ci 397bf215546Sopenharmony_cistatic void 398bf215546Sopenharmony_ciattrib_format(struct glthread_state *glthread, struct glthread_vao *vao, 399bf215546Sopenharmony_ci GLuint attribindex, GLint size, GLenum type, 400bf215546Sopenharmony_ci GLuint relativeoffset) 401bf215546Sopenharmony_ci{ 402bf215546Sopenharmony_ci if (attribindex >= VERT_ATTRIB_GENERIC_MAX) 403bf215546Sopenharmony_ci return; 404bf215546Sopenharmony_ci 405bf215546Sopenharmony_ci unsigned elem_size = element_size(size, type); 406bf215546Sopenharmony_ci 407bf215546Sopenharmony_ci unsigned i = VERT_ATTRIB_GENERIC(attribindex); 408bf215546Sopenharmony_ci vao->Attrib[i].ElementSize = elem_size; 409bf215546Sopenharmony_ci vao->Attrib[i].RelativeOffset = relativeoffset; 410bf215546Sopenharmony_ci} 411bf215546Sopenharmony_ci 412bf215546Sopenharmony_civoid 413bf215546Sopenharmony_ci_mesa_glthread_AttribFormat(struct gl_context *ctx, GLuint attribindex, 414bf215546Sopenharmony_ci GLint size, GLenum type, GLuint relativeoffset) 415bf215546Sopenharmony_ci{ 416bf215546Sopenharmony_ci struct glthread_state *glthread = &ctx->GLThread; 417bf215546Sopenharmony_ci 418bf215546Sopenharmony_ci attrib_format(glthread, glthread->CurrentVAO, attribindex, size, type, 419bf215546Sopenharmony_ci relativeoffset); 420bf215546Sopenharmony_ci} 421bf215546Sopenharmony_ci 422bf215546Sopenharmony_civoid 423bf215546Sopenharmony_ci_mesa_glthread_DSAAttribFormat(struct gl_context *ctx, GLuint vaobj, 424bf215546Sopenharmony_ci GLuint attribindex, GLint size, GLenum type, 425bf215546Sopenharmony_ci GLuint relativeoffset) 426bf215546Sopenharmony_ci{ 427bf215546Sopenharmony_ci struct glthread_state *glthread = &ctx->GLThread; 428bf215546Sopenharmony_ci struct glthread_vao *vao = lookup_vao(ctx, vaobj); 429bf215546Sopenharmony_ci 430bf215546Sopenharmony_ci if (vao) 431bf215546Sopenharmony_ci attrib_format(glthread, vao, attribindex, size, type, relativeoffset); 432bf215546Sopenharmony_ci} 433bf215546Sopenharmony_ci 434bf215546Sopenharmony_cistatic void 435bf215546Sopenharmony_cibind_vertex_buffer(struct glthread_state *glthread, struct glthread_vao *vao, 436bf215546Sopenharmony_ci GLuint bindingindex, GLuint buffer, GLintptr offset, 437bf215546Sopenharmony_ci GLsizei stride) 438bf215546Sopenharmony_ci{ 439bf215546Sopenharmony_ci if (bindingindex >= VERT_ATTRIB_GENERIC_MAX) 440bf215546Sopenharmony_ci return; 441bf215546Sopenharmony_ci 442bf215546Sopenharmony_ci unsigned i = VERT_ATTRIB_GENERIC(bindingindex); 443bf215546Sopenharmony_ci vao->Attrib[i].Pointer = (const void*)offset; 444bf215546Sopenharmony_ci vao->Attrib[i].Stride = stride; 445bf215546Sopenharmony_ci 446bf215546Sopenharmony_ci if (buffer != 0) 447bf215546Sopenharmony_ci vao->UserPointerMask &= ~(1u << i); 448bf215546Sopenharmony_ci else 449bf215546Sopenharmony_ci vao->UserPointerMask |= 1u << i; 450bf215546Sopenharmony_ci} 451bf215546Sopenharmony_ci 452bf215546Sopenharmony_civoid 453bf215546Sopenharmony_ci_mesa_glthread_VertexBuffer(struct gl_context *ctx, GLuint bindingindex, 454bf215546Sopenharmony_ci GLuint buffer, GLintptr offset, GLsizei stride) 455bf215546Sopenharmony_ci{ 456bf215546Sopenharmony_ci struct glthread_state *glthread = &ctx->GLThread; 457bf215546Sopenharmony_ci 458bf215546Sopenharmony_ci bind_vertex_buffer(glthread, glthread->CurrentVAO, bindingindex, buffer, 459bf215546Sopenharmony_ci offset, stride); 460bf215546Sopenharmony_ci} 461bf215546Sopenharmony_ci 462bf215546Sopenharmony_civoid 463bf215546Sopenharmony_ci_mesa_glthread_DSAVertexBuffer(struct gl_context *ctx, GLuint vaobj, 464bf215546Sopenharmony_ci GLuint bindingindex, GLuint buffer, 465bf215546Sopenharmony_ci GLintptr offset, GLsizei stride) 466bf215546Sopenharmony_ci{ 467bf215546Sopenharmony_ci struct glthread_state *glthread = &ctx->GLThread; 468bf215546Sopenharmony_ci struct glthread_vao *vao = lookup_vao(ctx, vaobj); 469bf215546Sopenharmony_ci 470bf215546Sopenharmony_ci if (vao) 471bf215546Sopenharmony_ci bind_vertex_buffer(glthread, vao, bindingindex, buffer, offset, stride); 472bf215546Sopenharmony_ci} 473bf215546Sopenharmony_ci 474bf215546Sopenharmony_civoid 475bf215546Sopenharmony_ci_mesa_glthread_DSAVertexBuffers(struct gl_context *ctx, GLuint vaobj, 476bf215546Sopenharmony_ci GLuint first, GLsizei count, 477bf215546Sopenharmony_ci const GLuint *buffers, 478bf215546Sopenharmony_ci const GLintptr *offsets, 479bf215546Sopenharmony_ci const GLsizei *strides) 480bf215546Sopenharmony_ci{ 481bf215546Sopenharmony_ci struct glthread_state *glthread = &ctx->GLThread; 482bf215546Sopenharmony_ci struct glthread_vao *vao; 483bf215546Sopenharmony_ci 484bf215546Sopenharmony_ci vao = lookup_vao(ctx, vaobj); 485bf215546Sopenharmony_ci if (!vao) 486bf215546Sopenharmony_ci return; 487bf215546Sopenharmony_ci 488bf215546Sopenharmony_ci for (unsigned i = 0; i < count; i++) { 489bf215546Sopenharmony_ci bind_vertex_buffer(glthread, vao, first + i, buffers[i], offsets[i], 490bf215546Sopenharmony_ci strides[i]); 491bf215546Sopenharmony_ci } 492bf215546Sopenharmony_ci} 493bf215546Sopenharmony_ci 494bf215546Sopenharmony_cistatic void 495bf215546Sopenharmony_cibinding_divisor(struct glthread_state *glthread, struct glthread_vao *vao, 496bf215546Sopenharmony_ci GLuint bindingindex, GLuint divisor) 497bf215546Sopenharmony_ci{ 498bf215546Sopenharmony_ci if (bindingindex >= VERT_ATTRIB_GENERIC_MAX) 499bf215546Sopenharmony_ci return; 500bf215546Sopenharmony_ci 501bf215546Sopenharmony_ci unsigned i = VERT_ATTRIB_GENERIC(bindingindex); 502bf215546Sopenharmony_ci vao->Attrib[i].Divisor = divisor; 503bf215546Sopenharmony_ci 504bf215546Sopenharmony_ci if (divisor) 505bf215546Sopenharmony_ci vao->NonZeroDivisorMask |= 1u << i; 506bf215546Sopenharmony_ci else 507bf215546Sopenharmony_ci vao->NonZeroDivisorMask &= ~(1u << i); 508bf215546Sopenharmony_ci} 509bf215546Sopenharmony_ci 510bf215546Sopenharmony_civoid 511bf215546Sopenharmony_ci_mesa_glthread_BindingDivisor(struct gl_context *ctx, GLuint bindingindex, 512bf215546Sopenharmony_ci GLuint divisor) 513bf215546Sopenharmony_ci{ 514bf215546Sopenharmony_ci struct glthread_state *glthread = &ctx->GLThread; 515bf215546Sopenharmony_ci 516bf215546Sopenharmony_ci binding_divisor(glthread, glthread->CurrentVAO, bindingindex, divisor); 517bf215546Sopenharmony_ci} 518bf215546Sopenharmony_ci 519bf215546Sopenharmony_civoid 520bf215546Sopenharmony_ci_mesa_glthread_DSABindingDivisor(struct gl_context *ctx, GLuint vaobj, 521bf215546Sopenharmony_ci GLuint bindingindex, GLuint divisor) 522bf215546Sopenharmony_ci{ 523bf215546Sopenharmony_ci struct glthread_state *glthread = &ctx->GLThread; 524bf215546Sopenharmony_ci struct glthread_vao *vao = lookup_vao(ctx, vaobj); 525bf215546Sopenharmony_ci 526bf215546Sopenharmony_ci if (vao) 527bf215546Sopenharmony_ci binding_divisor(glthread, vao, bindingindex, divisor); 528bf215546Sopenharmony_ci} 529bf215546Sopenharmony_ci 530bf215546Sopenharmony_civoid 531bf215546Sopenharmony_ci_mesa_glthread_AttribBinding(struct gl_context *ctx, GLuint attribindex, 532bf215546Sopenharmony_ci GLuint bindingindex) 533bf215546Sopenharmony_ci{ 534bf215546Sopenharmony_ci struct glthread_state *glthread = &ctx->GLThread; 535bf215546Sopenharmony_ci 536bf215546Sopenharmony_ci if (attribindex >= VERT_ATTRIB_GENERIC_MAX || 537bf215546Sopenharmony_ci bindingindex >= VERT_ATTRIB_GENERIC_MAX) 538bf215546Sopenharmony_ci return; 539bf215546Sopenharmony_ci 540bf215546Sopenharmony_ci set_attrib_binding(glthread, glthread->CurrentVAO, 541bf215546Sopenharmony_ci VERT_ATTRIB_GENERIC(attribindex), 542bf215546Sopenharmony_ci VERT_ATTRIB_GENERIC(bindingindex)); 543bf215546Sopenharmony_ci} 544bf215546Sopenharmony_ci 545bf215546Sopenharmony_civoid 546bf215546Sopenharmony_ci_mesa_glthread_DSAAttribBinding(struct gl_context *ctx, GLuint vaobj, 547bf215546Sopenharmony_ci GLuint attribindex, GLuint bindingindex) 548bf215546Sopenharmony_ci{ 549bf215546Sopenharmony_ci struct glthread_state *glthread = &ctx->GLThread; 550bf215546Sopenharmony_ci 551bf215546Sopenharmony_ci if (attribindex >= VERT_ATTRIB_GENERIC_MAX || 552bf215546Sopenharmony_ci bindingindex >= VERT_ATTRIB_GENERIC_MAX) 553bf215546Sopenharmony_ci return; 554bf215546Sopenharmony_ci 555bf215546Sopenharmony_ci struct glthread_vao *vao = lookup_vao(ctx, vaobj); 556bf215546Sopenharmony_ci if (vao) { 557bf215546Sopenharmony_ci set_attrib_binding(glthread, vao, 558bf215546Sopenharmony_ci VERT_ATTRIB_GENERIC(attribindex), 559bf215546Sopenharmony_ci VERT_ATTRIB_GENERIC(bindingindex)); 560bf215546Sopenharmony_ci } 561bf215546Sopenharmony_ci} 562bf215546Sopenharmony_ci 563bf215546Sopenharmony_civoid 564bf215546Sopenharmony_ci_mesa_glthread_DSAElementBuffer(struct gl_context *ctx, GLuint vaobj, 565bf215546Sopenharmony_ci GLuint buffer) 566bf215546Sopenharmony_ci{ 567bf215546Sopenharmony_ci struct glthread_vao *vao = lookup_vao(ctx, vaobj); 568bf215546Sopenharmony_ci 569bf215546Sopenharmony_ci if (vao) 570bf215546Sopenharmony_ci vao->CurrentElementBufferName = buffer; 571bf215546Sopenharmony_ci} 572bf215546Sopenharmony_ci 573bf215546Sopenharmony_civoid 574bf215546Sopenharmony_ci_mesa_glthread_PushClientAttrib(struct gl_context *ctx, GLbitfield mask, 575bf215546Sopenharmony_ci bool set_default) 576bf215546Sopenharmony_ci{ 577bf215546Sopenharmony_ci struct glthread_state *glthread = &ctx->GLThread; 578bf215546Sopenharmony_ci 579bf215546Sopenharmony_ci if (glthread->ClientAttribStackTop >= MAX_CLIENT_ATTRIB_STACK_DEPTH) 580bf215546Sopenharmony_ci return; 581bf215546Sopenharmony_ci 582bf215546Sopenharmony_ci struct glthread_client_attrib *top = 583bf215546Sopenharmony_ci &glthread->ClientAttribStack[glthread->ClientAttribStackTop]; 584bf215546Sopenharmony_ci 585bf215546Sopenharmony_ci if (mask & GL_CLIENT_VERTEX_ARRAY_BIT) { 586bf215546Sopenharmony_ci top->VAO = *glthread->CurrentVAO; 587bf215546Sopenharmony_ci top->CurrentArrayBufferName = glthread->CurrentArrayBufferName; 588bf215546Sopenharmony_ci top->ClientActiveTexture = glthread->ClientActiveTexture; 589bf215546Sopenharmony_ci top->RestartIndex = glthread->RestartIndex; 590bf215546Sopenharmony_ci top->PrimitiveRestart = glthread->PrimitiveRestart; 591bf215546Sopenharmony_ci top->PrimitiveRestartFixedIndex = glthread->PrimitiveRestartFixedIndex; 592bf215546Sopenharmony_ci top->Valid = true; 593bf215546Sopenharmony_ci } else { 594bf215546Sopenharmony_ci top->Valid = false; 595bf215546Sopenharmony_ci } 596bf215546Sopenharmony_ci 597bf215546Sopenharmony_ci glthread->ClientAttribStackTop++; 598bf215546Sopenharmony_ci 599bf215546Sopenharmony_ci if (set_default) 600bf215546Sopenharmony_ci _mesa_glthread_ClientAttribDefault(ctx, mask); 601bf215546Sopenharmony_ci} 602bf215546Sopenharmony_ci 603bf215546Sopenharmony_civoid 604bf215546Sopenharmony_ci_mesa_glthread_PopClientAttrib(struct gl_context *ctx) 605bf215546Sopenharmony_ci{ 606bf215546Sopenharmony_ci struct glthread_state *glthread = &ctx->GLThread; 607bf215546Sopenharmony_ci 608bf215546Sopenharmony_ci if (glthread->ClientAttribStackTop == 0) 609bf215546Sopenharmony_ci return; 610bf215546Sopenharmony_ci 611bf215546Sopenharmony_ci glthread->ClientAttribStackTop--; 612bf215546Sopenharmony_ci 613bf215546Sopenharmony_ci struct glthread_client_attrib *top = 614bf215546Sopenharmony_ci &glthread->ClientAttribStack[glthread->ClientAttribStackTop]; 615bf215546Sopenharmony_ci 616bf215546Sopenharmony_ci if (!top->Valid) 617bf215546Sopenharmony_ci return; 618bf215546Sopenharmony_ci 619bf215546Sopenharmony_ci /* Popping a delete VAO is an error. */ 620bf215546Sopenharmony_ci struct glthread_vao *vao = NULL; 621bf215546Sopenharmony_ci if (top->VAO.Name) { 622bf215546Sopenharmony_ci vao = lookup_vao(ctx, top->VAO.Name); 623bf215546Sopenharmony_ci if (!vao) 624bf215546Sopenharmony_ci return; 625bf215546Sopenharmony_ci } 626bf215546Sopenharmony_ci 627bf215546Sopenharmony_ci /* Restore states. */ 628bf215546Sopenharmony_ci glthread->CurrentArrayBufferName = top->CurrentArrayBufferName; 629bf215546Sopenharmony_ci glthread->ClientActiveTexture = top->ClientActiveTexture; 630bf215546Sopenharmony_ci glthread->RestartIndex = top->RestartIndex; 631bf215546Sopenharmony_ci glthread->PrimitiveRestart = top->PrimitiveRestart; 632bf215546Sopenharmony_ci glthread->PrimitiveRestartFixedIndex = top->PrimitiveRestartFixedIndex; 633bf215546Sopenharmony_ci 634bf215546Sopenharmony_ci if (!vao) 635bf215546Sopenharmony_ci vao = &glthread->DefaultVAO; 636bf215546Sopenharmony_ci 637bf215546Sopenharmony_ci assert(top->VAO.Name == vao->Name); 638bf215546Sopenharmony_ci *vao = top->VAO; /* Copy all fields. */ 639bf215546Sopenharmony_ci glthread->CurrentVAO = vao; 640bf215546Sopenharmony_ci} 641bf215546Sopenharmony_ci 642bf215546Sopenharmony_civoid 643bf215546Sopenharmony_ci_mesa_glthread_ClientAttribDefault(struct gl_context *ctx, GLbitfield mask) 644bf215546Sopenharmony_ci{ 645bf215546Sopenharmony_ci struct glthread_state *glthread = &ctx->GLThread; 646bf215546Sopenharmony_ci 647bf215546Sopenharmony_ci if (!(mask & GL_CLIENT_VERTEX_ARRAY_BIT)) 648bf215546Sopenharmony_ci return; 649bf215546Sopenharmony_ci 650bf215546Sopenharmony_ci glthread->CurrentArrayBufferName = 0; 651bf215546Sopenharmony_ci glthread->ClientActiveTexture = 0; 652bf215546Sopenharmony_ci glthread->RestartIndex = 0; 653bf215546Sopenharmony_ci glthread->PrimitiveRestart = false; 654bf215546Sopenharmony_ci glthread->PrimitiveRestartFixedIndex = false; 655bf215546Sopenharmony_ci glthread->CurrentVAO = &glthread->DefaultVAO; 656bf215546Sopenharmony_ci _mesa_glthread_reset_vao(glthread->CurrentVAO); 657bf215546Sopenharmony_ci} 658bf215546Sopenharmony_ci 659bf215546Sopenharmony_civoid 660bf215546Sopenharmony_ci_mesa_glthread_InterleavedArrays(struct gl_context *ctx, GLenum format, 661bf215546Sopenharmony_ci GLsizei stride, const GLvoid *pointer) 662bf215546Sopenharmony_ci{ 663bf215546Sopenharmony_ci struct gl_interleaved_layout layout; 664bf215546Sopenharmony_ci unsigned tex = VERT_ATTRIB_TEX(ctx->GLThread.ClientActiveTexture); 665bf215546Sopenharmony_ci 666bf215546Sopenharmony_ci if (stride < 0 || !_mesa_get_interleaved_layout(format, &layout)) 667bf215546Sopenharmony_ci return; 668bf215546Sopenharmony_ci 669bf215546Sopenharmony_ci if (!stride) 670bf215546Sopenharmony_ci stride = layout.defstride; 671bf215546Sopenharmony_ci 672bf215546Sopenharmony_ci _mesa_glthread_ClientState(ctx, NULL, VERT_ATTRIB_EDGEFLAG, false); 673bf215546Sopenharmony_ci _mesa_glthread_ClientState(ctx, NULL, VERT_ATTRIB_COLOR_INDEX, false); 674bf215546Sopenharmony_ci /* XXX also disable secondary color and generic arrays? */ 675bf215546Sopenharmony_ci 676bf215546Sopenharmony_ci /* Texcoords */ 677bf215546Sopenharmony_ci if (layout.tflag) { 678bf215546Sopenharmony_ci _mesa_glthread_ClientState(ctx, NULL, tex, true); 679bf215546Sopenharmony_ci _mesa_glthread_AttribPointer(ctx, tex, layout.tcomps, GL_FLOAT, stride, 680bf215546Sopenharmony_ci (GLubyte *) pointer + layout.toffset); 681bf215546Sopenharmony_ci } else { 682bf215546Sopenharmony_ci _mesa_glthread_ClientState(ctx, NULL, tex, false); 683bf215546Sopenharmony_ci } 684bf215546Sopenharmony_ci 685bf215546Sopenharmony_ci /* Color */ 686bf215546Sopenharmony_ci if (layout.cflag) { 687bf215546Sopenharmony_ci _mesa_glthread_ClientState(ctx, NULL, VERT_ATTRIB_COLOR0, true); 688bf215546Sopenharmony_ci _mesa_glthread_AttribPointer(ctx, VERT_ATTRIB_COLOR0, layout.ccomps, 689bf215546Sopenharmony_ci layout.ctype, stride, 690bf215546Sopenharmony_ci (GLubyte *) pointer + layout.coffset); 691bf215546Sopenharmony_ci } else { 692bf215546Sopenharmony_ci _mesa_glthread_ClientState(ctx, NULL, VERT_ATTRIB_COLOR0, false); 693bf215546Sopenharmony_ci } 694bf215546Sopenharmony_ci 695bf215546Sopenharmony_ci /* Normals */ 696bf215546Sopenharmony_ci if (layout.nflag) { 697bf215546Sopenharmony_ci _mesa_glthread_ClientState(ctx, NULL, VERT_ATTRIB_NORMAL, true); 698bf215546Sopenharmony_ci _mesa_glthread_AttribPointer(ctx, VERT_ATTRIB_NORMAL, 3, GL_FLOAT, 699bf215546Sopenharmony_ci stride, (GLubyte *) pointer + layout.noffset); 700bf215546Sopenharmony_ci } else { 701bf215546Sopenharmony_ci _mesa_glthread_ClientState(ctx, NULL, VERT_ATTRIB_NORMAL, false); 702bf215546Sopenharmony_ci } 703bf215546Sopenharmony_ci 704bf215546Sopenharmony_ci /* Vertices */ 705bf215546Sopenharmony_ci _mesa_glthread_ClientState(ctx, NULL, VERT_ATTRIB_POS, true); 706bf215546Sopenharmony_ci _mesa_glthread_AttribPointer(ctx, VERT_ATTRIB_POS, layout.vcomps, GL_FLOAT, 707bf215546Sopenharmony_ci stride, (GLubyte *) pointer + layout.voffset); 708bf215546Sopenharmony_ci} 709