2 /**************************************************************************
4 * Copyright 2007 VMware, Inc.
5 * Copyright 2012 Marek Olšák <maraeo@gmail.com>
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sub license, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial portions
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
23 * IN NO EVENT SHALL AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR
24 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 **************************************************************************/
31 * This converts the VBO's vertex attribute/array information into
32 * Gallium vertex state and binds it.
35 * Keith Whitwell <keithw@vmware.com>
36 * Marek Olšák <maraeo@gmail.com>
39 #include "st_context.h"
41 #include "st_cb_bufferobjects.h"
43 #include "st_program.h"
45 #include "cso_cache/cso_context.h"
46 #include "util/u_math.h"
47 #include "util/u_upload_mgr.h"
48 #include "main/bufferobj.h"
49 #include "main/glformats.h"
51 /* vertex_formats[gltype - GL_BYTE][integer*2 + normalized][size - 1] */
52 static const uint16_t vertex_formats
[][4][4] = {
55 PIPE_FORMAT_R8_SSCALED
,
56 PIPE_FORMAT_R8G8_SSCALED
,
57 PIPE_FORMAT_R8G8B8_SSCALED
,
58 PIPE_FORMAT_R8G8B8A8_SSCALED
62 PIPE_FORMAT_R8G8_SNORM
,
63 PIPE_FORMAT_R8G8B8_SNORM
,
64 PIPE_FORMAT_R8G8B8A8_SNORM
68 PIPE_FORMAT_R8G8_SINT
,
69 PIPE_FORMAT_R8G8B8_SINT
,
70 PIPE_FORMAT_R8G8B8A8_SINT
73 { /* GL_UNSIGNED_BYTE */
75 PIPE_FORMAT_R8_USCALED
,
76 PIPE_FORMAT_R8G8_USCALED
,
77 PIPE_FORMAT_R8G8B8_USCALED
,
78 PIPE_FORMAT_R8G8B8A8_USCALED
82 PIPE_FORMAT_R8G8_UNORM
,
83 PIPE_FORMAT_R8G8B8_UNORM
,
84 PIPE_FORMAT_R8G8B8A8_UNORM
88 PIPE_FORMAT_R8G8_UINT
,
89 PIPE_FORMAT_R8G8B8_UINT
,
90 PIPE_FORMAT_R8G8B8A8_UINT
95 PIPE_FORMAT_R16_SSCALED
,
96 PIPE_FORMAT_R16G16_SSCALED
,
97 PIPE_FORMAT_R16G16B16_SSCALED
,
98 PIPE_FORMAT_R16G16B16A16_SSCALED
101 PIPE_FORMAT_R16_SNORM
,
102 PIPE_FORMAT_R16G16_SNORM
,
103 PIPE_FORMAT_R16G16B16_SNORM
,
104 PIPE_FORMAT_R16G16B16A16_SNORM
107 PIPE_FORMAT_R16_SINT
,
108 PIPE_FORMAT_R16G16_SINT
,
109 PIPE_FORMAT_R16G16B16_SINT
,
110 PIPE_FORMAT_R16G16B16A16_SINT
113 { /* GL_UNSIGNED_SHORT */
115 PIPE_FORMAT_R16_USCALED
,
116 PIPE_FORMAT_R16G16_USCALED
,
117 PIPE_FORMAT_R16G16B16_USCALED
,
118 PIPE_FORMAT_R16G16B16A16_USCALED
121 PIPE_FORMAT_R16_UNORM
,
122 PIPE_FORMAT_R16G16_UNORM
,
123 PIPE_FORMAT_R16G16B16_UNORM
,
124 PIPE_FORMAT_R16G16B16A16_UNORM
127 PIPE_FORMAT_R16_UINT
,
128 PIPE_FORMAT_R16G16_UINT
,
129 PIPE_FORMAT_R16G16B16_UINT
,
130 PIPE_FORMAT_R16G16B16A16_UINT
135 PIPE_FORMAT_R32_SSCALED
,
136 PIPE_FORMAT_R32G32_SSCALED
,
137 PIPE_FORMAT_R32G32B32_SSCALED
,
138 PIPE_FORMAT_R32G32B32A32_SSCALED
141 PIPE_FORMAT_R32_SNORM
,
142 PIPE_FORMAT_R32G32_SNORM
,
143 PIPE_FORMAT_R32G32B32_SNORM
,
144 PIPE_FORMAT_R32G32B32A32_SNORM
147 PIPE_FORMAT_R32_SINT
,
148 PIPE_FORMAT_R32G32_SINT
,
149 PIPE_FORMAT_R32G32B32_SINT
,
150 PIPE_FORMAT_R32G32B32A32_SINT
153 { /* GL_UNSIGNED_INT */
155 PIPE_FORMAT_R32_USCALED
,
156 PIPE_FORMAT_R32G32_USCALED
,
157 PIPE_FORMAT_R32G32B32_USCALED
,
158 PIPE_FORMAT_R32G32B32A32_USCALED
161 PIPE_FORMAT_R32_UNORM
,
162 PIPE_FORMAT_R32G32_UNORM
,
163 PIPE_FORMAT_R32G32B32_UNORM
,
164 PIPE_FORMAT_R32G32B32A32_UNORM
167 PIPE_FORMAT_R32_UINT
,
168 PIPE_FORMAT_R32G32_UINT
,
169 PIPE_FORMAT_R32G32B32_UINT
,
170 PIPE_FORMAT_R32G32B32A32_UINT
175 PIPE_FORMAT_R32_FLOAT
,
176 PIPE_FORMAT_R32G32_FLOAT
,
177 PIPE_FORMAT_R32G32B32_FLOAT
,
178 PIPE_FORMAT_R32G32B32A32_FLOAT
181 PIPE_FORMAT_R32_FLOAT
,
182 PIPE_FORMAT_R32G32_FLOAT
,
183 PIPE_FORMAT_R32G32B32_FLOAT
,
184 PIPE_FORMAT_R32G32B32A32_FLOAT
187 {{0}}, /* GL_2_BYTES */
188 {{0}}, /* GL_3_BYTES */
189 {{0}}, /* GL_4_BYTES */
192 PIPE_FORMAT_R64_FLOAT
,
193 PIPE_FORMAT_R64G64_FLOAT
,
194 PIPE_FORMAT_R64G64B64_FLOAT
,
195 PIPE_FORMAT_R64G64B64A64_FLOAT
198 PIPE_FORMAT_R64_FLOAT
,
199 PIPE_FORMAT_R64G64_FLOAT
,
200 PIPE_FORMAT_R64G64B64_FLOAT
,
201 PIPE_FORMAT_R64G64B64A64_FLOAT
204 { /* GL_HALF_FLOAT */
206 PIPE_FORMAT_R16_FLOAT
,
207 PIPE_FORMAT_R16G16_FLOAT
,
208 PIPE_FORMAT_R16G16B16_FLOAT
,
209 PIPE_FORMAT_R16G16B16A16_FLOAT
212 PIPE_FORMAT_R16_FLOAT
,
213 PIPE_FORMAT_R16G16_FLOAT
,
214 PIPE_FORMAT_R16G16B16_FLOAT
,
215 PIPE_FORMAT_R16G16B16A16_FLOAT
220 PIPE_FORMAT_R32_FIXED
,
221 PIPE_FORMAT_R32G32_FIXED
,
222 PIPE_FORMAT_R32G32B32_FIXED
,
223 PIPE_FORMAT_R32G32B32A32_FIXED
226 PIPE_FORMAT_R32_FIXED
,
227 PIPE_FORMAT_R32G32_FIXED
,
228 PIPE_FORMAT_R32G32B32_FIXED
,
229 PIPE_FORMAT_R32G32B32A32_FIXED
236 * Return a PIPE_FORMAT_x for the given GL datatype and size.
239 st_pipe_vertex_format(GLenum type
, GLuint size
, GLenum format
,
240 GLboolean normalized
, GLboolean integer
)
244 assert(size
>= 1 && size
<= 4);
245 assert(format
== GL_RGBA
|| format
== GL_BGRA
);
248 case GL_HALF_FLOAT_OES
:
249 type
= GL_HALF_FLOAT
;
252 case GL_INT_2_10_10_10_REV
:
253 assert(size
== 4 && !integer
);
255 if (format
== GL_BGRA
) {
257 return PIPE_FORMAT_B10G10R10A2_SNORM
;
259 return PIPE_FORMAT_B10G10R10A2_SSCALED
;
262 return PIPE_FORMAT_R10G10B10A2_SNORM
;
264 return PIPE_FORMAT_R10G10B10A2_SSCALED
;
268 case GL_UNSIGNED_INT_2_10_10_10_REV
:
269 assert(size
== 4 && !integer
);
271 if (format
== GL_BGRA
) {
273 return PIPE_FORMAT_B10G10R10A2_UNORM
;
275 return PIPE_FORMAT_B10G10R10A2_USCALED
;
278 return PIPE_FORMAT_R10G10B10A2_UNORM
;
280 return PIPE_FORMAT_R10G10B10A2_USCALED
;
284 case GL_UNSIGNED_INT_10F_11F_11F_REV
:
285 assert(size
== 3 && !integer
&& format
== GL_RGBA
);
286 return PIPE_FORMAT_R11G11B10_FLOAT
;
288 case GL_UNSIGNED_BYTE
:
289 if (format
== GL_BGRA
) {
290 /* this is an odd-ball case */
292 return PIPE_FORMAT_B8G8R8A8_UNORM
;
297 index
= integer
*2 + normalized
;
299 assert(type
>= GL_BYTE
&& type
<= GL_FIXED
);
300 return vertex_formats
[type
- GL_BYTE
][index
][size
-1];
303 static const struct gl_vertex_array
*
304 get_client_array(const struct gl_vertex_array
**arrays
,
307 /* st_program uses 0xffffffff to denote a double placeholder attribute */
308 if (mesaAttr
== ST_DOUBLE_ATTRIB_PLACEHOLDER
)
310 return arrays
[mesaAttr
];
314 * Examine the active arrays to determine if we have interleaved
315 * vertex arrays all living in one VBO, or all living in user space.
318 is_interleaved_arrays(const struct st_vertex_program
*vp
,
319 const struct gl_vertex_array
**arrays
,
323 const struct gl_buffer_object
*firstBufObj
= NULL
;
324 GLint firstStride
= -1;
325 const GLubyte
*firstPtr
= NULL
;
326 GLboolean userSpaceBuffer
= GL_FALSE
;
328 for (attr
= 0; attr
< num_inputs
; attr
++) {
329 const struct gl_vertex_array
*array
;
330 const struct gl_buffer_object
*bufObj
;
333 array
= get_client_array(arrays
, vp
->index_to_input
[attr
]);
337 stride
= array
->StrideB
; /* in bytes */
339 /* To keep things simple, don't allow interleaved zero-stride attribs. */
343 bufObj
= array
->BufferObj
;
345 /* save info about the first array */
346 firstStride
= stride
;
347 firstPtr
= array
->Ptr
;
348 firstBufObj
= bufObj
;
349 userSpaceBuffer
= !bufObj
|| !bufObj
->Name
;
352 /* check if other arrays interleave with the first, in same buffer */
353 if (stride
!= firstStride
)
354 return GL_FALSE
; /* strides don't match */
356 if (bufObj
!= firstBufObj
)
357 return GL_FALSE
; /* arrays in different VBOs */
359 if (llabs(array
->Ptr
- firstPtr
) > firstStride
)
360 return GL_FALSE
; /* arrays start too far apart */
362 if ((!_mesa_is_bufferobj(bufObj
)) != userSpaceBuffer
)
363 return GL_FALSE
; /* mix of VBO and user-space arrays */
370 static void init_velement(struct pipe_vertex_element
*velement
,
371 int src_offset
, int format
,
372 int instance_divisor
, int vbo_index
)
374 velement
->src_offset
= src_offset
;
375 velement
->src_format
= format
;
376 velement
->instance_divisor
= instance_divisor
;
377 velement
->vertex_buffer_index
= vbo_index
;
378 assert(velement
->src_format
);
381 static void init_velement_lowered(const struct st_vertex_program
*vp
,
382 struct pipe_vertex_element
*velements
,
383 int src_offset
, int format
,
384 int instance_divisor
, int vbo_index
,
385 int nr_components
, GLboolean doubles
,
392 if (nr_components
< 2)
393 lower_format
= PIPE_FORMAT_R32G32_UINT
;
395 lower_format
= PIPE_FORMAT_R32G32B32A32_UINT
;
397 init_velement(&velements
[idx
], src_offset
,
398 lower_format
, instance_divisor
, vbo_index
);
401 if (idx
< vp
->num_inputs
&&
402 vp
->index_to_input
[idx
] == ST_DOUBLE_ATTRIB_PLACEHOLDER
) {
403 if (nr_components
>= 3) {
404 if (nr_components
== 3)
405 lower_format
= PIPE_FORMAT_R32G32_UINT
;
407 lower_format
= PIPE_FORMAT_R32G32B32A32_UINT
;
409 init_velement(&velements
[idx
], src_offset
+ 4 * sizeof(float),
410 lower_format
, instance_divisor
, vbo_index
);
412 /* The values here are undefined. Fill in some conservative
415 init_velement(&velements
[idx
], src_offset
, PIPE_FORMAT_R32G32_UINT
,
416 instance_divisor
, vbo_index
);
422 init_velement(&velements
[idx
], src_offset
,
423 format
, instance_divisor
, vbo_index
);
430 set_vertex_attribs(struct st_context
*st
,
431 struct pipe_vertex_buffer
*vbuffers
,
432 unsigned num_vbuffers
,
433 struct pipe_vertex_element
*velements
,
434 unsigned num_velements
)
436 struct cso_context
*cso
= st
->cso_context
;
438 cso_set_vertex_buffers(cso
, 0, num_vbuffers
, vbuffers
);
439 if (st
->last_num_vbuffers
> num_vbuffers
) {
440 /* Unbind remaining buffers, if any. */
441 cso_set_vertex_buffers(cso
, num_vbuffers
,
442 st
->last_num_vbuffers
- num_vbuffers
, NULL
);
444 st
->last_num_vbuffers
= num_vbuffers
;
445 cso_set_vertex_elements(cso
, num_velements
, velements
);
449 * Set up for drawing interleaved arrays that all live in one VBO
450 * or all live in user space.
451 * \param vbuffer returns vertex buffer info
452 * \param velements returns vertex element info
455 setup_interleaved_attribs(struct st_context
*st
,
456 const struct st_vertex_program
*vp
,
457 const struct gl_vertex_array
**arrays
,
460 struct pipe_vertex_buffer vbuffer
;
461 struct pipe_vertex_element velements
[PIPE_MAX_ATTRIBS
] = {{0}};
463 const GLubyte
*low_addr
= NULL
;
464 GLboolean usingVBO
; /* all arrays in a VBO? */
465 struct gl_buffer_object
*bufobj
;
468 /* Find the lowest address of the arrays we're drawing,
469 * Init bufobj and stride.
472 const struct gl_vertex_array
*array
;
474 array
= get_client_array(arrays
, vp
->index_to_input
[0]);
477 /* Since we're doing interleaved arrays, we know there'll be at most
478 * one buffer object and the stride will be the same for all arrays.
481 bufobj
= array
->BufferObj
;
482 stride
= array
->StrideB
;
484 low_addr
= arrays
[vp
->index_to_input
[0]]->Ptr
;
486 for (attr
= 1; attr
< num_inputs
; attr
++) {
487 const GLubyte
*start
;
488 array
= get_client_array(arrays
, vp
->index_to_input
[attr
]);
492 low_addr
= MIN2(low_addr
, start
);
496 /* not sure we'll ever have zero inputs, but play it safe */
502 /* are the arrays in user space? */
503 usingVBO
= _mesa_is_bufferobj(bufobj
);
505 for (attr
= 0; attr
< num_inputs
;) {
506 const struct gl_vertex_array
*array
;
510 array
= get_client_array(arrays
, vp
->index_to_input
[attr
]);
513 src_offset
= (unsigned) (array
->Ptr
- low_addr
);
514 assert(array
->_ElementSize
==
515 _mesa_bytes_per_vertex_attrib(array
->Size
, array
->Type
));
517 src_format
= st_pipe_vertex_format(array
->Type
,
523 init_velement_lowered(vp
, velements
, src_offset
, src_format
,
524 array
->InstanceDivisor
, 0,
525 array
->Size
, array
->Doubles
, &attr
);
529 * Return the vbuffer info and setup user-space attrib info, if needed.
531 if (num_inputs
== 0) {
532 /* just defensive coding here */
533 vbuffer
.buffer
.resource
= NULL
;
534 vbuffer
.is_user_buffer
= false;
535 vbuffer
.buffer_offset
= 0;
539 /* all interleaved arrays in a VBO */
540 struct st_buffer_object
*stobj
= st_buffer_object(bufobj
);
542 if (!stobj
|| !stobj
->buffer
) {
543 st
->vertex_array_out_of_memory
= true;
544 return; /* out-of-memory error probably */
547 vbuffer
.buffer
.resource
= stobj
->buffer
;
548 vbuffer
.is_user_buffer
= false;
549 vbuffer
.buffer_offset
= pointer_to_offset(low_addr
);
550 vbuffer
.stride
= stride
;
553 /* all interleaved arrays in user memory */
554 vbuffer
.buffer
.user
= low_addr
;
555 vbuffer
.is_user_buffer
= !!low_addr
; /* if NULL, then unbind */
556 vbuffer
.buffer_offset
= 0;
557 vbuffer
.stride
= stride
;
560 st
->draw_needs_minmax_index
= true;
563 set_vertex_attribs(st
, &vbuffer
, num_inputs
? 1 : 0,
564 velements
, num_inputs
);
568 * Set up a separate pipe_vertex_buffer and pipe_vertex_element for each
570 * \param vbuffer returns vertex buffer info
571 * \param velements returns vertex element info
574 setup_non_interleaved_attribs(struct st_context
*st
,
575 const struct st_vertex_program
*vp
,
576 const struct gl_vertex_array
**arrays
,
579 struct gl_context
*ctx
= st
->ctx
;
580 struct pipe_vertex_buffer vbuffer
[PIPE_MAX_ATTRIBS
];
581 struct pipe_vertex_element velements
[PIPE_MAX_ATTRIBS
] = {{0}};
582 unsigned num_vbuffers
= 0;
583 unsigned unref_buffers
= 0;
586 for (attr
= 0; attr
< num_inputs
;) {
587 const unsigned mesaAttr
= vp
->index_to_input
[attr
];
588 const struct gl_vertex_array
*array
;
589 struct gl_buffer_object
*bufobj
;
594 array
= get_client_array(arrays
, mesaAttr
);
597 bufidx
= num_vbuffers
++;
599 stride
= array
->StrideB
;
600 bufobj
= array
->BufferObj
;
601 assert(array
->_ElementSize
==
602 _mesa_bytes_per_vertex_attrib(array
->Size
, array
->Type
));
604 if (_mesa_is_bufferobj(bufobj
)) {
605 /* Attribute data is in a VBO.
606 * Recall that for VBOs, the gl_vertex_array->Ptr field is
607 * really an offset from the start of the VBO, not a pointer.
609 struct st_buffer_object
*stobj
= st_buffer_object(bufobj
);
611 if (!stobj
|| !stobj
->buffer
) {
612 st
->vertex_array_out_of_memory
= true;
613 return; /* out-of-memory error probably */
616 vbuffer
[bufidx
].buffer
.resource
= stobj
->buffer
;
617 vbuffer
[bufidx
].is_user_buffer
= false;
618 vbuffer
[bufidx
].buffer_offset
= pointer_to_offset(array
->Ptr
);
622 unsigned size
= array
->_ElementSize
;
623 /* This is optimal for GPU cache line usage if the upload size
624 * is <= cache line size.
626 unsigned alignment
= util_next_power_of_two(size
);
627 void *ptr
= array
->Ptr
? (void*)array
->Ptr
:
628 (void*)ctx
->Current
.Attrib
[mesaAttr
];
630 vbuffer
[bufidx
].is_user_buffer
= false;
631 vbuffer
[bufidx
].buffer
.resource
= NULL
;
633 /* Use const_uploader for zero-stride vertex attributes, because
634 * it may use a better memory placement than stream_uploader.
635 * The reason is that zero-stride attributes can be fetched many
636 * times (thousands of times), so a better placement is going to
639 * Upload the maximum possible size, which is 4x GLdouble = 32.
641 u_upload_data(st
->can_bind_const_buffer_as_vertex
?
642 st
->pipe
->const_uploader
:
643 st
->pipe
->stream_uploader
,
644 0, size
, alignment
, ptr
,
645 &vbuffer
[bufidx
].buffer_offset
,
646 &vbuffer
[bufidx
].buffer
.resource
);
647 unref_buffers
|= 1u << bufidx
;
650 vbuffer
[bufidx
].buffer
.user
= array
->Ptr
;
651 vbuffer
[bufidx
].is_user_buffer
= true;
652 vbuffer
[bufidx
].buffer_offset
= 0;
654 if (!array
->InstanceDivisor
)
655 st
->draw_needs_minmax_index
= true;
659 /* common-case setup */
660 vbuffer
[bufidx
].stride
= stride
; /* in bytes */
662 src_format
= st_pipe_vertex_format(array
->Type
,
668 init_velement_lowered(vp
, velements
, 0, src_format
,
669 array
->InstanceDivisor
, bufidx
,
670 array
->Size
, array
->Doubles
, &attr
);
673 if (!ctx
->Const
.AllowMappedBuffersDuringExecution
) {
674 u_upload_unmap(st
->pipe
->stream_uploader
);
677 set_vertex_attribs(st
, vbuffer
, num_vbuffers
, velements
, num_inputs
);
679 /* Unreference uploaded zero-stride vertex buffers. */
680 while (unref_buffers
) {
681 unsigned i
= u_bit_scan(&unref_buffers
);
682 pipe_resource_reference(&vbuffer
[i
].buffer
.resource
, NULL
);
686 void st_update_array(struct st_context
*st
)
688 struct gl_context
*ctx
= st
->ctx
;
689 const struct gl_vertex_array
**arrays
= ctx
->Array
._DrawArrays
;
690 const struct st_vertex_program
*vp
;
693 st
->vertex_array_out_of_memory
= FALSE
;
694 st
->draw_needs_minmax_index
= false;
696 /* No drawing has been done yet, so do nothing. */
700 /* vertex program validation must be done before this */
702 num_inputs
= st
->vp_variant
->num_inputs
;
704 if (is_interleaved_arrays(vp
, arrays
, num_inputs
))
705 setup_interleaved_attribs(st
, vp
, arrays
, num_inputs
);
707 setup_non_interleaved_attribs(st
, vp
, arrays
, num_inputs
);