2 * Copyright © 2020 Advanced Micro Devices, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 /* Draw function marshalling for glthread.
26 * The purpose of these glDraw wrappers is to upload non-VBO vertex and
27 * index data, so that glthread doesn't have to execute synchronously.
30 #include "c99_alloca.h"
32 #include "main/glthread_marshal.h"
33 #include "main/dispatch.h"
34 #include "main/varray.h"
36 static inline unsigned
37 get_index_size(GLenum type
)
39 /* GL_UNSIGNED_BYTE - GL_UNSIGNED_BYTE = 0
40 * GL_UNSIGNED_SHORT - GL_UNSIGNED_BYTE = 2
41 * GL_UNSIGNED_INT - GL_UNSIGNED_BYTE = 4
43 * Divide by 2 to get n=0,1,2, then the index size is: 1 << n
45 return 1 << ((type
- GL_UNSIGNED_BYTE
) >> 1);
49 is_index_type_valid(GLenum type
)
51 /* GL_UNSIGNED_BYTE = 0x1401
52 * GL_UNSIGNED_SHORT = 0x1403
53 * GL_UNSIGNED_INT = 0x1405
55 * The trick is that bit 1 and bit 2 mean USHORT and UINT, respectively.
56 * After clearing those two bits (with ~6), we should get UBYTE.
57 * Both bits can't be set, because the enum would be greater than UINT.
59 return type
<= GL_UNSIGNED_INT
&& (type
& ~6) == GL_UNSIGNED_BYTE
;
62 static ALWAYS_INLINE
struct gl_buffer_object
*
63 upload_indices(struct gl_context
*ctx
, unsigned count
, unsigned index_size
,
64 const GLvoid
**indices
)
66 struct gl_buffer_object
*upload_buffer
= NULL
;
67 unsigned upload_offset
= 0;
71 _mesa_glthread_upload(ctx
, *indices
, index_size
* count
,
72 &upload_offset
, &upload_buffer
, NULL
);
73 assert(upload_buffer
);
74 *indices
= (const GLvoid
*)(intptr_t)upload_offset
;
79 static ALWAYS_INLINE
struct gl_buffer_object
*
80 upload_multi_indices(struct gl_context
*ctx
, unsigned total_count
,
81 unsigned index_size
, unsigned draw_count
,
82 const GLsizei
*count
, const GLvoid
*const *indices
,
83 const GLvoid
**out_indices
)
85 struct gl_buffer_object
*upload_buffer
= NULL
;
86 unsigned upload_offset
= 0;
87 uint8_t *upload_ptr
= NULL
;
91 _mesa_glthread_upload(ctx
, NULL
, index_size
* total_count
,
92 &upload_offset
, &upload_buffer
, &upload_ptr
);
93 assert(upload_buffer
);
95 for (unsigned i
= 0, offset
= 0; i
< draw_count
; i
++) {
99 unsigned size
= count
[i
] * index_size
;
101 memcpy(upload_ptr
+ offset
, indices
[i
], size
);
102 out_indices
[i
] = (const GLvoid
*)(intptr_t)(upload_offset
+ offset
);
106 return upload_buffer
;
109 static ALWAYS_INLINE
bool
110 upload_vertices(struct gl_context
*ctx
, unsigned user_buffer_mask
,
111 unsigned start_vertex
, unsigned num_vertices
,
112 unsigned start_instance
, unsigned num_instances
,
113 struct glthread_attrib_binding
*buffers
)
115 struct glthread_vao
*vao
= ctx
->GLThread
.CurrentVAO
;
116 unsigned attrib_mask_iter
= vao
->Enabled
;
117 unsigned num_buffers
= 0;
119 assert((num_vertices
|| !(user_buffer_mask
& ~vao
->NonZeroDivisorMask
)) &&
120 (num_instances
|| !(user_buffer_mask
& vao
->NonZeroDivisorMask
)));
122 if (unlikely(vao
->BufferInterleaved
& user_buffer_mask
)) {
123 /* Slower upload path where some buffers reference multiple attribs,
124 * so we have to use 2 while loops instead of 1.
126 unsigned start_offset
[VERT_ATTRIB_MAX
];
127 unsigned end_offset
[VERT_ATTRIB_MAX
];
128 uint32_t buffer_mask
= 0;
130 while (attrib_mask_iter
) {
131 unsigned i
= u_bit_scan(&attrib_mask_iter
);
132 unsigned binding_index
= vao
->Attrib
[i
].BufferIndex
;
134 if (!(user_buffer_mask
& (1 << binding_index
)))
137 unsigned stride
= vao
->Attrib
[binding_index
].Stride
;
138 unsigned instance_div
= vao
->Attrib
[binding_index
].Divisor
;
139 unsigned element_size
= vao
->Attrib
[i
].ElementSize
;
140 unsigned offset
= vao
->Attrib
[i
].RelativeOffset
;
144 /* Per-instance attrib. */
146 /* Figure out how many instances we'll render given instance_div. We
147 * can't use the typical div_round_up() pattern because the CTS uses
148 * instance_div = ~0 for a test, which overflows div_round_up()'s
151 unsigned count
= num_instances
/ instance_div
;
152 if (count
* instance_div
!= num_instances
)
155 offset
+= stride
* start_instance
;
156 size
= stride
* (count
- 1) + element_size
;
158 /* Per-vertex attrib. */
159 offset
+= stride
* start_vertex
;
160 size
= stride
* (num_vertices
- 1) + element_size
;
163 unsigned binding_index_bit
= 1u << binding_index
;
165 /* Update upload offsets. */
166 if (!(buffer_mask
& binding_index_bit
)) {
167 start_offset
[binding_index
] = offset
;
168 end_offset
[binding_index
] = offset
+ size
;
170 if (offset
< start_offset
[binding_index
])
171 start_offset
[binding_index
] = offset
;
172 if (offset
+ size
> end_offset
[binding_index
])
173 end_offset
[binding_index
] = offset
+ size
;
176 buffer_mask
|= binding_index_bit
;
179 /* Upload buffers. */
180 while (buffer_mask
) {
181 struct gl_buffer_object
*upload_buffer
= NULL
;
182 unsigned upload_offset
= 0;
185 unsigned binding_index
= u_bit_scan(&buffer_mask
);
187 start
= start_offset
[binding_index
];
188 end
= end_offset
[binding_index
];
191 const void *ptr
= vao
->Attrib
[binding_index
].Pointer
;
192 _mesa_glthread_upload(ctx
, (uint8_t*)ptr
+ start
,
193 end
- start
, &upload_offset
,
194 &upload_buffer
, NULL
);
195 assert(upload_buffer
);
197 buffers
[num_buffers
].buffer
= upload_buffer
;
198 buffers
[num_buffers
].offset
= upload_offset
- start
;
199 buffers
[num_buffers
].original_pointer
= ptr
;
206 /* Faster path where all attribs are separate. */
207 while (attrib_mask_iter
) {
208 unsigned i
= u_bit_scan(&attrib_mask_iter
);
209 unsigned binding_index
= vao
->Attrib
[i
].BufferIndex
;
211 if (!(user_buffer_mask
& (1 << binding_index
)))
214 struct gl_buffer_object
*upload_buffer
= NULL
;
215 unsigned upload_offset
= 0;
216 unsigned stride
= vao
->Attrib
[binding_index
].Stride
;
217 unsigned instance_div
= vao
->Attrib
[binding_index
].Divisor
;
218 unsigned element_size
= vao
->Attrib
[i
].ElementSize
;
219 unsigned offset
= vao
->Attrib
[i
].RelativeOffset
;
223 /* Per-instance attrib. */
225 /* Figure out how many instances we'll render given instance_div. We
226 * can't use the typical div_round_up() pattern because the CTS uses
227 * instance_div = ~0 for a test, which overflows div_round_up()'s
230 unsigned count
= num_instances
/ instance_div
;
231 if (count
* instance_div
!= num_instances
)
234 offset
+= stride
* start_instance
;
235 size
= stride
* (count
- 1) + element_size
;
237 /* Per-vertex attrib. */
238 offset
+= stride
* start_vertex
;
239 size
= stride
* (num_vertices
- 1) + element_size
;
242 const void *ptr
= vao
->Attrib
[binding_index
].Pointer
;
243 _mesa_glthread_upload(ctx
, (uint8_t*)ptr
+ offset
,
244 size
, &upload_offset
, &upload_buffer
, NULL
);
245 assert(upload_buffer
);
247 buffers
[num_buffers
].buffer
= upload_buffer
;
248 buffers
[num_buffers
].offset
= upload_offset
- offset
;
249 buffers
[num_buffers
].original_pointer
= ptr
;
256 struct marshal_cmd_DrawArraysInstancedBaseInstance
258 struct marshal_cmd_base cmd_base
;
262 GLsizei instance_count
;
264 GLuint user_buffer_mask
;
268 _mesa_unmarshal_DrawArraysInstancedBaseInstance(struct gl_context
*ctx
,
269 const struct marshal_cmd_DrawArraysInstancedBaseInstance
*cmd
)
271 const GLenum mode
= cmd
->mode
;
272 const GLint first
= cmd
->first
;
273 const GLsizei count
= cmd
->count
;
274 const GLsizei instance_count
= cmd
->instance_count
;
275 const GLuint baseinstance
= cmd
->baseinstance
;
276 const GLuint user_buffer_mask
= cmd
->user_buffer_mask
;
277 const struct glthread_attrib_binding
*buffers
=
278 (const struct glthread_attrib_binding
*)(cmd
+ 1);
280 /* Bind uploaded buffers if needed. */
281 if (user_buffer_mask
) {
282 _mesa_InternalBindVertexBuffers(ctx
, buffers
, user_buffer_mask
,
286 CALL_DrawArraysInstancedBaseInstance(ctx
->CurrentServerDispatch
,
287 (mode
, first
, count
, instance_count
,
290 /* Restore states. */
291 if (user_buffer_mask
) {
292 _mesa_InternalBindVertexBuffers(ctx
, buffers
, user_buffer_mask
,
297 static ALWAYS_INLINE
void
298 draw_arrays_async(struct gl_context
*ctx
, GLenum mode
, GLint first
,
299 GLsizei count
, GLsizei instance_count
, GLuint baseinstance
,
300 unsigned user_buffer_mask
,
301 const struct glthread_attrib_binding
*buffers
)
303 int buffers_size
= util_bitcount(user_buffer_mask
) * sizeof(buffers
[0]);
304 int cmd_size
= sizeof(struct marshal_cmd_DrawArraysInstancedBaseInstance
) +
306 struct marshal_cmd_DrawArraysInstancedBaseInstance
*cmd
;
308 cmd
= _mesa_glthread_allocate_command(ctx
, DISPATCH_CMD_DrawArraysInstancedBaseInstance
,
313 cmd
->instance_count
= instance_count
;
314 cmd
->baseinstance
= baseinstance
;
315 cmd
->user_buffer_mask
= user_buffer_mask
;
317 if (user_buffer_mask
)
318 memcpy(cmd
+ 1, buffers
, buffers_size
);
321 static ALWAYS_INLINE
void
322 draw_arrays(GLenum mode
, GLint first
, GLsizei count
, GLsizei instance_count
,
323 GLuint baseinstance
, bool compiled_into_dlist
)
325 GET_CURRENT_CONTEXT(ctx
);
327 struct glthread_vao
*vao
= ctx
->GLThread
.CurrentVAO
;
328 unsigned user_buffer_mask
= vao
->UserPointerMask
& vao
->BufferEnabled
;
330 if (compiled_into_dlist
&& ctx
->GLThread
.inside_dlist
) {
331 _mesa_glthread_finish_before(ctx
, "DrawArrays");
332 /* Use the function that's compiled into a display list. */
333 CALL_DrawArrays(ctx
->CurrentServerDispatch
, (mode
, first
, count
));
337 /* Fast path when nothing needs to be done.
339 * This is also an error path. Zero counts should still call the driver
340 * for possible GL errors.
342 if (ctx
->API
== API_OPENGL_CORE
|| !user_buffer_mask
||
343 count
<= 0 || instance_count
<= 0) {
344 draw_arrays_async(ctx
, mode
, first
, count
, instance_count
, baseinstance
,
349 /* Upload and draw. */
350 struct glthread_attrib_binding buffers
[VERT_ATTRIB_MAX
];
351 if (!ctx
->GLThread
.SupportsNonVBOUploads
||
352 !upload_vertices(ctx
, user_buffer_mask
, first
, count
, baseinstance
,
353 instance_count
, buffers
)) {
354 _mesa_glthread_finish_before(ctx
, "DrawArrays");
355 CALL_DrawArraysInstancedBaseInstance(ctx
->CurrentServerDispatch
,
356 (mode
, first
, count
, instance_count
,
361 draw_arrays_async(ctx
, mode
, first
, count
, instance_count
, baseinstance
,
362 user_buffer_mask
, buffers
);
365 struct marshal_cmd_MultiDrawArrays
367 struct marshal_cmd_base cmd_base
;
370 GLuint user_buffer_mask
;
374 _mesa_unmarshal_MultiDrawArrays(struct gl_context
*ctx
,
375 const struct marshal_cmd_MultiDrawArrays
*cmd
)
377 const GLenum mode
= cmd
->mode
;
378 const GLsizei draw_count
= cmd
->draw_count
;
379 const GLuint user_buffer_mask
= cmd
->user_buffer_mask
;
381 const char *variable_data
= (const char *)(cmd
+ 1);
382 const GLint
*first
= (GLint
*)variable_data
;
383 variable_data
+= sizeof(GLint
) * draw_count
;
384 const GLsizei
*count
= (GLsizei
*)variable_data
;
385 variable_data
+= sizeof(GLsizei
) * draw_count
;
386 const struct glthread_attrib_binding
*buffers
=
387 (const struct glthread_attrib_binding
*)variable_data
;
389 /* Bind uploaded buffers if needed. */
390 if (user_buffer_mask
) {
391 _mesa_InternalBindVertexBuffers(ctx
, buffers
, user_buffer_mask
,
395 CALL_MultiDrawArrays(ctx
->CurrentServerDispatch
,
396 (mode
, first
, count
, draw_count
));
398 /* Restore states. */
399 if (user_buffer_mask
) {
400 _mesa_InternalBindVertexBuffers(ctx
, buffers
, user_buffer_mask
,
405 static ALWAYS_INLINE
void
406 multi_draw_arrays_async(struct gl_context
*ctx
, GLenum mode
,
407 const GLint
*first
, const GLsizei
*count
,
408 GLsizei draw_count
, unsigned user_buffer_mask
,
409 const struct glthread_attrib_binding
*buffers
)
411 int first_size
= sizeof(GLint
) * draw_count
;
412 int count_size
= sizeof(GLsizei
) * draw_count
;
413 int buffers_size
= util_bitcount(user_buffer_mask
) * sizeof(buffers
[0]);
414 int cmd_size
= sizeof(struct marshal_cmd_MultiDrawArrays
) +
415 first_size
+ count_size
+ buffers_size
;
416 struct marshal_cmd_MultiDrawArrays
*cmd
;
418 cmd
= _mesa_glthread_allocate_command(ctx
, DISPATCH_CMD_MultiDrawArrays
,
421 cmd
->draw_count
= draw_count
;
422 cmd
->user_buffer_mask
= user_buffer_mask
;
424 char *variable_data
= (char*)(cmd
+ 1);
425 memcpy(variable_data
, first
, first_size
);
426 variable_data
+= first_size
;
427 memcpy(variable_data
, count
, count_size
);
429 if (user_buffer_mask
) {
430 variable_data
+= count_size
;
431 memcpy(variable_data
, buffers
, buffers_size
);
436 _mesa_marshal_MultiDrawArrays(GLenum mode
, const GLint
*first
,
437 const GLsizei
*count
, GLsizei draw_count
)
439 GET_CURRENT_CONTEXT(ctx
);
441 struct glthread_vao
*vao
= ctx
->GLThread
.CurrentVAO
;
442 unsigned user_buffer_mask
= vao
->UserPointerMask
& vao
->BufferEnabled
;
444 if (ctx
->GLThread
.inside_dlist
)
447 if (draw_count
>= 0 &&
448 (ctx
->API
== API_OPENGL_CORE
|| !user_buffer_mask
)) {
449 multi_draw_arrays_async(ctx
, mode
, first
, count
, draw_count
, 0, NULL
);
453 /* If the draw count is too high or negative, the queue can't be used. */
454 if (!ctx
->GLThread
.SupportsNonVBOUploads
||
455 draw_count
< 0 || draw_count
> MARSHAL_MAX_CMD_SIZE
/ 16)
458 unsigned min_index
= ~0;
459 unsigned max_index_exclusive
= 0;
461 for (unsigned i
= 0; i
< draw_count
; i
++) {
462 GLsizei vertex_count
= count
[i
];
464 if (vertex_count
< 0) {
465 /* Just call the driver to set the error. */
466 multi_draw_arrays_async(ctx
, mode
, first
, count
, draw_count
, 0, NULL
);
469 if (vertex_count
== 0)
472 min_index
= MIN2(min_index
, first
[i
]);
473 max_index_exclusive
= MAX2(max_index_exclusive
, first
[i
] + vertex_count
);
476 unsigned num_vertices
= max_index_exclusive
- min_index
;
477 if (num_vertices
== 0) {
478 /* Nothing to do, but call the driver to set possible GL errors. */
479 multi_draw_arrays_async(ctx
, mode
, first
, count
, draw_count
, 0, NULL
);
483 /* Upload and draw. */
484 struct glthread_attrib_binding buffers
[VERT_ATTRIB_MAX
];
485 if (!upload_vertices(ctx
, user_buffer_mask
, min_index
, num_vertices
,
489 multi_draw_arrays_async(ctx
, mode
, first
, count
, draw_count
,
490 user_buffer_mask
, buffers
);
494 _mesa_glthread_finish_before(ctx
, "MultiDrawArrays");
495 CALL_MultiDrawArrays(ctx
->CurrentServerDispatch
,
496 (mode
, first
, count
, draw_count
));
499 struct marshal_cmd_DrawElementsInstancedBaseVertexBaseInstance
501 struct marshal_cmd_base cmd_base
;
502 bool index_bounds_valid
;
506 GLsizei instance_count
;
511 GLuint user_buffer_mask
;
512 const GLvoid
*indices
;
513 struct gl_buffer_object
*index_buffer
;
517 _mesa_unmarshal_DrawElementsInstancedBaseVertexBaseInstance(struct gl_context
*ctx
,
518 const struct marshal_cmd_DrawElementsInstancedBaseVertexBaseInstance
*cmd
)
520 const GLenum mode
= cmd
->mode
;
521 const GLsizei count
= cmd
->count
;
522 const GLenum type
= cmd
->type
;
523 const GLvoid
*indices
= cmd
->indices
;
524 const GLsizei instance_count
= cmd
->instance_count
;
525 const GLint basevertex
= cmd
->basevertex
;
526 const GLuint baseinstance
= cmd
->baseinstance
;
527 const GLuint min_index
= cmd
->min_index
;
528 const GLuint max_index
= cmd
->max_index
;
529 const GLuint user_buffer_mask
= cmd
->user_buffer_mask
;
530 struct gl_buffer_object
*index_buffer
= cmd
->index_buffer
;
531 const struct glthread_attrib_binding
*buffers
=
532 (const struct glthread_attrib_binding
*)(cmd
+ 1);
534 /* Bind uploaded buffers if needed. */
535 if (user_buffer_mask
) {
536 _mesa_InternalBindVertexBuffers(ctx
, buffers
, user_buffer_mask
,
540 _mesa_InternalBindElementBuffer(ctx
, index_buffer
);
544 if (cmd
->index_bounds_valid
&& instance_count
== 1 && baseinstance
== 0) {
545 CALL_DrawRangeElementsBaseVertex(ctx
->CurrentServerDispatch
,
546 (mode
, min_index
, max_index
, count
,
547 type
, indices
, basevertex
));
549 CALL_DrawElementsInstancedBaseVertexBaseInstance(ctx
->CurrentServerDispatch
,
550 (mode
, count
, type
, indices
,
551 instance_count
, basevertex
,
555 /* Restore states. */
557 _mesa_InternalBindElementBuffer(ctx
, NULL
);
559 if (user_buffer_mask
) {
560 _mesa_InternalBindVertexBuffers(ctx
, buffers
, user_buffer_mask
,
565 static ALWAYS_INLINE
void
566 draw_elements_async(struct gl_context
*ctx
, GLenum mode
, GLsizei count
,
567 GLenum type
, const GLvoid
*indices
, GLsizei instance_count
,
568 GLint basevertex
, GLuint baseinstance
,
569 bool index_bounds_valid
, GLuint min_index
, GLuint max_index
,
570 struct gl_buffer_object
*index_buffer
,
571 unsigned user_buffer_mask
,
572 const struct glthread_attrib_binding
*buffers
)
574 int buffers_size
= util_bitcount(user_buffer_mask
) * sizeof(buffers
[0]);
575 int cmd_size
= sizeof(struct marshal_cmd_DrawElementsInstancedBaseVertexBaseInstance
) +
577 struct marshal_cmd_DrawElementsInstancedBaseVertexBaseInstance
*cmd
;
579 cmd
= _mesa_glthread_allocate_command(ctx
, DISPATCH_CMD_DrawElementsInstancedBaseVertexBaseInstance
, cmd_size
);
583 cmd
->indices
= indices
;
584 cmd
->instance_count
= instance_count
;
585 cmd
->basevertex
= basevertex
;
586 cmd
->baseinstance
= baseinstance
;
587 cmd
->min_index
= min_index
;
588 cmd
->max_index
= max_index
;
589 cmd
->user_buffer_mask
= user_buffer_mask
;
590 cmd
->index_bounds_valid
= index_bounds_valid
;
591 cmd
->index_buffer
= index_buffer
;
593 if (user_buffer_mask
)
594 memcpy(cmd
+ 1, buffers
, buffers_size
);
598 draw_elements(GLenum mode
, GLsizei count
, GLenum type
, const GLvoid
*indices
,
599 GLsizei instance_count
, GLint basevertex
, GLuint baseinstance
,
600 bool index_bounds_valid
, GLuint min_index
, GLuint max_index
,
601 bool compiled_into_dlist
)
603 GET_CURRENT_CONTEXT(ctx
);
605 struct glthread_vao
*vao
= ctx
->GLThread
.CurrentVAO
;
606 unsigned user_buffer_mask
= vao
->UserPointerMask
& vao
->BufferEnabled
;
607 bool has_user_indices
= vao
->CurrentElementBufferName
== 0;
609 if (compiled_into_dlist
&& ctx
->GLThread
.inside_dlist
)
612 /* Fast path when nothing needs to be done.
614 * This is also an error path. Zero counts should still call the driver
615 * for possible GL errors.
617 if (ctx
->API
== API_OPENGL_CORE
||
618 count
<= 0 || instance_count
<= 0 || max_index
< min_index
||
619 !is_index_type_valid(type
) ||
620 (!user_buffer_mask
&& !has_user_indices
)) {
621 draw_elements_async(ctx
, mode
, count
, type
, indices
, instance_count
,
622 basevertex
, baseinstance
, index_bounds_valid
,
623 min_index
, max_index
, 0, 0, NULL
);
627 if (!ctx
->GLThread
.SupportsNonVBOUploads
)
630 bool need_index_bounds
= user_buffer_mask
& ~vao
->NonZeroDivisorMask
;
631 unsigned index_size
= get_index_size(type
);
633 if (need_index_bounds
&& !index_bounds_valid
) {
634 /* Sync if indices come from a buffer and vertices come from memory
635 * and index bounds are not valid.
637 * We would have to map the indices to compute the index bounds, and
638 * for that we would have to sync anyway.
640 if (!has_user_indices
)
643 /* Compute the index bounds. */
646 vbo_get_minmax_index_mapped(count
, index_size
,
647 ctx
->GLThread
._RestartIndex
[index_size
- 1],
648 ctx
->GLThread
._PrimitiveRestart
, indices
,
649 &min_index
, &max_index
);
650 index_bounds_valid
= true;
653 unsigned start_vertex
= min_index
+ basevertex
;
654 unsigned num_vertices
= max_index
+ 1 - min_index
;
656 /* If there is too much data to upload, sync and let the driver unroll
658 if (util_is_vbo_upload_ratio_too_large(count
, num_vertices
))
661 struct glthread_attrib_binding buffers
[VERT_ATTRIB_MAX
];
662 if (user_buffer_mask
&&
663 !upload_vertices(ctx
, user_buffer_mask
, start_vertex
, num_vertices
,
664 baseinstance
, instance_count
, buffers
))
667 /* Upload indices. */
668 struct gl_buffer_object
*index_buffer
= NULL
;
669 if (has_user_indices
)
670 index_buffer
= upload_indices(ctx
, count
, index_size
, &indices
);
672 /* Draw asynchronously. */
673 draw_elements_async(ctx
, mode
, count
, type
, indices
, instance_count
,
674 basevertex
, baseinstance
, index_bounds_valid
,
675 min_index
, max_index
, index_buffer
,
676 user_buffer_mask
, buffers
);
680 _mesa_glthread_finish_before(ctx
, "DrawElements");
682 if (compiled_into_dlist
&& ctx
->GLThread
.inside_dlist
) {
683 /* Only use the ones that are compiled into display lists. */
685 CALL_DrawElementsBaseVertex(ctx
->CurrentServerDispatch
,
686 (mode
, count
, type
, indices
, basevertex
));
687 } else if (index_bounds_valid
) {
688 CALL_DrawRangeElements(ctx
->CurrentServerDispatch
,
689 (mode
, min_index
, max_index
, count
, type
, indices
));
691 CALL_DrawElements(ctx
->CurrentServerDispatch
, (mode
, count
, type
, indices
));
693 } else if (index_bounds_valid
&& instance_count
== 1 && baseinstance
== 0) {
694 CALL_DrawRangeElementsBaseVertex(ctx
->CurrentServerDispatch
,
695 (mode
, min_index
, max_index
, count
,
696 type
, indices
, basevertex
));
698 CALL_DrawElementsInstancedBaseVertexBaseInstance(ctx
->CurrentServerDispatch
,
699 (mode
, count
, type
, indices
,
700 instance_count
, basevertex
,
705 struct marshal_cmd_MultiDrawElementsBaseVertex
707 struct marshal_cmd_base cmd_base
;
708 bool has_base_vertex
;
712 GLuint user_buffer_mask
;
713 struct gl_buffer_object
*index_buffer
;
717 _mesa_unmarshal_MultiDrawElementsBaseVertex(struct gl_context
*ctx
,
718 const struct marshal_cmd_MultiDrawElementsBaseVertex
*cmd
)
720 const GLenum mode
= cmd
->mode
;
721 const GLenum type
= cmd
->type
;
722 const GLsizei draw_count
= cmd
->draw_count
;
723 const GLuint user_buffer_mask
= cmd
->user_buffer_mask
;
724 struct gl_buffer_object
*index_buffer
= cmd
->index_buffer
;
725 const bool has_base_vertex
= cmd
->has_base_vertex
;
727 const char *variable_data
= (const char *)(cmd
+ 1);
728 const GLsizei
*count
= (GLsizei
*)variable_data
;
729 variable_data
+= sizeof(GLsizei
) * draw_count
;
730 const GLvoid
*const *indices
= (const GLvoid
*const *)variable_data
;
731 variable_data
+= sizeof(const GLvoid
*const *) * draw_count
;
732 const GLsizei
*basevertex
= NULL
;
733 if (has_base_vertex
) {
734 basevertex
= (GLsizei
*)variable_data
;
735 variable_data
+= sizeof(GLsizei
) * draw_count
;
737 const struct glthread_attrib_binding
*buffers
=
738 (const struct glthread_attrib_binding
*)variable_data
;
740 /* Bind uploaded buffers if needed. */
741 if (user_buffer_mask
) {
742 _mesa_InternalBindVertexBuffers(ctx
, buffers
, user_buffer_mask
,
746 _mesa_InternalBindElementBuffer(ctx
, index_buffer
);
750 if (has_base_vertex
) {
751 CALL_MultiDrawElementsBaseVertex(ctx
->CurrentServerDispatch
,
752 (mode
, count
, type
, indices
, draw_count
,
755 CALL_MultiDrawElementsEXT(ctx
->CurrentServerDispatch
,
756 (mode
, count
, type
, indices
, draw_count
));
759 /* Restore states. */
761 _mesa_InternalBindElementBuffer(ctx
, NULL
);
763 if (user_buffer_mask
) {
764 _mesa_InternalBindVertexBuffers(ctx
, buffers
, user_buffer_mask
,
769 static ALWAYS_INLINE
void
770 multi_draw_elements_async(struct gl_context
*ctx
, GLenum mode
,
771 const GLsizei
*count
, GLenum type
,
772 const GLvoid
*const *indices
, GLsizei draw_count
,
773 const GLsizei
*basevertex
,
774 struct gl_buffer_object
*index_buffer
,
775 unsigned user_buffer_mask
,
776 const struct glthread_attrib_binding
*buffers
)
778 int count_size
= sizeof(GLsizei
) * draw_count
;
779 int indices_size
= sizeof(indices
[0]) * draw_count
;
780 int basevertex_size
= basevertex
? sizeof(GLsizei
) * draw_count
: 0;
781 int buffers_size
= util_bitcount(user_buffer_mask
) * sizeof(buffers
[0]);
782 int cmd_size
= sizeof(struct marshal_cmd_MultiDrawElementsBaseVertex
) +
783 count_size
+ indices_size
+ basevertex_size
+ buffers_size
;
784 struct marshal_cmd_MultiDrawElementsBaseVertex
*cmd
;
786 cmd
= _mesa_glthread_allocate_command(ctx
, DISPATCH_CMD_MultiDrawElementsBaseVertex
, cmd_size
);
789 cmd
->draw_count
= draw_count
;
790 cmd
->user_buffer_mask
= user_buffer_mask
;
791 cmd
->index_buffer
= index_buffer
;
792 cmd
->has_base_vertex
= basevertex
!= NULL
;
794 char *variable_data
= (char*)(cmd
+ 1);
795 memcpy(variable_data
, count
, count_size
);
796 variable_data
+= count_size
;
797 memcpy(variable_data
, indices
, indices_size
);
798 variable_data
+= indices_size
;
801 memcpy(variable_data
, basevertex
, basevertex_size
);
802 variable_data
+= basevertex_size
;
805 if (user_buffer_mask
)
806 memcpy(variable_data
, buffers
, buffers_size
);
810 _mesa_marshal_MultiDrawElementsBaseVertex(GLenum mode
, const GLsizei
*count
,
812 const GLvoid
*const *indices
,
814 const GLsizei
*basevertex
)
816 GET_CURRENT_CONTEXT(ctx
);
818 struct glthread_vao
*vao
= ctx
->GLThread
.CurrentVAO
;
819 unsigned user_buffer_mask
= vao
->UserPointerMask
& vao
->BufferEnabled
;
820 bool has_user_indices
= vao
->CurrentElementBufferName
== 0;
822 if (ctx
->GLThread
.inside_dlist
)
825 /* Fast path when nothing needs to be done. */
826 if (draw_count
>= 0 &&
827 (ctx
->API
== API_OPENGL_CORE
||
828 !is_index_type_valid(type
) ||
829 (!user_buffer_mask
&& !has_user_indices
))) {
830 multi_draw_elements_async(ctx
, mode
, count
, type
, indices
, draw_count
,
831 basevertex
, 0, 0, NULL
);
835 bool need_index_bounds
= user_buffer_mask
& ~vao
->NonZeroDivisorMask
;
837 /* If the draw count is too high or negative, the queue can't be used.
839 * Sync if indices come from a buffer and vertices come from memory
840 * and index bounds are not valid. We would have to map the indices
841 * to compute the index bounds, and for that we would have to sync anyway.
843 if (!ctx
->GLThread
.SupportsNonVBOUploads
||
844 draw_count
< 0 || draw_count
> MARSHAL_MAX_CMD_SIZE
/ 32 ||
845 (need_index_bounds
&& !has_user_indices
))
848 unsigned index_size
= get_index_size(type
);
849 unsigned min_index
= ~0;
850 unsigned max_index
= 0;
851 unsigned total_count
= 0;
852 unsigned num_vertices
= 0;
854 /* This is always true if there is per-vertex data that needs to be
857 if (need_index_bounds
) {
858 /* Compute the index bounds. */
859 for (unsigned i
= 0; i
< draw_count
; i
++) {
860 GLsizei vertex_count
= count
[i
];
862 if (vertex_count
< 0) {
863 /* Just call the driver to set the error. */
864 multi_draw_elements_async(ctx
, mode
, count
, type
, indices
, draw_count
,
865 basevertex
, 0, 0, NULL
);
868 if (vertex_count
== 0)
871 unsigned min
= ~0, max
= 0;
872 vbo_get_minmax_index_mapped(vertex_count
, index_size
,
873 ctx
->GLThread
._RestartIndex
[index_size
- 1],
874 ctx
->GLThread
._PrimitiveRestart
, indices
[i
],
877 min
+= basevertex
[i
];
878 max
+= basevertex
[i
];
880 min_index
= MIN2(min_index
, min
);
881 max_index
= MAX2(max_index
, max
);
882 total_count
+= vertex_count
;
885 num_vertices
= max_index
+ 1 - min_index
;
887 if (total_count
== 0 || num_vertices
== 0) {
888 /* Nothing to do, but call the driver to set possible GL errors. */
889 multi_draw_elements_async(ctx
, mode
, count
, type
, indices
, draw_count
,
890 basevertex
, 0, 0, NULL
);
894 /* If there is too much data to upload, sync and let the driver unroll
896 if (util_is_vbo_upload_ratio_too_large(total_count
, num_vertices
))
898 } else if (has_user_indices
) {
899 /* Only compute total_count for the upload of indices. */
900 for (unsigned i
= 0; i
< draw_count
; i
++) {
901 GLsizei vertex_count
= count
[i
];
903 if (vertex_count
< 0) {
904 /* Just call the driver to set the error. */
905 multi_draw_elements_async(ctx
, mode
, count
, type
, indices
, draw_count
,
906 basevertex
, 0, 0, NULL
);
909 if (vertex_count
== 0)
912 total_count
+= vertex_count
;
915 if (total_count
== 0) {
916 /* Nothing to do, but call the driver to set possible GL errors. */
917 multi_draw_elements_async(ctx
, mode
, count
, type
, indices
, draw_count
,
918 basevertex
, 0, 0, NULL
);
923 /* Upload vertices. */
924 struct glthread_attrib_binding buffers
[VERT_ATTRIB_MAX
];
925 if (user_buffer_mask
&&
926 !upload_vertices(ctx
, user_buffer_mask
, min_index
, num_vertices
,
930 /* Upload indices. */
931 struct gl_buffer_object
*index_buffer
= NULL
;
932 if (has_user_indices
) {
933 const GLvoid
**out_indices
= alloca(sizeof(indices
[0]) * draw_count
);
935 index_buffer
= upload_multi_indices(ctx
, total_count
, index_size
,
936 draw_count
, count
, indices
,
938 indices
= out_indices
;
941 /* Draw asynchronously. */
942 multi_draw_elements_async(ctx
, mode
, count
, type
, indices
, draw_count
,
943 basevertex
, index_buffer
, user_buffer_mask
,
948 _mesa_glthread_finish_before(ctx
, "DrawElements");
951 CALL_MultiDrawElementsBaseVertex(ctx
->CurrentServerDispatch
,
952 (mode
, count
, type
, indices
, draw_count
,
955 CALL_MultiDrawElementsEXT(ctx
->CurrentServerDispatch
,
956 (mode
, count
, type
, indices
, draw_count
));
961 _mesa_marshal_DrawArrays(GLenum mode
, GLint first
, GLsizei count
)
963 draw_arrays(mode
, first
, count
, 1, 0, true);
967 _mesa_marshal_DrawArraysInstancedARB(GLenum mode
, GLint first
, GLsizei count
,
968 GLsizei instance_count
)
970 draw_arrays(mode
, first
, count
, instance_count
, 0, false);
974 _mesa_marshal_DrawArraysInstancedBaseInstance(GLenum mode
, GLint first
,
975 GLsizei count
, GLsizei instance_count
,
978 draw_arrays(mode
, first
, count
, instance_count
, baseinstance
, false);
982 _mesa_marshal_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
983 const GLvoid
*indices
)
985 draw_elements(mode
, count
, type
, indices
, 1, 0, 0, false, 0, 0, true);
989 _mesa_marshal_DrawRangeElements(GLenum mode
, GLuint start
, GLuint end
,
990 GLsizei count
, GLenum type
,
991 const GLvoid
*indices
)
993 draw_elements(mode
, count
, type
, indices
, 1, 0, 0, true, start
, end
, true);
997 _mesa_marshal_DrawElementsInstancedARB(GLenum mode
, GLsizei count
, GLenum type
,
998 const GLvoid
*indices
, GLsizei instance_count
)
1000 draw_elements(mode
, count
, type
, indices
, instance_count
, 0, 0, false, 0, 0, false);
1004 _mesa_marshal_DrawElementsBaseVertex(GLenum mode
, GLsizei count
, GLenum type
,
1005 const GLvoid
*indices
, GLint basevertex
)
1007 draw_elements(mode
, count
, type
, indices
, 1, basevertex
, 0, false, 0, 0, true);
1011 _mesa_marshal_DrawRangeElementsBaseVertex(GLenum mode
, GLuint start
, GLuint end
,
1012 GLsizei count
, GLenum type
,
1013 const GLvoid
*indices
, GLint basevertex
)
1015 draw_elements(mode
, count
, type
, indices
, 1, basevertex
, 0, true, start
, end
, false);
1019 _mesa_marshal_DrawElementsInstancedBaseVertex(GLenum mode
, GLsizei count
,
1020 GLenum type
, const GLvoid
*indices
,
1021 GLsizei instance_count
, GLint basevertex
)
1023 draw_elements(mode
, count
, type
, indices
, instance_count
, basevertex
, 0, false, 0, 0, false);
1027 _mesa_marshal_DrawElementsInstancedBaseInstance(GLenum mode
, GLsizei count
,
1028 GLenum type
, const GLvoid
*indices
,
1029 GLsizei instance_count
, GLuint baseinstance
)
1031 draw_elements(mode
, count
, type
, indices
, instance_count
, 0, baseinstance
, false, 0, 0, false);
1035 _mesa_marshal_DrawElementsInstancedBaseVertexBaseInstance(GLenum mode
, GLsizei count
,
1036 GLenum type
, const GLvoid
*indices
,
1037 GLsizei instance_count
, GLint basevertex
,
1038 GLuint baseinstance
)
1040 draw_elements(mode
, count
, type
, indices
, instance_count
, basevertex
, baseinstance
, false, 0, 0, false);
1044 _mesa_marshal_MultiDrawElementsEXT(GLenum mode
, const GLsizei
*count
,
1045 GLenum type
, const GLvoid
*const *indices
,
1048 _mesa_marshal_MultiDrawElementsBaseVertex(mode
, count
, type
, indices
,
1053 _mesa_unmarshal_DrawArrays(struct gl_context
*ctx
, const struct marshal_cmd_DrawArrays
*cmd
)
1055 unreachable("never used - DrawArraysInstancedBaseInstance is used instead");
1059 _mesa_unmarshal_DrawArraysInstancedARB(struct gl_context
*ctx
, const struct marshal_cmd_DrawArraysInstancedARB
*cmd
)
1061 unreachable("never used - DrawArraysInstancedBaseInstance is used instead");
1065 _mesa_unmarshal_DrawElements(struct gl_context
*ctx
, const struct marshal_cmd_DrawElements
*cmd
)
1067 unreachable("never used - DrawElementsInstancedBaseVertexBaseInstance is used instead");
1071 _mesa_unmarshal_DrawRangeElements(struct gl_context
*ctx
, const struct marshal_cmd_DrawRangeElements
*cmd
)
1073 unreachable("never used - DrawElementsInstancedBaseVertexBaseInstance is used instead");
1077 _mesa_unmarshal_DrawElementsInstancedARB(struct gl_context
*ctx
, const struct marshal_cmd_DrawElementsInstancedARB
*cmd
)
1079 unreachable("never used - DrawElementsInstancedBaseVertexBaseInstance is used instead");
1083 _mesa_unmarshal_DrawElementsBaseVertex(struct gl_context
*ctx
, const struct marshal_cmd_DrawElementsBaseVertex
*cmd
)
1085 unreachable("never used - DrawElementsInstancedBaseVertexBaseInstance is used instead");
1089 _mesa_unmarshal_DrawRangeElementsBaseVertex(struct gl_context
*ctx
, const struct marshal_cmd_DrawRangeElementsBaseVertex
*cmd
)
1091 unreachable("never used - DrawElementsInstancedBaseVertexBaseInstance is used instead");
1095 _mesa_unmarshal_DrawElementsInstancedBaseVertex(struct gl_context
*ctx
, const struct marshal_cmd_DrawElementsInstancedBaseVertex
*cmd
)
1097 unreachable("never used - DrawElementsInstancedBaseVertexBaseInstance is used instead");
1101 _mesa_unmarshal_DrawElementsInstancedBaseInstance(struct gl_context
*ctx
, const struct marshal_cmd_DrawElementsInstancedBaseInstance
*cmd
)
1103 unreachable("never used - DrawElementsInstancedBaseVertexBaseInstance is used instead");
1107 _mesa_unmarshal_MultiDrawElementsEXT(struct gl_context
*ctx
, const struct marshal_cmd_MultiDrawElementsEXT
*cmd
)
1109 unreachable("never used - MultiDrawElementsBaseVertex is used instead");