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/* Draw function marshalling for glthread. 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci * The purpose of these glDraw wrappers is to upload non-VBO vertex and 27bf215546Sopenharmony_ci * index data, so that glthread doesn't have to execute synchronously. 28bf215546Sopenharmony_ci */ 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_ci#include "c99_alloca.h" 31bf215546Sopenharmony_ci 32bf215546Sopenharmony_ci#include "main/glthread_marshal.h" 33bf215546Sopenharmony_ci#include "main/dispatch.h" 34bf215546Sopenharmony_ci#include "main/varray.h" 35bf215546Sopenharmony_ci 36bf215546Sopenharmony_cistatic inline unsigned 37bf215546Sopenharmony_ciget_index_size(GLenum type) 38bf215546Sopenharmony_ci{ 39bf215546Sopenharmony_ci /* GL_UNSIGNED_BYTE - GL_UNSIGNED_BYTE = 0 40bf215546Sopenharmony_ci * GL_UNSIGNED_SHORT - GL_UNSIGNED_BYTE = 2 41bf215546Sopenharmony_ci * GL_UNSIGNED_INT - GL_UNSIGNED_BYTE = 4 42bf215546Sopenharmony_ci * 43bf215546Sopenharmony_ci * Divide by 2 to get n=0,1,2, then the index size is: 1 << n 44bf215546Sopenharmony_ci */ 45bf215546Sopenharmony_ci return 1 << ((type - GL_UNSIGNED_BYTE) >> 1); 46bf215546Sopenharmony_ci} 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_cistatic inline bool 49bf215546Sopenharmony_ciis_index_type_valid(GLenum type) 50bf215546Sopenharmony_ci{ 51bf215546Sopenharmony_ci /* GL_UNSIGNED_BYTE = 0x1401 52bf215546Sopenharmony_ci * GL_UNSIGNED_SHORT = 0x1403 53bf215546Sopenharmony_ci * GL_UNSIGNED_INT = 0x1405 54bf215546Sopenharmony_ci * 55bf215546Sopenharmony_ci * The trick is that bit 1 and bit 2 mean USHORT and UINT, respectively. 56bf215546Sopenharmony_ci * After clearing those two bits (with ~6), we should get UBYTE. 57bf215546Sopenharmony_ci * Both bits can't be set, because the enum would be greater than UINT. 58bf215546Sopenharmony_ci */ 59bf215546Sopenharmony_ci return type <= GL_UNSIGNED_INT && (type & ~6) == GL_UNSIGNED_BYTE; 60bf215546Sopenharmony_ci} 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_cistatic ALWAYS_INLINE struct gl_buffer_object * 63bf215546Sopenharmony_ciupload_indices(struct gl_context *ctx, unsigned count, unsigned index_size, 64bf215546Sopenharmony_ci const GLvoid **indices) 65bf215546Sopenharmony_ci{ 66bf215546Sopenharmony_ci struct gl_buffer_object *upload_buffer = NULL; 67bf215546Sopenharmony_ci unsigned upload_offset = 0; 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_ci assert(count); 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_ci _mesa_glthread_upload(ctx, *indices, index_size * count, 72bf215546Sopenharmony_ci &upload_offset, &upload_buffer, NULL); 73bf215546Sopenharmony_ci assert(upload_buffer); 74bf215546Sopenharmony_ci *indices = (const GLvoid*)(intptr_t)upload_offset; 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_ci return upload_buffer; 77bf215546Sopenharmony_ci} 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_cistatic ALWAYS_INLINE struct gl_buffer_object * 80bf215546Sopenharmony_ciupload_multi_indices(struct gl_context *ctx, unsigned total_count, 81bf215546Sopenharmony_ci unsigned index_size, unsigned draw_count, 82bf215546Sopenharmony_ci const GLsizei *count, const GLvoid *const *indices, 83bf215546Sopenharmony_ci const GLvoid **out_indices) 84bf215546Sopenharmony_ci{ 85bf215546Sopenharmony_ci struct gl_buffer_object *upload_buffer = NULL; 86bf215546Sopenharmony_ci unsigned upload_offset = 0; 87bf215546Sopenharmony_ci uint8_t *upload_ptr = NULL; 88bf215546Sopenharmony_ci 89bf215546Sopenharmony_ci assert(total_count); 90bf215546Sopenharmony_ci 91bf215546Sopenharmony_ci _mesa_glthread_upload(ctx, NULL, index_size * total_count, 92bf215546Sopenharmony_ci &upload_offset, &upload_buffer, &upload_ptr); 93bf215546Sopenharmony_ci assert(upload_buffer); 94bf215546Sopenharmony_ci 95bf215546Sopenharmony_ci for (unsigned i = 0, offset = 0; i < draw_count; i++) { 96bf215546Sopenharmony_ci if (count[i] == 0) 97bf215546Sopenharmony_ci continue; 98bf215546Sopenharmony_ci 99bf215546Sopenharmony_ci unsigned size = count[i] * index_size; 100bf215546Sopenharmony_ci 101bf215546Sopenharmony_ci memcpy(upload_ptr + offset, indices[i], size); 102bf215546Sopenharmony_ci out_indices[i] = (const GLvoid*)(intptr_t)(upload_offset + offset); 103bf215546Sopenharmony_ci offset += size; 104bf215546Sopenharmony_ci } 105bf215546Sopenharmony_ci 106bf215546Sopenharmony_ci return upload_buffer; 107bf215546Sopenharmony_ci} 108bf215546Sopenharmony_ci 109bf215546Sopenharmony_cistatic ALWAYS_INLINE bool 110bf215546Sopenharmony_ciupload_vertices(struct gl_context *ctx, unsigned user_buffer_mask, 111bf215546Sopenharmony_ci unsigned start_vertex, unsigned num_vertices, 112bf215546Sopenharmony_ci unsigned start_instance, unsigned num_instances, 113bf215546Sopenharmony_ci struct glthread_attrib_binding *buffers) 114bf215546Sopenharmony_ci{ 115bf215546Sopenharmony_ci struct glthread_vao *vao = ctx->GLThread.CurrentVAO; 116bf215546Sopenharmony_ci unsigned attrib_mask_iter = vao->Enabled; 117bf215546Sopenharmony_ci unsigned num_buffers = 0; 118bf215546Sopenharmony_ci 119bf215546Sopenharmony_ci assert((num_vertices || !(user_buffer_mask & ~vao->NonZeroDivisorMask)) && 120bf215546Sopenharmony_ci (num_instances || !(user_buffer_mask & vao->NonZeroDivisorMask))); 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_ci if (unlikely(vao->BufferInterleaved & user_buffer_mask)) { 123bf215546Sopenharmony_ci /* Slower upload path where some buffers reference multiple attribs, 124bf215546Sopenharmony_ci * so we have to use 2 while loops instead of 1. 125bf215546Sopenharmony_ci */ 126bf215546Sopenharmony_ci unsigned start_offset[VERT_ATTRIB_MAX]; 127bf215546Sopenharmony_ci unsigned end_offset[VERT_ATTRIB_MAX]; 128bf215546Sopenharmony_ci uint32_t buffer_mask = 0; 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_ci while (attrib_mask_iter) { 131bf215546Sopenharmony_ci unsigned i = u_bit_scan(&attrib_mask_iter); 132bf215546Sopenharmony_ci unsigned binding_index = vao->Attrib[i].BufferIndex; 133bf215546Sopenharmony_ci 134bf215546Sopenharmony_ci if (!(user_buffer_mask & (1 << binding_index))) 135bf215546Sopenharmony_ci continue; 136bf215546Sopenharmony_ci 137bf215546Sopenharmony_ci unsigned stride = vao->Attrib[binding_index].Stride; 138bf215546Sopenharmony_ci unsigned instance_div = vao->Attrib[binding_index].Divisor; 139bf215546Sopenharmony_ci unsigned element_size = vao->Attrib[i].ElementSize; 140bf215546Sopenharmony_ci unsigned offset = vao->Attrib[i].RelativeOffset; 141bf215546Sopenharmony_ci unsigned size; 142bf215546Sopenharmony_ci 143bf215546Sopenharmony_ci if (instance_div) { 144bf215546Sopenharmony_ci /* Per-instance attrib. */ 145bf215546Sopenharmony_ci 146bf215546Sopenharmony_ci /* Figure out how many instances we'll render given instance_div. We 147bf215546Sopenharmony_ci * can't use the typical div_round_up() pattern because the CTS uses 148bf215546Sopenharmony_ci * instance_div = ~0 for a test, which overflows div_round_up()'s 149bf215546Sopenharmony_ci * addition. 150bf215546Sopenharmony_ci */ 151bf215546Sopenharmony_ci unsigned count = num_instances / instance_div; 152bf215546Sopenharmony_ci if (count * instance_div != num_instances) 153bf215546Sopenharmony_ci count++; 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci offset += stride * start_instance; 156bf215546Sopenharmony_ci size = stride * (count - 1) + element_size; 157bf215546Sopenharmony_ci } else { 158bf215546Sopenharmony_ci /* Per-vertex attrib. */ 159bf215546Sopenharmony_ci offset += stride * start_vertex; 160bf215546Sopenharmony_ci size = stride * (num_vertices - 1) + element_size; 161bf215546Sopenharmony_ci } 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci unsigned binding_index_bit = 1u << binding_index; 164bf215546Sopenharmony_ci 165bf215546Sopenharmony_ci /* Update upload offsets. */ 166bf215546Sopenharmony_ci if (!(buffer_mask & binding_index_bit)) { 167bf215546Sopenharmony_ci start_offset[binding_index] = offset; 168bf215546Sopenharmony_ci end_offset[binding_index] = offset + size; 169bf215546Sopenharmony_ci } else { 170bf215546Sopenharmony_ci if (offset < start_offset[binding_index]) 171bf215546Sopenharmony_ci start_offset[binding_index] = offset; 172bf215546Sopenharmony_ci if (offset + size > end_offset[binding_index]) 173bf215546Sopenharmony_ci end_offset[binding_index] = offset + size; 174bf215546Sopenharmony_ci } 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ci buffer_mask |= binding_index_bit; 177bf215546Sopenharmony_ci } 178bf215546Sopenharmony_ci 179bf215546Sopenharmony_ci /* Upload buffers. */ 180bf215546Sopenharmony_ci while (buffer_mask) { 181bf215546Sopenharmony_ci struct gl_buffer_object *upload_buffer = NULL; 182bf215546Sopenharmony_ci unsigned upload_offset = 0; 183bf215546Sopenharmony_ci unsigned start, end; 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_ci unsigned binding_index = u_bit_scan(&buffer_mask); 186bf215546Sopenharmony_ci 187bf215546Sopenharmony_ci start = start_offset[binding_index]; 188bf215546Sopenharmony_ci end = end_offset[binding_index]; 189bf215546Sopenharmony_ci assert(start < end); 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci const void *ptr = vao->Attrib[binding_index].Pointer; 192bf215546Sopenharmony_ci _mesa_glthread_upload(ctx, (uint8_t*)ptr + start, 193bf215546Sopenharmony_ci end - start, &upload_offset, 194bf215546Sopenharmony_ci &upload_buffer, NULL); 195bf215546Sopenharmony_ci assert(upload_buffer); 196bf215546Sopenharmony_ci 197bf215546Sopenharmony_ci buffers[num_buffers].buffer = upload_buffer; 198bf215546Sopenharmony_ci buffers[num_buffers].offset = upload_offset - start; 199bf215546Sopenharmony_ci buffers[num_buffers].original_pointer = ptr; 200bf215546Sopenharmony_ci num_buffers++; 201bf215546Sopenharmony_ci } 202bf215546Sopenharmony_ci 203bf215546Sopenharmony_ci return true; 204bf215546Sopenharmony_ci } 205bf215546Sopenharmony_ci 206bf215546Sopenharmony_ci /* Faster path where all attribs are separate. */ 207bf215546Sopenharmony_ci while (attrib_mask_iter) { 208bf215546Sopenharmony_ci unsigned i = u_bit_scan(&attrib_mask_iter); 209bf215546Sopenharmony_ci unsigned binding_index = vao->Attrib[i].BufferIndex; 210bf215546Sopenharmony_ci 211bf215546Sopenharmony_ci if (!(user_buffer_mask & (1 << binding_index))) 212bf215546Sopenharmony_ci continue; 213bf215546Sopenharmony_ci 214bf215546Sopenharmony_ci struct gl_buffer_object *upload_buffer = NULL; 215bf215546Sopenharmony_ci unsigned upload_offset = 0; 216bf215546Sopenharmony_ci unsigned stride = vao->Attrib[binding_index].Stride; 217bf215546Sopenharmony_ci unsigned instance_div = vao->Attrib[binding_index].Divisor; 218bf215546Sopenharmony_ci unsigned element_size = vao->Attrib[i].ElementSize; 219bf215546Sopenharmony_ci unsigned offset = vao->Attrib[i].RelativeOffset; 220bf215546Sopenharmony_ci unsigned size; 221bf215546Sopenharmony_ci 222bf215546Sopenharmony_ci if (instance_div) { 223bf215546Sopenharmony_ci /* Per-instance attrib. */ 224bf215546Sopenharmony_ci 225bf215546Sopenharmony_ci /* Figure out how many instances we'll render given instance_div. We 226bf215546Sopenharmony_ci * can't use the typical div_round_up() pattern because the CTS uses 227bf215546Sopenharmony_ci * instance_div = ~0 for a test, which overflows div_round_up()'s 228bf215546Sopenharmony_ci * addition. 229bf215546Sopenharmony_ci */ 230bf215546Sopenharmony_ci unsigned count = num_instances / instance_div; 231bf215546Sopenharmony_ci if (count * instance_div != num_instances) 232bf215546Sopenharmony_ci count++; 233bf215546Sopenharmony_ci 234bf215546Sopenharmony_ci offset += stride * start_instance; 235bf215546Sopenharmony_ci size = stride * (count - 1) + element_size; 236bf215546Sopenharmony_ci } else { 237bf215546Sopenharmony_ci /* Per-vertex attrib. */ 238bf215546Sopenharmony_ci offset += stride * start_vertex; 239bf215546Sopenharmony_ci size = stride * (num_vertices - 1) + element_size; 240bf215546Sopenharmony_ci } 241bf215546Sopenharmony_ci 242bf215546Sopenharmony_ci const void *ptr = vao->Attrib[binding_index].Pointer; 243bf215546Sopenharmony_ci _mesa_glthread_upload(ctx, (uint8_t*)ptr + offset, 244bf215546Sopenharmony_ci size, &upload_offset, &upload_buffer, NULL); 245bf215546Sopenharmony_ci assert(upload_buffer); 246bf215546Sopenharmony_ci 247bf215546Sopenharmony_ci buffers[num_buffers].buffer = upload_buffer; 248bf215546Sopenharmony_ci buffers[num_buffers].offset = upload_offset - offset; 249bf215546Sopenharmony_ci buffers[num_buffers].original_pointer = ptr; 250bf215546Sopenharmony_ci num_buffers++; 251bf215546Sopenharmony_ci } 252bf215546Sopenharmony_ci 253bf215546Sopenharmony_ci return true; 254bf215546Sopenharmony_ci} 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_ci/* Generic DrawArrays structure NOT supporting user buffers. Ignore the name. */ 257bf215546Sopenharmony_cistruct marshal_cmd_DrawArrays 258bf215546Sopenharmony_ci{ 259bf215546Sopenharmony_ci struct marshal_cmd_base cmd_base; 260bf215546Sopenharmony_ci GLenum mode; 261bf215546Sopenharmony_ci GLint first; 262bf215546Sopenharmony_ci GLsizei count; 263bf215546Sopenharmony_ci GLsizei instance_count; 264bf215546Sopenharmony_ci GLuint baseinstance; 265bf215546Sopenharmony_ci}; 266bf215546Sopenharmony_ci 267bf215546Sopenharmony_ciuint32_t 268bf215546Sopenharmony_ci_mesa_unmarshal_DrawArrays(struct gl_context *ctx, 269bf215546Sopenharmony_ci const struct marshal_cmd_DrawArrays *cmd, 270bf215546Sopenharmony_ci const uint64_t *last) 271bf215546Sopenharmony_ci{ 272bf215546Sopenharmony_ci /* Ignore the function name. We use DISPATCH_CMD_DrawArrays 273bf215546Sopenharmony_ci * for all DrawArrays variants without user buffers, and 274bf215546Sopenharmony_ci * DISPATCH_CMD_DrawArraysInstancedBaseInstance for all DrawArrays 275bf215546Sopenharmony_ci * variants with user buffrs. 276bf215546Sopenharmony_ci */ 277bf215546Sopenharmony_ci const GLenum mode = cmd->mode; 278bf215546Sopenharmony_ci const GLint first = cmd->first; 279bf215546Sopenharmony_ci const GLsizei count = cmd->count; 280bf215546Sopenharmony_ci const GLsizei instance_count = cmd->instance_count; 281bf215546Sopenharmony_ci const GLuint baseinstance = cmd->baseinstance; 282bf215546Sopenharmony_ci 283bf215546Sopenharmony_ci CALL_DrawArraysInstancedBaseInstance(ctx->CurrentServerDispatch, 284bf215546Sopenharmony_ci (mode, first, count, instance_count, 285bf215546Sopenharmony_ci baseinstance)); 286bf215546Sopenharmony_ci return cmd->cmd_base.cmd_size; 287bf215546Sopenharmony_ci} 288bf215546Sopenharmony_ci 289bf215546Sopenharmony_cistatic ALWAYS_INLINE void 290bf215546Sopenharmony_cidraw_arrays_async(struct gl_context *ctx, GLenum mode, GLint first, 291bf215546Sopenharmony_ci GLsizei count, GLsizei instance_count, GLuint baseinstance) 292bf215546Sopenharmony_ci{ 293bf215546Sopenharmony_ci int cmd_size = sizeof(struct marshal_cmd_DrawArrays); 294bf215546Sopenharmony_ci struct marshal_cmd_DrawArrays *cmd = 295bf215546Sopenharmony_ci _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawArrays, cmd_size); 296bf215546Sopenharmony_ci 297bf215546Sopenharmony_ci cmd->mode = mode; 298bf215546Sopenharmony_ci cmd->first = first; 299bf215546Sopenharmony_ci cmd->count = count; 300bf215546Sopenharmony_ci cmd->instance_count = instance_count; 301bf215546Sopenharmony_ci cmd->baseinstance = baseinstance; 302bf215546Sopenharmony_ci} 303bf215546Sopenharmony_ci 304bf215546Sopenharmony_ci/* Generic DrawArrays structure supporting user buffers. Ignore the name. */ 305bf215546Sopenharmony_cistruct marshal_cmd_DrawArraysInstancedBaseInstance 306bf215546Sopenharmony_ci{ 307bf215546Sopenharmony_ci struct marshal_cmd_base cmd_base; 308bf215546Sopenharmony_ci GLenum mode; 309bf215546Sopenharmony_ci GLint first; 310bf215546Sopenharmony_ci GLsizei count; 311bf215546Sopenharmony_ci GLsizei instance_count; 312bf215546Sopenharmony_ci GLuint baseinstance; 313bf215546Sopenharmony_ci GLuint user_buffer_mask; 314bf215546Sopenharmony_ci}; 315bf215546Sopenharmony_ci 316bf215546Sopenharmony_ciuint32_t 317bf215546Sopenharmony_ci_mesa_unmarshal_DrawArraysInstancedBaseInstance(struct gl_context *ctx, 318bf215546Sopenharmony_ci const struct marshal_cmd_DrawArraysInstancedBaseInstance *cmd, 319bf215546Sopenharmony_ci const uint64_t *last) 320bf215546Sopenharmony_ci{ 321bf215546Sopenharmony_ci /* Ignore the function name. We use DISPATCH_CMD_DrawArrays 322bf215546Sopenharmony_ci * for all DrawArrays variants without user buffers, and 323bf215546Sopenharmony_ci * DISPATCH_CMD_DrawArraysInstancedBaseInstance for all DrawArrays 324bf215546Sopenharmony_ci * variants with user buffrs. 325bf215546Sopenharmony_ci */ 326bf215546Sopenharmony_ci const GLenum mode = cmd->mode; 327bf215546Sopenharmony_ci const GLint first = cmd->first; 328bf215546Sopenharmony_ci const GLsizei count = cmd->count; 329bf215546Sopenharmony_ci const GLsizei instance_count = cmd->instance_count; 330bf215546Sopenharmony_ci const GLuint baseinstance = cmd->baseinstance; 331bf215546Sopenharmony_ci const GLuint user_buffer_mask = cmd->user_buffer_mask; 332bf215546Sopenharmony_ci const struct glthread_attrib_binding *buffers = 333bf215546Sopenharmony_ci (const struct glthread_attrib_binding *)(cmd + 1); 334bf215546Sopenharmony_ci 335bf215546Sopenharmony_ci /* Bind uploaded buffers if needed. */ 336bf215546Sopenharmony_ci if (user_buffer_mask) { 337bf215546Sopenharmony_ci _mesa_InternalBindVertexBuffers(ctx, buffers, user_buffer_mask, 338bf215546Sopenharmony_ci false); 339bf215546Sopenharmony_ci } 340bf215546Sopenharmony_ci 341bf215546Sopenharmony_ci CALL_DrawArraysInstancedBaseInstance(ctx->CurrentServerDispatch, 342bf215546Sopenharmony_ci (mode, first, count, instance_count, 343bf215546Sopenharmony_ci baseinstance)); 344bf215546Sopenharmony_ci 345bf215546Sopenharmony_ci /* Restore states. */ 346bf215546Sopenharmony_ci if (user_buffer_mask) { 347bf215546Sopenharmony_ci _mesa_InternalBindVertexBuffers(ctx, buffers, user_buffer_mask, 348bf215546Sopenharmony_ci true); 349bf215546Sopenharmony_ci } 350bf215546Sopenharmony_ci return cmd->cmd_base.cmd_size; 351bf215546Sopenharmony_ci} 352bf215546Sopenharmony_ci 353bf215546Sopenharmony_cistatic ALWAYS_INLINE void 354bf215546Sopenharmony_cidraw_arrays_async_user(struct gl_context *ctx, GLenum mode, GLint first, 355bf215546Sopenharmony_ci GLsizei count, GLsizei instance_count, GLuint baseinstance, 356bf215546Sopenharmony_ci unsigned user_buffer_mask, 357bf215546Sopenharmony_ci const struct glthread_attrib_binding *buffers) 358bf215546Sopenharmony_ci{ 359bf215546Sopenharmony_ci int buffers_size = util_bitcount(user_buffer_mask) * sizeof(buffers[0]); 360bf215546Sopenharmony_ci int cmd_size = sizeof(struct marshal_cmd_DrawArraysInstancedBaseInstance) + 361bf215546Sopenharmony_ci buffers_size; 362bf215546Sopenharmony_ci struct marshal_cmd_DrawArraysInstancedBaseInstance *cmd; 363bf215546Sopenharmony_ci 364bf215546Sopenharmony_ci cmd = _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawArraysInstancedBaseInstance, 365bf215546Sopenharmony_ci cmd_size); 366bf215546Sopenharmony_ci cmd->mode = mode; 367bf215546Sopenharmony_ci cmd->first = first; 368bf215546Sopenharmony_ci cmd->count = count; 369bf215546Sopenharmony_ci cmd->instance_count = instance_count; 370bf215546Sopenharmony_ci cmd->baseinstance = baseinstance; 371bf215546Sopenharmony_ci cmd->user_buffer_mask = user_buffer_mask; 372bf215546Sopenharmony_ci 373bf215546Sopenharmony_ci if (user_buffer_mask) 374bf215546Sopenharmony_ci memcpy(cmd + 1, buffers, buffers_size); 375bf215546Sopenharmony_ci} 376bf215546Sopenharmony_ci 377bf215546Sopenharmony_cistatic ALWAYS_INLINE void 378bf215546Sopenharmony_cidraw_arrays(GLenum mode, GLint first, GLsizei count, GLsizei instance_count, 379bf215546Sopenharmony_ci GLuint baseinstance, bool compiled_into_dlist) 380bf215546Sopenharmony_ci{ 381bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 382bf215546Sopenharmony_ci 383bf215546Sopenharmony_ci struct glthread_vao *vao = ctx->GLThread.CurrentVAO; 384bf215546Sopenharmony_ci unsigned user_buffer_mask = vao->UserPointerMask & vao->BufferEnabled; 385bf215546Sopenharmony_ci 386bf215546Sopenharmony_ci if (compiled_into_dlist && ctx->GLThread.ListMode) { 387bf215546Sopenharmony_ci _mesa_glthread_finish_before(ctx, "DrawArrays"); 388bf215546Sopenharmony_ci /* Use the function that's compiled into a display list. */ 389bf215546Sopenharmony_ci CALL_DrawArrays(ctx->CurrentServerDispatch, (mode, first, count)); 390bf215546Sopenharmony_ci return; 391bf215546Sopenharmony_ci } 392bf215546Sopenharmony_ci 393bf215546Sopenharmony_ci /* Fast path when nothing needs to be done. 394bf215546Sopenharmony_ci * 395bf215546Sopenharmony_ci * This is also an error path. Zero counts should still call the driver 396bf215546Sopenharmony_ci * for possible GL errors. 397bf215546Sopenharmony_ci */ 398bf215546Sopenharmony_ci if (ctx->API == API_OPENGL_CORE || !user_buffer_mask || 399bf215546Sopenharmony_ci count <= 0 || instance_count <= 0) { 400bf215546Sopenharmony_ci draw_arrays_async(ctx, mode, first, count, instance_count, baseinstance); 401bf215546Sopenharmony_ci return; 402bf215546Sopenharmony_ci } 403bf215546Sopenharmony_ci 404bf215546Sopenharmony_ci /* Upload and draw. */ 405bf215546Sopenharmony_ci struct glthread_attrib_binding buffers[VERT_ATTRIB_MAX]; 406bf215546Sopenharmony_ci if (!ctx->GLThread.SupportsNonVBOUploads || 407bf215546Sopenharmony_ci !upload_vertices(ctx, user_buffer_mask, first, count, baseinstance, 408bf215546Sopenharmony_ci instance_count, buffers)) { 409bf215546Sopenharmony_ci _mesa_glthread_finish_before(ctx, "DrawArrays"); 410bf215546Sopenharmony_ci CALL_DrawArraysInstancedBaseInstance(ctx->CurrentServerDispatch, 411bf215546Sopenharmony_ci (mode, first, count, instance_count, 412bf215546Sopenharmony_ci baseinstance)); 413bf215546Sopenharmony_ci return; 414bf215546Sopenharmony_ci } 415bf215546Sopenharmony_ci 416bf215546Sopenharmony_ci draw_arrays_async_user(ctx, mode, first, count, instance_count, baseinstance, 417bf215546Sopenharmony_ci user_buffer_mask, buffers); 418bf215546Sopenharmony_ci} 419bf215546Sopenharmony_ci 420bf215546Sopenharmony_cistruct marshal_cmd_MultiDrawArrays 421bf215546Sopenharmony_ci{ 422bf215546Sopenharmony_ci struct marshal_cmd_base cmd_base; 423bf215546Sopenharmony_ci GLenum mode; 424bf215546Sopenharmony_ci GLsizei draw_count; 425bf215546Sopenharmony_ci GLuint user_buffer_mask; 426bf215546Sopenharmony_ci}; 427bf215546Sopenharmony_ci 428bf215546Sopenharmony_ciuint32_t 429bf215546Sopenharmony_ci_mesa_unmarshal_MultiDrawArrays(struct gl_context *ctx, 430bf215546Sopenharmony_ci const struct marshal_cmd_MultiDrawArrays *cmd, 431bf215546Sopenharmony_ci const uint64_t *last) 432bf215546Sopenharmony_ci{ 433bf215546Sopenharmony_ci const GLenum mode = cmd->mode; 434bf215546Sopenharmony_ci const GLsizei draw_count = cmd->draw_count; 435bf215546Sopenharmony_ci const GLuint user_buffer_mask = cmd->user_buffer_mask; 436bf215546Sopenharmony_ci 437bf215546Sopenharmony_ci const char *variable_data = (const char *)(cmd + 1); 438bf215546Sopenharmony_ci const GLint *first = (GLint *)variable_data; 439bf215546Sopenharmony_ci variable_data += sizeof(GLint) * draw_count; 440bf215546Sopenharmony_ci const GLsizei *count = (GLsizei *)variable_data; 441bf215546Sopenharmony_ci variable_data += sizeof(GLsizei) * draw_count; 442bf215546Sopenharmony_ci const struct glthread_attrib_binding *buffers = 443bf215546Sopenharmony_ci (const struct glthread_attrib_binding *)variable_data; 444bf215546Sopenharmony_ci 445bf215546Sopenharmony_ci /* Bind uploaded buffers if needed. */ 446bf215546Sopenharmony_ci if (user_buffer_mask) { 447bf215546Sopenharmony_ci _mesa_InternalBindVertexBuffers(ctx, buffers, user_buffer_mask, 448bf215546Sopenharmony_ci false); 449bf215546Sopenharmony_ci } 450bf215546Sopenharmony_ci 451bf215546Sopenharmony_ci CALL_MultiDrawArrays(ctx->CurrentServerDispatch, 452bf215546Sopenharmony_ci (mode, first, count, draw_count)); 453bf215546Sopenharmony_ci 454bf215546Sopenharmony_ci /* Restore states. */ 455bf215546Sopenharmony_ci if (user_buffer_mask) { 456bf215546Sopenharmony_ci _mesa_InternalBindVertexBuffers(ctx, buffers, user_buffer_mask, 457bf215546Sopenharmony_ci true); 458bf215546Sopenharmony_ci } 459bf215546Sopenharmony_ci return cmd->cmd_base.cmd_size; 460bf215546Sopenharmony_ci} 461bf215546Sopenharmony_ci 462bf215546Sopenharmony_cistatic ALWAYS_INLINE bool 463bf215546Sopenharmony_cimulti_draw_arrays_async(struct gl_context *ctx, GLenum mode, 464bf215546Sopenharmony_ci const GLint *first, const GLsizei *count, 465bf215546Sopenharmony_ci GLsizei draw_count, unsigned user_buffer_mask, 466bf215546Sopenharmony_ci const struct glthread_attrib_binding *buffers) 467bf215546Sopenharmony_ci{ 468bf215546Sopenharmony_ci int first_size = sizeof(GLint) * draw_count; 469bf215546Sopenharmony_ci int count_size = sizeof(GLsizei) * draw_count; 470bf215546Sopenharmony_ci int buffers_size = util_bitcount(user_buffer_mask) * sizeof(buffers[0]); 471bf215546Sopenharmony_ci int cmd_size = sizeof(struct marshal_cmd_MultiDrawArrays) + 472bf215546Sopenharmony_ci first_size + count_size + buffers_size; 473bf215546Sopenharmony_ci struct marshal_cmd_MultiDrawArrays *cmd; 474bf215546Sopenharmony_ci 475bf215546Sopenharmony_ci /* Make sure cmd can fit the queue buffer */ 476bf215546Sopenharmony_ci if (cmd_size > MARSHAL_MAX_CMD_SIZE) { 477bf215546Sopenharmony_ci return false; 478bf215546Sopenharmony_ci } 479bf215546Sopenharmony_ci 480bf215546Sopenharmony_ci cmd = _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_MultiDrawArrays, 481bf215546Sopenharmony_ci cmd_size); 482bf215546Sopenharmony_ci cmd->mode = mode; 483bf215546Sopenharmony_ci cmd->draw_count = draw_count; 484bf215546Sopenharmony_ci cmd->user_buffer_mask = user_buffer_mask; 485bf215546Sopenharmony_ci 486bf215546Sopenharmony_ci char *variable_data = (char*)(cmd + 1); 487bf215546Sopenharmony_ci memcpy(variable_data, first, first_size); 488bf215546Sopenharmony_ci variable_data += first_size; 489bf215546Sopenharmony_ci memcpy(variable_data, count, count_size); 490bf215546Sopenharmony_ci 491bf215546Sopenharmony_ci if (user_buffer_mask) { 492bf215546Sopenharmony_ci variable_data += count_size; 493bf215546Sopenharmony_ci memcpy(variable_data, buffers, buffers_size); 494bf215546Sopenharmony_ci } 495bf215546Sopenharmony_ci 496bf215546Sopenharmony_ci return true; 497bf215546Sopenharmony_ci} 498bf215546Sopenharmony_ci 499bf215546Sopenharmony_civoid GLAPIENTRY 500bf215546Sopenharmony_ci_mesa_marshal_MultiDrawArrays(GLenum mode, const GLint *first, 501bf215546Sopenharmony_ci const GLsizei *count, GLsizei draw_count) 502bf215546Sopenharmony_ci{ 503bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 504bf215546Sopenharmony_ci 505bf215546Sopenharmony_ci struct glthread_vao *vao = ctx->GLThread.CurrentVAO; 506bf215546Sopenharmony_ci unsigned user_buffer_mask = vao->UserPointerMask & vao->BufferEnabled; 507bf215546Sopenharmony_ci 508bf215546Sopenharmony_ci if (ctx->GLThread.ListMode) 509bf215546Sopenharmony_ci goto sync; 510bf215546Sopenharmony_ci 511bf215546Sopenharmony_ci if (draw_count >= 0 && 512bf215546Sopenharmony_ci (ctx->API == API_OPENGL_CORE || !user_buffer_mask) && 513bf215546Sopenharmony_ci multi_draw_arrays_async(ctx, mode, first, count, draw_count, 0, NULL)) { 514bf215546Sopenharmony_ci return; 515bf215546Sopenharmony_ci } 516bf215546Sopenharmony_ci 517bf215546Sopenharmony_ci /* If the draw count is too high or negative, the queue can't be used. */ 518bf215546Sopenharmony_ci if (!ctx->GLThread.SupportsNonVBOUploads || 519bf215546Sopenharmony_ci draw_count < 0 || draw_count > MARSHAL_MAX_CMD_SIZE / 16) 520bf215546Sopenharmony_ci goto sync; 521bf215546Sopenharmony_ci 522bf215546Sopenharmony_ci unsigned min_index = ~0; 523bf215546Sopenharmony_ci unsigned max_index_exclusive = 0; 524bf215546Sopenharmony_ci 525bf215546Sopenharmony_ci for (unsigned i = 0; i < draw_count; i++) { 526bf215546Sopenharmony_ci GLsizei vertex_count = count[i]; 527bf215546Sopenharmony_ci 528bf215546Sopenharmony_ci if (vertex_count < 0) { 529bf215546Sopenharmony_ci /* Just call the driver to set the error. */ 530bf215546Sopenharmony_ci multi_draw_arrays_async(ctx, mode, first, count, draw_count, 0, NULL); 531bf215546Sopenharmony_ci return; 532bf215546Sopenharmony_ci } 533bf215546Sopenharmony_ci if (vertex_count == 0) 534bf215546Sopenharmony_ci continue; 535bf215546Sopenharmony_ci 536bf215546Sopenharmony_ci min_index = MIN2(min_index, first[i]); 537bf215546Sopenharmony_ci max_index_exclusive = MAX2(max_index_exclusive, first[i] + vertex_count); 538bf215546Sopenharmony_ci } 539bf215546Sopenharmony_ci 540bf215546Sopenharmony_ci unsigned num_vertices = max_index_exclusive - min_index; 541bf215546Sopenharmony_ci if (num_vertices == 0) { 542bf215546Sopenharmony_ci /* Nothing to do, but call the driver to set possible GL errors. */ 543bf215546Sopenharmony_ci multi_draw_arrays_async(ctx, mode, first, count, draw_count, 0, NULL); 544bf215546Sopenharmony_ci return; 545bf215546Sopenharmony_ci } 546bf215546Sopenharmony_ci 547bf215546Sopenharmony_ci /* Upload and draw. */ 548bf215546Sopenharmony_ci struct glthread_attrib_binding buffers[VERT_ATTRIB_MAX]; 549bf215546Sopenharmony_ci if (!upload_vertices(ctx, user_buffer_mask, min_index, num_vertices, 550bf215546Sopenharmony_ci 0, 1, buffers)) 551bf215546Sopenharmony_ci goto sync; 552bf215546Sopenharmony_ci 553bf215546Sopenharmony_ci multi_draw_arrays_async(ctx, mode, first, count, draw_count, 554bf215546Sopenharmony_ci user_buffer_mask, buffers); 555bf215546Sopenharmony_ci return; 556bf215546Sopenharmony_ci 557bf215546Sopenharmony_cisync: 558bf215546Sopenharmony_ci _mesa_glthread_finish_before(ctx, "MultiDrawArrays"); 559bf215546Sopenharmony_ci CALL_MultiDrawArrays(ctx->CurrentServerDispatch, 560bf215546Sopenharmony_ci (mode, first, count, draw_count)); 561bf215546Sopenharmony_ci} 562bf215546Sopenharmony_ci 563bf215546Sopenharmony_ci/* DrawElementsInstancedBaseVertexBaseInstance not supporting user buffers. 564bf215546Sopenharmony_ci * Ignore the name. 565bf215546Sopenharmony_ci */ 566bf215546Sopenharmony_cistruct marshal_cmd_DrawElementsInstancedARB 567bf215546Sopenharmony_ci{ 568bf215546Sopenharmony_ci struct marshal_cmd_base cmd_base; 569bf215546Sopenharmony_ci GLenum mode; 570bf215546Sopenharmony_ci GLenum type; 571bf215546Sopenharmony_ci GLsizei count; 572bf215546Sopenharmony_ci GLsizei instance_count; 573bf215546Sopenharmony_ci GLint basevertex; 574bf215546Sopenharmony_ci GLuint baseinstance; 575bf215546Sopenharmony_ci const GLvoid *indices; 576bf215546Sopenharmony_ci}; 577bf215546Sopenharmony_ci 578bf215546Sopenharmony_ciuint32_t 579bf215546Sopenharmony_ci_mesa_unmarshal_DrawElementsInstancedARB(struct gl_context *ctx, 580bf215546Sopenharmony_ci const struct marshal_cmd_DrawElementsInstancedARB *cmd, 581bf215546Sopenharmony_ci const uint64_t *last) 582bf215546Sopenharmony_ci{ 583bf215546Sopenharmony_ci /* Ignore the function name. We use DISPATCH_CMD_DrawElementsInstanced- 584bf215546Sopenharmony_ci * BaseVertexBaseInstance for all DrawElements variants with user buffers, 585bf215546Sopenharmony_ci * and both DISPATCH_CMD_DrawElementsInstancedARB and DISPATCH_CMD_Draw- 586bf215546Sopenharmony_ci * RangeElementsBaseVertex for all draw elements variants without user 587bf215546Sopenharmony_ci * buffers. 588bf215546Sopenharmony_ci */ 589bf215546Sopenharmony_ci const GLenum mode = cmd->mode; 590bf215546Sopenharmony_ci const GLsizei count = cmd->count; 591bf215546Sopenharmony_ci const GLenum type = cmd->type; 592bf215546Sopenharmony_ci const GLvoid *indices = cmd->indices; 593bf215546Sopenharmony_ci const GLsizei instance_count = cmd->instance_count; 594bf215546Sopenharmony_ci const GLint basevertex = cmd->basevertex; 595bf215546Sopenharmony_ci const GLuint baseinstance = cmd->baseinstance; 596bf215546Sopenharmony_ci 597bf215546Sopenharmony_ci CALL_DrawElementsInstancedBaseVertexBaseInstance(ctx->CurrentServerDispatch, 598bf215546Sopenharmony_ci (mode, count, type, indices, 599bf215546Sopenharmony_ci instance_count, basevertex, 600bf215546Sopenharmony_ci baseinstance)); 601bf215546Sopenharmony_ci return cmd->cmd_base.cmd_size; 602bf215546Sopenharmony_ci} 603bf215546Sopenharmony_ci 604bf215546Sopenharmony_cistruct marshal_cmd_DrawRangeElementsBaseVertex 605bf215546Sopenharmony_ci{ 606bf215546Sopenharmony_ci struct marshal_cmd_base cmd_base; 607bf215546Sopenharmony_ci GLenum mode; 608bf215546Sopenharmony_ci GLenum type; 609bf215546Sopenharmony_ci GLsizei count; 610bf215546Sopenharmony_ci GLint basevertex; 611bf215546Sopenharmony_ci GLuint min_index; 612bf215546Sopenharmony_ci GLuint max_index; 613bf215546Sopenharmony_ci const GLvoid *indices; 614bf215546Sopenharmony_ci}; 615bf215546Sopenharmony_ci 616bf215546Sopenharmony_ciuint32_t 617bf215546Sopenharmony_ci_mesa_unmarshal_DrawRangeElementsBaseVertex(struct gl_context *ctx, 618bf215546Sopenharmony_ci const struct marshal_cmd_DrawRangeElementsBaseVertex *cmd, 619bf215546Sopenharmony_ci const uint64_t *last) 620bf215546Sopenharmony_ci{ 621bf215546Sopenharmony_ci const GLenum mode = cmd->mode; 622bf215546Sopenharmony_ci const GLsizei count = cmd->count; 623bf215546Sopenharmony_ci const GLenum type = cmd->type; 624bf215546Sopenharmony_ci const GLvoid *indices = cmd->indices; 625bf215546Sopenharmony_ci const GLint basevertex = cmd->basevertex; 626bf215546Sopenharmony_ci const GLuint min_index = cmd->min_index; 627bf215546Sopenharmony_ci const GLuint max_index = cmd->max_index; 628bf215546Sopenharmony_ci 629bf215546Sopenharmony_ci CALL_DrawRangeElementsBaseVertex(ctx->CurrentServerDispatch, 630bf215546Sopenharmony_ci (mode, min_index, max_index, count, 631bf215546Sopenharmony_ci type, indices, basevertex)); 632bf215546Sopenharmony_ci return cmd->cmd_base.cmd_size; 633bf215546Sopenharmony_ci} 634bf215546Sopenharmony_ci 635bf215546Sopenharmony_cistatic ALWAYS_INLINE void 636bf215546Sopenharmony_cidraw_elements_async(struct gl_context *ctx, GLenum mode, GLsizei count, 637bf215546Sopenharmony_ci GLenum type, const GLvoid *indices, GLsizei instance_count, 638bf215546Sopenharmony_ci GLint basevertex, GLuint baseinstance, 639bf215546Sopenharmony_ci bool index_bounds_valid, GLuint min_index, GLuint max_index) 640bf215546Sopenharmony_ci{ 641bf215546Sopenharmony_ci if (index_bounds_valid) { 642bf215546Sopenharmony_ci int cmd_size = sizeof(struct marshal_cmd_DrawRangeElementsBaseVertex); 643bf215546Sopenharmony_ci struct marshal_cmd_DrawRangeElementsBaseVertex *cmd = 644bf215546Sopenharmony_ci _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawRangeElementsBaseVertex, cmd_size); 645bf215546Sopenharmony_ci 646bf215546Sopenharmony_ci cmd->mode = mode; 647bf215546Sopenharmony_ci cmd->count = count; 648bf215546Sopenharmony_ci cmd->type = type; 649bf215546Sopenharmony_ci cmd->indices = indices; 650bf215546Sopenharmony_ci cmd->basevertex = basevertex; 651bf215546Sopenharmony_ci cmd->min_index = min_index; 652bf215546Sopenharmony_ci cmd->max_index = max_index; 653bf215546Sopenharmony_ci } else { 654bf215546Sopenharmony_ci int cmd_size = sizeof(struct marshal_cmd_DrawElementsInstancedARB); 655bf215546Sopenharmony_ci struct marshal_cmd_DrawElementsInstancedARB *cmd = 656bf215546Sopenharmony_ci _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawElementsInstancedARB, cmd_size); 657bf215546Sopenharmony_ci 658bf215546Sopenharmony_ci cmd->mode = mode; 659bf215546Sopenharmony_ci cmd->count = count; 660bf215546Sopenharmony_ci cmd->type = type; 661bf215546Sopenharmony_ci cmd->indices = indices; 662bf215546Sopenharmony_ci cmd->instance_count = instance_count; 663bf215546Sopenharmony_ci cmd->basevertex = basevertex; 664bf215546Sopenharmony_ci cmd->baseinstance = baseinstance; 665bf215546Sopenharmony_ci } 666bf215546Sopenharmony_ci} 667bf215546Sopenharmony_ci 668bf215546Sopenharmony_cistruct marshal_cmd_DrawElementsInstancedBaseVertexBaseInstance 669bf215546Sopenharmony_ci{ 670bf215546Sopenharmony_ci struct marshal_cmd_base cmd_base; 671bf215546Sopenharmony_ci bool index_bounds_valid; 672bf215546Sopenharmony_ci GLenum mode; 673bf215546Sopenharmony_ci GLenum type; 674bf215546Sopenharmony_ci GLsizei count; 675bf215546Sopenharmony_ci GLsizei instance_count; 676bf215546Sopenharmony_ci GLint basevertex; 677bf215546Sopenharmony_ci GLuint baseinstance; 678bf215546Sopenharmony_ci GLuint min_index; 679bf215546Sopenharmony_ci GLuint max_index; 680bf215546Sopenharmony_ci GLuint user_buffer_mask; 681bf215546Sopenharmony_ci const GLvoid *indices; 682bf215546Sopenharmony_ci struct gl_buffer_object *index_buffer; 683bf215546Sopenharmony_ci}; 684bf215546Sopenharmony_ci 685bf215546Sopenharmony_ciuint32_t 686bf215546Sopenharmony_ci_mesa_unmarshal_DrawElementsInstancedBaseVertexBaseInstance(struct gl_context *ctx, 687bf215546Sopenharmony_ci const struct marshal_cmd_DrawElementsInstancedBaseVertexBaseInstance *cmd, 688bf215546Sopenharmony_ci const uint64_t *last) 689bf215546Sopenharmony_ci{ 690bf215546Sopenharmony_ci /* Ignore the function name. We use DISPATCH_CMD_DrawElementsInstanced- 691bf215546Sopenharmony_ci * BaseVertexBaseInstance for all DrawElements variants with user buffers, 692bf215546Sopenharmony_ci * and both DISPATCH_CMD_DrawElementsInstancedARB and DISPATCH_CMD_Draw- 693bf215546Sopenharmony_ci * RangeElementsBaseVertex for all draw elements variants without user 694bf215546Sopenharmony_ci * buffers. 695bf215546Sopenharmony_ci */ 696bf215546Sopenharmony_ci const GLenum mode = cmd->mode; 697bf215546Sopenharmony_ci const GLsizei count = cmd->count; 698bf215546Sopenharmony_ci const GLenum type = cmd->type; 699bf215546Sopenharmony_ci const GLvoid *indices = cmd->indices; 700bf215546Sopenharmony_ci const GLsizei instance_count = cmd->instance_count; 701bf215546Sopenharmony_ci const GLint basevertex = cmd->basevertex; 702bf215546Sopenharmony_ci const GLuint baseinstance = cmd->baseinstance; 703bf215546Sopenharmony_ci const GLuint min_index = cmd->min_index; 704bf215546Sopenharmony_ci const GLuint max_index = cmd->max_index; 705bf215546Sopenharmony_ci const GLuint user_buffer_mask = cmd->user_buffer_mask; 706bf215546Sopenharmony_ci struct gl_buffer_object *index_buffer = cmd->index_buffer; 707bf215546Sopenharmony_ci const struct glthread_attrib_binding *buffers = 708bf215546Sopenharmony_ci (const struct glthread_attrib_binding *)(cmd + 1); 709bf215546Sopenharmony_ci 710bf215546Sopenharmony_ci /* Bind uploaded buffers if needed. */ 711bf215546Sopenharmony_ci if (user_buffer_mask) { 712bf215546Sopenharmony_ci _mesa_InternalBindVertexBuffers(ctx, buffers, user_buffer_mask, 713bf215546Sopenharmony_ci false); 714bf215546Sopenharmony_ci } 715bf215546Sopenharmony_ci if (index_buffer) { 716bf215546Sopenharmony_ci _mesa_InternalBindElementBuffer(ctx, index_buffer); 717bf215546Sopenharmony_ci } 718bf215546Sopenharmony_ci 719bf215546Sopenharmony_ci /* Draw. */ 720bf215546Sopenharmony_ci if (cmd->index_bounds_valid && instance_count == 1 && baseinstance == 0) { 721bf215546Sopenharmony_ci CALL_DrawRangeElementsBaseVertex(ctx->CurrentServerDispatch, 722bf215546Sopenharmony_ci (mode, min_index, max_index, count, 723bf215546Sopenharmony_ci type, indices, basevertex)); 724bf215546Sopenharmony_ci } else { 725bf215546Sopenharmony_ci CALL_DrawElementsInstancedBaseVertexBaseInstance(ctx->CurrentServerDispatch, 726bf215546Sopenharmony_ci (mode, count, type, indices, 727bf215546Sopenharmony_ci instance_count, basevertex, 728bf215546Sopenharmony_ci baseinstance)); 729bf215546Sopenharmony_ci } 730bf215546Sopenharmony_ci 731bf215546Sopenharmony_ci /* Restore states. */ 732bf215546Sopenharmony_ci if (index_buffer) { 733bf215546Sopenharmony_ci _mesa_InternalBindElementBuffer(ctx, NULL); 734bf215546Sopenharmony_ci } 735bf215546Sopenharmony_ci if (user_buffer_mask) { 736bf215546Sopenharmony_ci _mesa_InternalBindVertexBuffers(ctx, buffers, user_buffer_mask, 737bf215546Sopenharmony_ci true); 738bf215546Sopenharmony_ci } 739bf215546Sopenharmony_ci return cmd->cmd_base.cmd_size; 740bf215546Sopenharmony_ci} 741bf215546Sopenharmony_ci 742bf215546Sopenharmony_cistatic ALWAYS_INLINE void 743bf215546Sopenharmony_cidraw_elements_async_user(struct gl_context *ctx, GLenum mode, GLsizei count, 744bf215546Sopenharmony_ci GLenum type, const GLvoid *indices, GLsizei instance_count, 745bf215546Sopenharmony_ci GLint basevertex, GLuint baseinstance, 746bf215546Sopenharmony_ci bool index_bounds_valid, GLuint min_index, GLuint max_index, 747bf215546Sopenharmony_ci struct gl_buffer_object *index_buffer, 748bf215546Sopenharmony_ci unsigned user_buffer_mask, 749bf215546Sopenharmony_ci const struct glthread_attrib_binding *buffers) 750bf215546Sopenharmony_ci{ 751bf215546Sopenharmony_ci int buffers_size = util_bitcount(user_buffer_mask) * sizeof(buffers[0]); 752bf215546Sopenharmony_ci int cmd_size = sizeof(struct marshal_cmd_DrawElementsInstancedBaseVertexBaseInstance) + 753bf215546Sopenharmony_ci buffers_size; 754bf215546Sopenharmony_ci struct marshal_cmd_DrawElementsInstancedBaseVertexBaseInstance *cmd; 755bf215546Sopenharmony_ci 756bf215546Sopenharmony_ci cmd = _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawElementsInstancedBaseVertexBaseInstance, cmd_size); 757bf215546Sopenharmony_ci cmd->mode = mode; 758bf215546Sopenharmony_ci cmd->count = count; 759bf215546Sopenharmony_ci cmd->type = type; 760bf215546Sopenharmony_ci cmd->indices = indices; 761bf215546Sopenharmony_ci cmd->instance_count = instance_count; 762bf215546Sopenharmony_ci cmd->basevertex = basevertex; 763bf215546Sopenharmony_ci cmd->baseinstance = baseinstance; 764bf215546Sopenharmony_ci cmd->min_index = min_index; 765bf215546Sopenharmony_ci cmd->max_index = max_index; 766bf215546Sopenharmony_ci cmd->user_buffer_mask = user_buffer_mask; 767bf215546Sopenharmony_ci cmd->index_bounds_valid = index_bounds_valid; 768bf215546Sopenharmony_ci cmd->index_buffer = index_buffer; 769bf215546Sopenharmony_ci 770bf215546Sopenharmony_ci if (user_buffer_mask) 771bf215546Sopenharmony_ci memcpy(cmd + 1, buffers, buffers_size); 772bf215546Sopenharmony_ci} 773bf215546Sopenharmony_ci 774bf215546Sopenharmony_cistatic void 775bf215546Sopenharmony_cidraw_elements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, 776bf215546Sopenharmony_ci GLsizei instance_count, GLint basevertex, GLuint baseinstance, 777bf215546Sopenharmony_ci bool index_bounds_valid, GLuint min_index, GLuint max_index, 778bf215546Sopenharmony_ci bool compiled_into_dlist) 779bf215546Sopenharmony_ci{ 780bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 781bf215546Sopenharmony_ci 782bf215546Sopenharmony_ci struct glthread_vao *vao = ctx->GLThread.CurrentVAO; 783bf215546Sopenharmony_ci unsigned user_buffer_mask = vao->UserPointerMask & vao->BufferEnabled; 784bf215546Sopenharmony_ci bool has_user_indices = vao->CurrentElementBufferName == 0; 785bf215546Sopenharmony_ci 786bf215546Sopenharmony_ci if (compiled_into_dlist && ctx->GLThread.ListMode) 787bf215546Sopenharmony_ci goto sync; 788bf215546Sopenharmony_ci 789bf215546Sopenharmony_ci /* Fast path when nothing needs to be done. 790bf215546Sopenharmony_ci * 791bf215546Sopenharmony_ci * This is also an error path. Zero counts should still call the driver 792bf215546Sopenharmony_ci * for possible GL errors. 793bf215546Sopenharmony_ci */ 794bf215546Sopenharmony_ci if (ctx->API == API_OPENGL_CORE || 795bf215546Sopenharmony_ci count <= 0 || instance_count <= 0 || max_index < min_index || 796bf215546Sopenharmony_ci !is_index_type_valid(type) || 797bf215546Sopenharmony_ci (!user_buffer_mask && !has_user_indices)) { 798bf215546Sopenharmony_ci draw_elements_async(ctx, mode, count, type, indices, instance_count, 799bf215546Sopenharmony_ci basevertex, baseinstance, index_bounds_valid, 800bf215546Sopenharmony_ci min_index, max_index); 801bf215546Sopenharmony_ci return; 802bf215546Sopenharmony_ci } 803bf215546Sopenharmony_ci 804bf215546Sopenharmony_ci if (!ctx->GLThread.SupportsNonVBOUploads) 805bf215546Sopenharmony_ci goto sync; 806bf215546Sopenharmony_ci 807bf215546Sopenharmony_ci bool need_index_bounds = user_buffer_mask & ~vao->NonZeroDivisorMask; 808bf215546Sopenharmony_ci unsigned index_size = get_index_size(type); 809bf215546Sopenharmony_ci 810bf215546Sopenharmony_ci if (need_index_bounds && !index_bounds_valid) { 811bf215546Sopenharmony_ci /* Sync if indices come from a buffer and vertices come from memory 812bf215546Sopenharmony_ci * and index bounds are not valid. 813bf215546Sopenharmony_ci * 814bf215546Sopenharmony_ci * We would have to map the indices to compute the index bounds, and 815bf215546Sopenharmony_ci * for that we would have to sync anyway. 816bf215546Sopenharmony_ci */ 817bf215546Sopenharmony_ci if (!has_user_indices) 818bf215546Sopenharmony_ci goto sync; 819bf215546Sopenharmony_ci 820bf215546Sopenharmony_ci /* Compute the index bounds. */ 821bf215546Sopenharmony_ci min_index = ~0; 822bf215546Sopenharmony_ci max_index = 0; 823bf215546Sopenharmony_ci vbo_get_minmax_index_mapped(count, index_size, 824bf215546Sopenharmony_ci ctx->GLThread._RestartIndex[index_size - 1], 825bf215546Sopenharmony_ci ctx->GLThread._PrimitiveRestart, indices, 826bf215546Sopenharmony_ci &min_index, &max_index); 827bf215546Sopenharmony_ci index_bounds_valid = true; 828bf215546Sopenharmony_ci } 829bf215546Sopenharmony_ci 830bf215546Sopenharmony_ci unsigned start_vertex = min_index + basevertex; 831bf215546Sopenharmony_ci unsigned num_vertices = max_index + 1 - min_index; 832bf215546Sopenharmony_ci 833bf215546Sopenharmony_ci /* If there is too much data to upload, sync and let the driver unroll 834bf215546Sopenharmony_ci * indices. */ 835bf215546Sopenharmony_ci if (util_is_vbo_upload_ratio_too_large(count, num_vertices)) 836bf215546Sopenharmony_ci goto sync; 837bf215546Sopenharmony_ci 838bf215546Sopenharmony_ci struct glthread_attrib_binding buffers[VERT_ATTRIB_MAX]; 839bf215546Sopenharmony_ci if (user_buffer_mask && 840bf215546Sopenharmony_ci !upload_vertices(ctx, user_buffer_mask, start_vertex, num_vertices, 841bf215546Sopenharmony_ci baseinstance, instance_count, buffers)) 842bf215546Sopenharmony_ci goto sync; 843bf215546Sopenharmony_ci 844bf215546Sopenharmony_ci /* Upload indices. */ 845bf215546Sopenharmony_ci struct gl_buffer_object *index_buffer = NULL; 846bf215546Sopenharmony_ci if (has_user_indices) 847bf215546Sopenharmony_ci index_buffer = upload_indices(ctx, count, index_size, &indices); 848bf215546Sopenharmony_ci 849bf215546Sopenharmony_ci /* Draw asynchronously. */ 850bf215546Sopenharmony_ci draw_elements_async_user(ctx, mode, count, type, indices, instance_count, 851bf215546Sopenharmony_ci basevertex, baseinstance, index_bounds_valid, 852bf215546Sopenharmony_ci min_index, max_index, index_buffer, 853bf215546Sopenharmony_ci user_buffer_mask, buffers); 854bf215546Sopenharmony_ci return; 855bf215546Sopenharmony_ci 856bf215546Sopenharmony_cisync: 857bf215546Sopenharmony_ci _mesa_glthread_finish_before(ctx, "DrawElements"); 858bf215546Sopenharmony_ci 859bf215546Sopenharmony_ci if (compiled_into_dlist && ctx->GLThread.ListMode) { 860bf215546Sopenharmony_ci /* Only use the ones that are compiled into display lists. */ 861bf215546Sopenharmony_ci if (basevertex) { 862bf215546Sopenharmony_ci CALL_DrawElementsBaseVertex(ctx->CurrentServerDispatch, 863bf215546Sopenharmony_ci (mode, count, type, indices, basevertex)); 864bf215546Sopenharmony_ci } else if (index_bounds_valid) { 865bf215546Sopenharmony_ci CALL_DrawRangeElements(ctx->CurrentServerDispatch, 866bf215546Sopenharmony_ci (mode, min_index, max_index, count, type, indices)); 867bf215546Sopenharmony_ci } else { 868bf215546Sopenharmony_ci CALL_DrawElements(ctx->CurrentServerDispatch, (mode, count, type, indices)); 869bf215546Sopenharmony_ci } 870bf215546Sopenharmony_ci } else if (index_bounds_valid && instance_count == 1 && baseinstance == 0) { 871bf215546Sopenharmony_ci CALL_DrawRangeElementsBaseVertex(ctx->CurrentServerDispatch, 872bf215546Sopenharmony_ci (mode, min_index, max_index, count, 873bf215546Sopenharmony_ci type, indices, basevertex)); 874bf215546Sopenharmony_ci } else { 875bf215546Sopenharmony_ci CALL_DrawElementsInstancedBaseVertexBaseInstance(ctx->CurrentServerDispatch, 876bf215546Sopenharmony_ci (mode, count, type, indices, 877bf215546Sopenharmony_ci instance_count, basevertex, 878bf215546Sopenharmony_ci baseinstance)); 879bf215546Sopenharmony_ci } 880bf215546Sopenharmony_ci} 881bf215546Sopenharmony_ci 882bf215546Sopenharmony_cistruct marshal_cmd_MultiDrawElementsBaseVertex 883bf215546Sopenharmony_ci{ 884bf215546Sopenharmony_ci struct marshal_cmd_base cmd_base; 885bf215546Sopenharmony_ci bool has_base_vertex; 886bf215546Sopenharmony_ci GLenum mode; 887bf215546Sopenharmony_ci GLenum type; 888bf215546Sopenharmony_ci GLsizei draw_count; 889bf215546Sopenharmony_ci GLuint user_buffer_mask; 890bf215546Sopenharmony_ci struct gl_buffer_object *index_buffer; 891bf215546Sopenharmony_ci}; 892bf215546Sopenharmony_ci 893bf215546Sopenharmony_ciuint32_t 894bf215546Sopenharmony_ci_mesa_unmarshal_MultiDrawElementsBaseVertex(struct gl_context *ctx, 895bf215546Sopenharmony_ci const struct marshal_cmd_MultiDrawElementsBaseVertex *cmd, 896bf215546Sopenharmony_ci const uint64_t *last) 897bf215546Sopenharmony_ci{ 898bf215546Sopenharmony_ci const GLenum mode = cmd->mode; 899bf215546Sopenharmony_ci const GLenum type = cmd->type; 900bf215546Sopenharmony_ci const GLsizei draw_count = cmd->draw_count; 901bf215546Sopenharmony_ci const GLuint user_buffer_mask = cmd->user_buffer_mask; 902bf215546Sopenharmony_ci struct gl_buffer_object *index_buffer = cmd->index_buffer; 903bf215546Sopenharmony_ci const bool has_base_vertex = cmd->has_base_vertex; 904bf215546Sopenharmony_ci 905bf215546Sopenharmony_ci const char *variable_data = (const char *)(cmd + 1); 906bf215546Sopenharmony_ci const GLsizei *count = (GLsizei *)variable_data; 907bf215546Sopenharmony_ci variable_data += sizeof(GLsizei) * draw_count; 908bf215546Sopenharmony_ci const GLvoid *const *indices = (const GLvoid *const *)variable_data; 909bf215546Sopenharmony_ci variable_data += sizeof(const GLvoid *const *) * draw_count; 910bf215546Sopenharmony_ci const GLsizei *basevertex = NULL; 911bf215546Sopenharmony_ci if (has_base_vertex) { 912bf215546Sopenharmony_ci basevertex = (GLsizei *)variable_data; 913bf215546Sopenharmony_ci variable_data += sizeof(GLsizei) * draw_count; 914bf215546Sopenharmony_ci } 915bf215546Sopenharmony_ci const struct glthread_attrib_binding *buffers = 916bf215546Sopenharmony_ci (const struct glthread_attrib_binding *)variable_data; 917bf215546Sopenharmony_ci 918bf215546Sopenharmony_ci /* Bind uploaded buffers if needed. */ 919bf215546Sopenharmony_ci if (user_buffer_mask) { 920bf215546Sopenharmony_ci _mesa_InternalBindVertexBuffers(ctx, buffers, user_buffer_mask, 921bf215546Sopenharmony_ci false); 922bf215546Sopenharmony_ci } 923bf215546Sopenharmony_ci if (index_buffer) { 924bf215546Sopenharmony_ci _mesa_InternalBindElementBuffer(ctx, index_buffer); 925bf215546Sopenharmony_ci } 926bf215546Sopenharmony_ci 927bf215546Sopenharmony_ci /* Draw. */ 928bf215546Sopenharmony_ci if (has_base_vertex) { 929bf215546Sopenharmony_ci CALL_MultiDrawElementsBaseVertex(ctx->CurrentServerDispatch, 930bf215546Sopenharmony_ci (mode, count, type, indices, draw_count, 931bf215546Sopenharmony_ci basevertex)); 932bf215546Sopenharmony_ci } else { 933bf215546Sopenharmony_ci CALL_MultiDrawElementsEXT(ctx->CurrentServerDispatch, 934bf215546Sopenharmony_ci (mode, count, type, indices, draw_count)); 935bf215546Sopenharmony_ci } 936bf215546Sopenharmony_ci 937bf215546Sopenharmony_ci /* Restore states. */ 938bf215546Sopenharmony_ci if (index_buffer) { 939bf215546Sopenharmony_ci _mesa_InternalBindElementBuffer(ctx, NULL); 940bf215546Sopenharmony_ci } 941bf215546Sopenharmony_ci if (user_buffer_mask) { 942bf215546Sopenharmony_ci _mesa_InternalBindVertexBuffers(ctx, buffers, user_buffer_mask, 943bf215546Sopenharmony_ci true); 944bf215546Sopenharmony_ci } 945bf215546Sopenharmony_ci return cmd->cmd_base.cmd_size; 946bf215546Sopenharmony_ci} 947bf215546Sopenharmony_ci 948bf215546Sopenharmony_cistatic ALWAYS_INLINE bool 949bf215546Sopenharmony_cimulti_draw_elements_async(struct gl_context *ctx, GLenum mode, 950bf215546Sopenharmony_ci const GLsizei *count, GLenum type, 951bf215546Sopenharmony_ci const GLvoid *const *indices, GLsizei draw_count, 952bf215546Sopenharmony_ci const GLsizei *basevertex, 953bf215546Sopenharmony_ci struct gl_buffer_object *index_buffer, 954bf215546Sopenharmony_ci unsigned user_buffer_mask, 955bf215546Sopenharmony_ci const struct glthread_attrib_binding *buffers) 956bf215546Sopenharmony_ci{ 957bf215546Sopenharmony_ci int count_size = sizeof(GLsizei) * draw_count; 958bf215546Sopenharmony_ci int indices_size = sizeof(indices[0]) * draw_count; 959bf215546Sopenharmony_ci int basevertex_size = basevertex ? sizeof(GLsizei) * draw_count : 0; 960bf215546Sopenharmony_ci int buffers_size = util_bitcount(user_buffer_mask) * sizeof(buffers[0]); 961bf215546Sopenharmony_ci int cmd_size = sizeof(struct marshal_cmd_MultiDrawElementsBaseVertex) + 962bf215546Sopenharmony_ci count_size + indices_size + basevertex_size + buffers_size; 963bf215546Sopenharmony_ci struct marshal_cmd_MultiDrawElementsBaseVertex *cmd; 964bf215546Sopenharmony_ci 965bf215546Sopenharmony_ci /* Make sure cmd can fit the queue buffer */ 966bf215546Sopenharmony_ci if (cmd_size > MARSHAL_MAX_CMD_SIZE) { 967bf215546Sopenharmony_ci return false; 968bf215546Sopenharmony_ci } 969bf215546Sopenharmony_ci 970bf215546Sopenharmony_ci cmd = _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_MultiDrawElementsBaseVertex, cmd_size); 971bf215546Sopenharmony_ci cmd->mode = mode; 972bf215546Sopenharmony_ci cmd->type = type; 973bf215546Sopenharmony_ci cmd->draw_count = draw_count; 974bf215546Sopenharmony_ci cmd->user_buffer_mask = user_buffer_mask; 975bf215546Sopenharmony_ci cmd->index_buffer = index_buffer; 976bf215546Sopenharmony_ci cmd->has_base_vertex = basevertex != NULL; 977bf215546Sopenharmony_ci 978bf215546Sopenharmony_ci char *variable_data = (char*)(cmd + 1); 979bf215546Sopenharmony_ci memcpy(variable_data, count, count_size); 980bf215546Sopenharmony_ci variable_data += count_size; 981bf215546Sopenharmony_ci memcpy(variable_data, indices, indices_size); 982bf215546Sopenharmony_ci variable_data += indices_size; 983bf215546Sopenharmony_ci 984bf215546Sopenharmony_ci if (basevertex) { 985bf215546Sopenharmony_ci memcpy(variable_data, basevertex, basevertex_size); 986bf215546Sopenharmony_ci variable_data += basevertex_size; 987bf215546Sopenharmony_ci } 988bf215546Sopenharmony_ci 989bf215546Sopenharmony_ci if (user_buffer_mask) 990bf215546Sopenharmony_ci memcpy(variable_data, buffers, buffers_size); 991bf215546Sopenharmony_ci 992bf215546Sopenharmony_ci return true; 993bf215546Sopenharmony_ci} 994bf215546Sopenharmony_ci 995bf215546Sopenharmony_civoid GLAPIENTRY 996bf215546Sopenharmony_ci_mesa_marshal_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count, 997bf215546Sopenharmony_ci GLenum type, 998bf215546Sopenharmony_ci const GLvoid *const *indices, 999bf215546Sopenharmony_ci GLsizei draw_count, 1000bf215546Sopenharmony_ci const GLsizei *basevertex) 1001bf215546Sopenharmony_ci{ 1002bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 1003bf215546Sopenharmony_ci 1004bf215546Sopenharmony_ci struct glthread_vao *vao = ctx->GLThread.CurrentVAO; 1005bf215546Sopenharmony_ci unsigned user_buffer_mask = vao->UserPointerMask & vao->BufferEnabled; 1006bf215546Sopenharmony_ci bool has_user_indices = vao->CurrentElementBufferName == 0; 1007bf215546Sopenharmony_ci 1008bf215546Sopenharmony_ci if (ctx->GLThread.ListMode) 1009bf215546Sopenharmony_ci goto sync; 1010bf215546Sopenharmony_ci 1011bf215546Sopenharmony_ci /* Fast path when nothing needs to be done. */ 1012bf215546Sopenharmony_ci if (draw_count >= 0 && 1013bf215546Sopenharmony_ci (ctx->API == API_OPENGL_CORE || 1014bf215546Sopenharmony_ci !is_index_type_valid(type) || 1015bf215546Sopenharmony_ci (!user_buffer_mask && !has_user_indices))) { 1016bf215546Sopenharmony_ci if (multi_draw_elements_async(ctx, mode, count, type, indices, 1017bf215546Sopenharmony_ci draw_count, basevertex, NULL, 0, NULL)) 1018bf215546Sopenharmony_ci return; 1019bf215546Sopenharmony_ci } 1020bf215546Sopenharmony_ci 1021bf215546Sopenharmony_ci bool need_index_bounds = user_buffer_mask & ~vao->NonZeroDivisorMask; 1022bf215546Sopenharmony_ci 1023bf215546Sopenharmony_ci /* If the draw count is too high or negative, the queue can't be used. 1024bf215546Sopenharmony_ci * 1025bf215546Sopenharmony_ci * Sync if indices come from a buffer and vertices come from memory 1026bf215546Sopenharmony_ci * and index bounds are not valid. We would have to map the indices 1027bf215546Sopenharmony_ci * to compute the index bounds, and for that we would have to sync anyway. 1028bf215546Sopenharmony_ci */ 1029bf215546Sopenharmony_ci if (!ctx->GLThread.SupportsNonVBOUploads || 1030bf215546Sopenharmony_ci draw_count < 0 || draw_count > MARSHAL_MAX_CMD_SIZE / 32 || 1031bf215546Sopenharmony_ci (need_index_bounds && !has_user_indices)) 1032bf215546Sopenharmony_ci goto sync; 1033bf215546Sopenharmony_ci 1034bf215546Sopenharmony_ci unsigned index_size = get_index_size(type); 1035bf215546Sopenharmony_ci unsigned min_index = ~0; 1036bf215546Sopenharmony_ci unsigned max_index = 0; 1037bf215546Sopenharmony_ci unsigned total_count = 0; 1038bf215546Sopenharmony_ci unsigned num_vertices = 0; 1039bf215546Sopenharmony_ci 1040bf215546Sopenharmony_ci /* This is always true if there is per-vertex data that needs to be 1041bf215546Sopenharmony_ci * uploaded. 1042bf215546Sopenharmony_ci */ 1043bf215546Sopenharmony_ci if (need_index_bounds) { 1044bf215546Sopenharmony_ci /* Compute the index bounds. */ 1045bf215546Sopenharmony_ci for (unsigned i = 0; i < draw_count; i++) { 1046bf215546Sopenharmony_ci GLsizei vertex_count = count[i]; 1047bf215546Sopenharmony_ci 1048bf215546Sopenharmony_ci if (vertex_count < 0) { 1049bf215546Sopenharmony_ci /* Just call the driver to set the error. */ 1050bf215546Sopenharmony_ci multi_draw_elements_async(ctx, mode, count, type, indices, draw_count, 1051bf215546Sopenharmony_ci basevertex, NULL, 0, NULL); 1052bf215546Sopenharmony_ci return; 1053bf215546Sopenharmony_ci } 1054bf215546Sopenharmony_ci if (vertex_count == 0) 1055bf215546Sopenharmony_ci continue; 1056bf215546Sopenharmony_ci 1057bf215546Sopenharmony_ci unsigned min = ~0, max = 0; 1058bf215546Sopenharmony_ci vbo_get_minmax_index_mapped(vertex_count, index_size, 1059bf215546Sopenharmony_ci ctx->GLThread._RestartIndex[index_size - 1], 1060bf215546Sopenharmony_ci ctx->GLThread._PrimitiveRestart, indices[i], 1061bf215546Sopenharmony_ci &min, &max); 1062bf215546Sopenharmony_ci if (basevertex) { 1063bf215546Sopenharmony_ci min += basevertex[i]; 1064bf215546Sopenharmony_ci max += basevertex[i]; 1065bf215546Sopenharmony_ci } 1066bf215546Sopenharmony_ci min_index = MIN2(min_index, min); 1067bf215546Sopenharmony_ci max_index = MAX2(max_index, max); 1068bf215546Sopenharmony_ci total_count += vertex_count; 1069bf215546Sopenharmony_ci } 1070bf215546Sopenharmony_ci 1071bf215546Sopenharmony_ci num_vertices = max_index + 1 - min_index; 1072bf215546Sopenharmony_ci 1073bf215546Sopenharmony_ci if (total_count == 0 || num_vertices == 0) { 1074bf215546Sopenharmony_ci /* Nothing to do, but call the driver to set possible GL errors. */ 1075bf215546Sopenharmony_ci multi_draw_elements_async(ctx, mode, count, type, indices, draw_count, 1076bf215546Sopenharmony_ci basevertex, NULL, 0, NULL); 1077bf215546Sopenharmony_ci return; 1078bf215546Sopenharmony_ci } 1079bf215546Sopenharmony_ci 1080bf215546Sopenharmony_ci /* If there is too much data to upload, sync and let the driver unroll 1081bf215546Sopenharmony_ci * indices. */ 1082bf215546Sopenharmony_ci if (util_is_vbo_upload_ratio_too_large(total_count, num_vertices)) 1083bf215546Sopenharmony_ci goto sync; 1084bf215546Sopenharmony_ci } else if (has_user_indices) { 1085bf215546Sopenharmony_ci /* Only compute total_count for the upload of indices. */ 1086bf215546Sopenharmony_ci for (unsigned i = 0; i < draw_count; i++) { 1087bf215546Sopenharmony_ci GLsizei vertex_count = count[i]; 1088bf215546Sopenharmony_ci 1089bf215546Sopenharmony_ci if (vertex_count < 0) { 1090bf215546Sopenharmony_ci /* Just call the driver to set the error. */ 1091bf215546Sopenharmony_ci multi_draw_elements_async(ctx, mode, count, type, indices, draw_count, 1092bf215546Sopenharmony_ci basevertex, NULL, 0, NULL); 1093bf215546Sopenharmony_ci return; 1094bf215546Sopenharmony_ci } 1095bf215546Sopenharmony_ci if (vertex_count == 0) 1096bf215546Sopenharmony_ci continue; 1097bf215546Sopenharmony_ci 1098bf215546Sopenharmony_ci total_count += vertex_count; 1099bf215546Sopenharmony_ci } 1100bf215546Sopenharmony_ci 1101bf215546Sopenharmony_ci if (total_count == 0) { 1102bf215546Sopenharmony_ci /* Nothing to do, but call the driver to set possible GL errors. */ 1103bf215546Sopenharmony_ci multi_draw_elements_async(ctx, mode, count, type, indices, draw_count, 1104bf215546Sopenharmony_ci basevertex, NULL, 0, NULL); 1105bf215546Sopenharmony_ci return; 1106bf215546Sopenharmony_ci } 1107bf215546Sopenharmony_ci } 1108bf215546Sopenharmony_ci 1109bf215546Sopenharmony_ci /* Upload vertices. */ 1110bf215546Sopenharmony_ci struct glthread_attrib_binding buffers[VERT_ATTRIB_MAX]; 1111bf215546Sopenharmony_ci if (user_buffer_mask && 1112bf215546Sopenharmony_ci !upload_vertices(ctx, user_buffer_mask, min_index, num_vertices, 1113bf215546Sopenharmony_ci 0, 1, buffers)) 1114bf215546Sopenharmony_ci goto sync; 1115bf215546Sopenharmony_ci 1116bf215546Sopenharmony_ci /* Upload indices. */ 1117bf215546Sopenharmony_ci struct gl_buffer_object *index_buffer = NULL; 1118bf215546Sopenharmony_ci if (has_user_indices) { 1119bf215546Sopenharmony_ci const GLvoid **out_indices = alloca(sizeof(indices[0]) * draw_count); 1120bf215546Sopenharmony_ci 1121bf215546Sopenharmony_ci index_buffer = upload_multi_indices(ctx, total_count, index_size, 1122bf215546Sopenharmony_ci draw_count, count, indices, 1123bf215546Sopenharmony_ci out_indices); 1124bf215546Sopenharmony_ci indices = out_indices; 1125bf215546Sopenharmony_ci } 1126bf215546Sopenharmony_ci 1127bf215546Sopenharmony_ci /* Draw asynchronously. */ 1128bf215546Sopenharmony_ci multi_draw_elements_async(ctx, mode, count, type, indices, draw_count, 1129bf215546Sopenharmony_ci basevertex, index_buffer, user_buffer_mask, 1130bf215546Sopenharmony_ci buffers); 1131bf215546Sopenharmony_ci return; 1132bf215546Sopenharmony_ci 1133bf215546Sopenharmony_cisync: 1134bf215546Sopenharmony_ci _mesa_glthread_finish_before(ctx, "DrawElements"); 1135bf215546Sopenharmony_ci 1136bf215546Sopenharmony_ci if (basevertex) { 1137bf215546Sopenharmony_ci CALL_MultiDrawElementsBaseVertex(ctx->CurrentServerDispatch, 1138bf215546Sopenharmony_ci (mode, count, type, indices, draw_count, 1139bf215546Sopenharmony_ci basevertex)); 1140bf215546Sopenharmony_ci } else { 1141bf215546Sopenharmony_ci CALL_MultiDrawElementsEXT(ctx->CurrentServerDispatch, 1142bf215546Sopenharmony_ci (mode, count, type, indices, draw_count)); 1143bf215546Sopenharmony_ci } 1144bf215546Sopenharmony_ci} 1145bf215546Sopenharmony_ci 1146bf215546Sopenharmony_civoid GLAPIENTRY 1147bf215546Sopenharmony_ci_mesa_marshal_DrawArrays(GLenum mode, GLint first, GLsizei count) 1148bf215546Sopenharmony_ci{ 1149bf215546Sopenharmony_ci draw_arrays(mode, first, count, 1, 0, true); 1150bf215546Sopenharmony_ci} 1151bf215546Sopenharmony_ci 1152bf215546Sopenharmony_civoid GLAPIENTRY 1153bf215546Sopenharmony_ci_mesa_marshal_DrawArraysInstancedARB(GLenum mode, GLint first, GLsizei count, 1154bf215546Sopenharmony_ci GLsizei instance_count) 1155bf215546Sopenharmony_ci{ 1156bf215546Sopenharmony_ci draw_arrays(mode, first, count, instance_count, 0, false); 1157bf215546Sopenharmony_ci} 1158bf215546Sopenharmony_ci 1159bf215546Sopenharmony_civoid GLAPIENTRY 1160bf215546Sopenharmony_ci_mesa_marshal_DrawArraysInstancedBaseInstance(GLenum mode, GLint first, 1161bf215546Sopenharmony_ci GLsizei count, GLsizei instance_count, 1162bf215546Sopenharmony_ci GLuint baseinstance) 1163bf215546Sopenharmony_ci{ 1164bf215546Sopenharmony_ci draw_arrays(mode, first, count, instance_count, baseinstance, false); 1165bf215546Sopenharmony_ci} 1166bf215546Sopenharmony_ci 1167bf215546Sopenharmony_civoid GLAPIENTRY 1168bf215546Sopenharmony_ci_mesa_marshal_DrawElements(GLenum mode, GLsizei count, GLenum type, 1169bf215546Sopenharmony_ci const GLvoid *indices) 1170bf215546Sopenharmony_ci{ 1171bf215546Sopenharmony_ci draw_elements(mode, count, type, indices, 1, 0, 0, false, 0, 0, true); 1172bf215546Sopenharmony_ci} 1173bf215546Sopenharmony_ci 1174bf215546Sopenharmony_civoid GLAPIENTRY 1175bf215546Sopenharmony_ci_mesa_marshal_DrawRangeElements(GLenum mode, GLuint start, GLuint end, 1176bf215546Sopenharmony_ci GLsizei count, GLenum type, 1177bf215546Sopenharmony_ci const GLvoid *indices) 1178bf215546Sopenharmony_ci{ 1179bf215546Sopenharmony_ci draw_elements(mode, count, type, indices, 1, 0, 0, true, start, end, true); 1180bf215546Sopenharmony_ci} 1181bf215546Sopenharmony_ci 1182bf215546Sopenharmony_civoid GLAPIENTRY 1183bf215546Sopenharmony_ci_mesa_marshal_DrawElementsInstancedARB(GLenum mode, GLsizei count, GLenum type, 1184bf215546Sopenharmony_ci const GLvoid *indices, GLsizei instance_count) 1185bf215546Sopenharmony_ci{ 1186bf215546Sopenharmony_ci draw_elements(mode, count, type, indices, instance_count, 0, 0, false, 0, 0, false); 1187bf215546Sopenharmony_ci} 1188bf215546Sopenharmony_ci 1189bf215546Sopenharmony_civoid GLAPIENTRY 1190bf215546Sopenharmony_ci_mesa_marshal_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, 1191bf215546Sopenharmony_ci const GLvoid *indices, GLint basevertex) 1192bf215546Sopenharmony_ci{ 1193bf215546Sopenharmony_ci draw_elements(mode, count, type, indices, 1, basevertex, 0, false, 0, 0, true); 1194bf215546Sopenharmony_ci} 1195bf215546Sopenharmony_ci 1196bf215546Sopenharmony_civoid GLAPIENTRY 1197bf215546Sopenharmony_ci_mesa_marshal_DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, 1198bf215546Sopenharmony_ci GLsizei count, GLenum type, 1199bf215546Sopenharmony_ci const GLvoid *indices, GLint basevertex) 1200bf215546Sopenharmony_ci{ 1201bf215546Sopenharmony_ci draw_elements(mode, count, type, indices, 1, basevertex, 0, true, start, end, false); 1202bf215546Sopenharmony_ci} 1203bf215546Sopenharmony_ci 1204bf215546Sopenharmony_civoid GLAPIENTRY 1205bf215546Sopenharmony_ci_mesa_marshal_DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, 1206bf215546Sopenharmony_ci GLenum type, const GLvoid *indices, 1207bf215546Sopenharmony_ci GLsizei instance_count, GLint basevertex) 1208bf215546Sopenharmony_ci{ 1209bf215546Sopenharmony_ci draw_elements(mode, count, type, indices, instance_count, basevertex, 0, false, 0, 0, false); 1210bf215546Sopenharmony_ci} 1211bf215546Sopenharmony_ci 1212bf215546Sopenharmony_civoid GLAPIENTRY 1213bf215546Sopenharmony_ci_mesa_marshal_DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, 1214bf215546Sopenharmony_ci GLenum type, const GLvoid *indices, 1215bf215546Sopenharmony_ci GLsizei instance_count, GLuint baseinstance) 1216bf215546Sopenharmony_ci{ 1217bf215546Sopenharmony_ci draw_elements(mode, count, type, indices, instance_count, 0, baseinstance, false, 0, 0, false); 1218bf215546Sopenharmony_ci} 1219bf215546Sopenharmony_ci 1220bf215546Sopenharmony_civoid GLAPIENTRY 1221bf215546Sopenharmony_ci_mesa_marshal_DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, 1222bf215546Sopenharmony_ci GLenum type, const GLvoid *indices, 1223bf215546Sopenharmony_ci GLsizei instance_count, GLint basevertex, 1224bf215546Sopenharmony_ci GLuint baseinstance) 1225bf215546Sopenharmony_ci{ 1226bf215546Sopenharmony_ci draw_elements(mode, count, type, indices, instance_count, basevertex, baseinstance, false, 0, 0, false); 1227bf215546Sopenharmony_ci} 1228bf215546Sopenharmony_ci 1229bf215546Sopenharmony_civoid GLAPIENTRY 1230bf215546Sopenharmony_ci_mesa_marshal_MultiDrawElementsEXT(GLenum mode, const GLsizei *count, 1231bf215546Sopenharmony_ci GLenum type, const GLvoid *const *indices, 1232bf215546Sopenharmony_ci GLsizei draw_count) 1233bf215546Sopenharmony_ci{ 1234bf215546Sopenharmony_ci _mesa_marshal_MultiDrawElementsBaseVertex(mode, count, type, indices, 1235bf215546Sopenharmony_ci draw_count, NULL); 1236bf215546Sopenharmony_ci} 1237bf215546Sopenharmony_ci 1238bf215546Sopenharmony_ciuint32_t 1239bf215546Sopenharmony_ci_mesa_unmarshal_DrawArraysInstancedARB(struct gl_context *ctx, const struct marshal_cmd_DrawArraysInstancedARB *cmd, const uint64_t *last) 1240bf215546Sopenharmony_ci{ 1241bf215546Sopenharmony_ci unreachable("never used - DrawArraysInstancedBaseInstance is used instead"); 1242bf215546Sopenharmony_ci return 0; 1243bf215546Sopenharmony_ci} 1244bf215546Sopenharmony_ci 1245bf215546Sopenharmony_ciuint32_t 1246bf215546Sopenharmony_ci_mesa_unmarshal_DrawElements(struct gl_context *ctx, const struct marshal_cmd_DrawElements *cmd, const uint64_t *last) 1247bf215546Sopenharmony_ci{ 1248bf215546Sopenharmony_ci unreachable("never used - DrawElementsInstancedBaseVertexBaseInstance is used instead"); 1249bf215546Sopenharmony_ci return 0; 1250bf215546Sopenharmony_ci} 1251bf215546Sopenharmony_ci 1252bf215546Sopenharmony_ciuint32_t 1253bf215546Sopenharmony_ci_mesa_unmarshal_DrawRangeElements(struct gl_context *ctx, const struct marshal_cmd_DrawRangeElements *cmd, const uint64_t *last) 1254bf215546Sopenharmony_ci{ 1255bf215546Sopenharmony_ci unreachable("never used - DrawElementsInstancedBaseVertexBaseInstance is used instead"); 1256bf215546Sopenharmony_ci return 0; 1257bf215546Sopenharmony_ci} 1258bf215546Sopenharmony_ci 1259bf215546Sopenharmony_ciuint32_t 1260bf215546Sopenharmony_ci_mesa_unmarshal_DrawElementsBaseVertex(struct gl_context *ctx, const struct marshal_cmd_DrawElementsBaseVertex *cmd, const uint64_t *last) 1261bf215546Sopenharmony_ci{ 1262bf215546Sopenharmony_ci unreachable("never used - DrawElementsInstancedBaseVertexBaseInstance is used instead"); 1263bf215546Sopenharmony_ci return 0; 1264bf215546Sopenharmony_ci} 1265bf215546Sopenharmony_ci 1266bf215546Sopenharmony_ciuint32_t 1267bf215546Sopenharmony_ci_mesa_unmarshal_DrawElementsInstancedBaseVertex(struct gl_context *ctx, const struct marshal_cmd_DrawElementsInstancedBaseVertex *cmd, const uint64_t *last) 1268bf215546Sopenharmony_ci{ 1269bf215546Sopenharmony_ci unreachable("never used - DrawElementsInstancedBaseVertexBaseInstance is used instead"); 1270bf215546Sopenharmony_ci return 0; 1271bf215546Sopenharmony_ci} 1272bf215546Sopenharmony_ci 1273bf215546Sopenharmony_ciuint32_t 1274bf215546Sopenharmony_ci_mesa_unmarshal_DrawElementsInstancedBaseInstance(struct gl_context *ctx, const struct marshal_cmd_DrawElementsInstancedBaseInstance *cmd, const uint64_t *last) 1275bf215546Sopenharmony_ci{ 1276bf215546Sopenharmony_ci unreachable("never used - DrawElementsInstancedBaseVertexBaseInstance is used instead"); 1277bf215546Sopenharmony_ci return 0; 1278bf215546Sopenharmony_ci} 1279bf215546Sopenharmony_ci 1280bf215546Sopenharmony_ciuint32_t 1281bf215546Sopenharmony_ci_mesa_unmarshal_MultiDrawElementsEXT(struct gl_context *ctx, const struct marshal_cmd_MultiDrawElementsEXT *cmd, const uint64_t *last) 1282bf215546Sopenharmony_ci{ 1283bf215546Sopenharmony_ci unreachable("never used - MultiDrawElementsBaseVertex is used instead"); 1284bf215546Sopenharmony_ci return 0; 1285bf215546Sopenharmony_ci} 1286