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"
50 #include "main/varray.h"
51 #include "main/arrayobj.h"
53 /* vertex_formats[gltype - GL_BYTE][integer*2 + normalized][size - 1] */
54 static const uint16_t vertex_formats
[][4][4] = {
57 PIPE_FORMAT_R8_SSCALED
,
58 PIPE_FORMAT_R8G8_SSCALED
,
59 PIPE_FORMAT_R8G8B8_SSCALED
,
60 PIPE_FORMAT_R8G8B8A8_SSCALED
64 PIPE_FORMAT_R8G8_SNORM
,
65 PIPE_FORMAT_R8G8B8_SNORM
,
66 PIPE_FORMAT_R8G8B8A8_SNORM
70 PIPE_FORMAT_R8G8_SINT
,
71 PIPE_FORMAT_R8G8B8_SINT
,
72 PIPE_FORMAT_R8G8B8A8_SINT
75 { /* GL_UNSIGNED_BYTE */
77 PIPE_FORMAT_R8_USCALED
,
78 PIPE_FORMAT_R8G8_USCALED
,
79 PIPE_FORMAT_R8G8B8_USCALED
,
80 PIPE_FORMAT_R8G8B8A8_USCALED
84 PIPE_FORMAT_R8G8_UNORM
,
85 PIPE_FORMAT_R8G8B8_UNORM
,
86 PIPE_FORMAT_R8G8B8A8_UNORM
90 PIPE_FORMAT_R8G8_UINT
,
91 PIPE_FORMAT_R8G8B8_UINT
,
92 PIPE_FORMAT_R8G8B8A8_UINT
97 PIPE_FORMAT_R16_SSCALED
,
98 PIPE_FORMAT_R16G16_SSCALED
,
99 PIPE_FORMAT_R16G16B16_SSCALED
,
100 PIPE_FORMAT_R16G16B16A16_SSCALED
103 PIPE_FORMAT_R16_SNORM
,
104 PIPE_FORMAT_R16G16_SNORM
,
105 PIPE_FORMAT_R16G16B16_SNORM
,
106 PIPE_FORMAT_R16G16B16A16_SNORM
109 PIPE_FORMAT_R16_SINT
,
110 PIPE_FORMAT_R16G16_SINT
,
111 PIPE_FORMAT_R16G16B16_SINT
,
112 PIPE_FORMAT_R16G16B16A16_SINT
115 { /* GL_UNSIGNED_SHORT */
117 PIPE_FORMAT_R16_USCALED
,
118 PIPE_FORMAT_R16G16_USCALED
,
119 PIPE_FORMAT_R16G16B16_USCALED
,
120 PIPE_FORMAT_R16G16B16A16_USCALED
123 PIPE_FORMAT_R16_UNORM
,
124 PIPE_FORMAT_R16G16_UNORM
,
125 PIPE_FORMAT_R16G16B16_UNORM
,
126 PIPE_FORMAT_R16G16B16A16_UNORM
129 PIPE_FORMAT_R16_UINT
,
130 PIPE_FORMAT_R16G16_UINT
,
131 PIPE_FORMAT_R16G16B16_UINT
,
132 PIPE_FORMAT_R16G16B16A16_UINT
137 PIPE_FORMAT_R32_SSCALED
,
138 PIPE_FORMAT_R32G32_SSCALED
,
139 PIPE_FORMAT_R32G32B32_SSCALED
,
140 PIPE_FORMAT_R32G32B32A32_SSCALED
143 PIPE_FORMAT_R32_SNORM
,
144 PIPE_FORMAT_R32G32_SNORM
,
145 PIPE_FORMAT_R32G32B32_SNORM
,
146 PIPE_FORMAT_R32G32B32A32_SNORM
149 PIPE_FORMAT_R32_SINT
,
150 PIPE_FORMAT_R32G32_SINT
,
151 PIPE_FORMAT_R32G32B32_SINT
,
152 PIPE_FORMAT_R32G32B32A32_SINT
155 { /* GL_UNSIGNED_INT */
157 PIPE_FORMAT_R32_USCALED
,
158 PIPE_FORMAT_R32G32_USCALED
,
159 PIPE_FORMAT_R32G32B32_USCALED
,
160 PIPE_FORMAT_R32G32B32A32_USCALED
163 PIPE_FORMAT_R32_UNORM
,
164 PIPE_FORMAT_R32G32_UNORM
,
165 PIPE_FORMAT_R32G32B32_UNORM
,
166 PIPE_FORMAT_R32G32B32A32_UNORM
169 PIPE_FORMAT_R32_UINT
,
170 PIPE_FORMAT_R32G32_UINT
,
171 PIPE_FORMAT_R32G32B32_UINT
,
172 PIPE_FORMAT_R32G32B32A32_UINT
177 PIPE_FORMAT_R32_FLOAT
,
178 PIPE_FORMAT_R32G32_FLOAT
,
179 PIPE_FORMAT_R32G32B32_FLOAT
,
180 PIPE_FORMAT_R32G32B32A32_FLOAT
183 PIPE_FORMAT_R32_FLOAT
,
184 PIPE_FORMAT_R32G32_FLOAT
,
185 PIPE_FORMAT_R32G32B32_FLOAT
,
186 PIPE_FORMAT_R32G32B32A32_FLOAT
189 {{0}}, /* GL_2_BYTES */
190 {{0}}, /* GL_3_BYTES */
191 {{0}}, /* GL_4_BYTES */
194 PIPE_FORMAT_R64_FLOAT
,
195 PIPE_FORMAT_R64G64_FLOAT
,
196 PIPE_FORMAT_R64G64B64_FLOAT
,
197 PIPE_FORMAT_R64G64B64A64_FLOAT
200 PIPE_FORMAT_R64_FLOAT
,
201 PIPE_FORMAT_R64G64_FLOAT
,
202 PIPE_FORMAT_R64G64B64_FLOAT
,
203 PIPE_FORMAT_R64G64B64A64_FLOAT
206 { /* GL_HALF_FLOAT */
208 PIPE_FORMAT_R16_FLOAT
,
209 PIPE_FORMAT_R16G16_FLOAT
,
210 PIPE_FORMAT_R16G16B16_FLOAT
,
211 PIPE_FORMAT_R16G16B16A16_FLOAT
214 PIPE_FORMAT_R16_FLOAT
,
215 PIPE_FORMAT_R16G16_FLOAT
,
216 PIPE_FORMAT_R16G16B16_FLOAT
,
217 PIPE_FORMAT_R16G16B16A16_FLOAT
222 PIPE_FORMAT_R32_FIXED
,
223 PIPE_FORMAT_R32G32_FIXED
,
224 PIPE_FORMAT_R32G32B32_FIXED
,
225 PIPE_FORMAT_R32G32B32A32_FIXED
228 PIPE_FORMAT_R32_FIXED
,
229 PIPE_FORMAT_R32G32_FIXED
,
230 PIPE_FORMAT_R32G32B32_FIXED
,
231 PIPE_FORMAT_R32G32B32A32_FIXED
238 * Return a PIPE_FORMAT_x for the given GL datatype and size.
240 static enum pipe_format
241 st_pipe_vertex_format(const struct gl_vertex_format
*vformat
)
243 const GLubyte size
= vformat
->Size
;
244 const GLenum16 format
= vformat
->Format
;
245 const bool normalized
= vformat
->Normalized
;
246 const bool integer
= vformat
->Integer
;
247 GLenum16 type
= vformat
->Type
;
250 assert(size
>= 1 && size
<= 4);
251 assert(format
== GL_RGBA
|| format
== GL_BGRA
);
252 assert(vformat
->_ElementSize
== _mesa_bytes_per_vertex_attrib(size
, type
));
255 case GL_HALF_FLOAT_OES
:
256 type
= GL_HALF_FLOAT
;
259 case GL_INT_2_10_10_10_REV
:
260 assert(size
== 4 && !integer
);
262 if (format
== GL_BGRA
) {
264 return PIPE_FORMAT_B10G10R10A2_SNORM
;
266 return PIPE_FORMAT_B10G10R10A2_SSCALED
;
269 return PIPE_FORMAT_R10G10B10A2_SNORM
;
271 return PIPE_FORMAT_R10G10B10A2_SSCALED
;
275 case GL_UNSIGNED_INT_2_10_10_10_REV
:
276 assert(size
== 4 && !integer
);
278 if (format
== GL_BGRA
) {
280 return PIPE_FORMAT_B10G10R10A2_UNORM
;
282 return PIPE_FORMAT_B10G10R10A2_USCALED
;
285 return PIPE_FORMAT_R10G10B10A2_UNORM
;
287 return PIPE_FORMAT_R10G10B10A2_USCALED
;
291 case GL_UNSIGNED_INT_10F_11F_11F_REV
:
292 assert(size
== 3 && !integer
&& format
== GL_RGBA
);
293 return PIPE_FORMAT_R11G11B10_FLOAT
;
295 case GL_UNSIGNED_BYTE
:
296 if (format
== GL_BGRA
) {
297 /* this is an odd-ball case */
299 return PIPE_FORMAT_B8G8R8A8_UNORM
;
304 index
= integer
*2 + normalized
;
306 assert(type
>= GL_BYTE
&& type
<= GL_FIXED
);
307 return vertex_formats
[type
- GL_BYTE
][index
][size
-1];
310 static void init_velement(struct pipe_vertex_element
*velement
,
311 int src_offset
, int format
,
312 int instance_divisor
, int vbo_index
)
314 velement
->src_offset
= src_offset
;
315 velement
->src_format
= format
;
316 velement
->instance_divisor
= instance_divisor
;
317 velement
->vertex_buffer_index
= vbo_index
;
318 assert(velement
->src_format
);
321 static void init_velement_lowered(const struct st_vertex_program
*vp
,
322 struct pipe_vertex_element
*velements
,
323 const struct gl_vertex_format
*vformat
,
324 int src_offset
, int instance_divisor
,
325 int vbo_index
, int idx
)
327 const GLubyte nr_components
= vformat
->Size
;
329 if (vformat
->Doubles
) {
332 if (nr_components
< 2)
333 lower_format
= PIPE_FORMAT_R32G32_UINT
;
335 lower_format
= PIPE_FORMAT_R32G32B32A32_UINT
;
337 init_velement(&velements
[idx
], src_offset
,
338 lower_format
, instance_divisor
, vbo_index
);
341 if (idx
< vp
->num_inputs
&&
342 vp
->index_to_input
[idx
] == ST_DOUBLE_ATTRIB_PLACEHOLDER
) {
343 if (nr_components
>= 3) {
344 if (nr_components
== 3)
345 lower_format
= PIPE_FORMAT_R32G32_UINT
;
347 lower_format
= PIPE_FORMAT_R32G32B32A32_UINT
;
349 init_velement(&velements
[idx
], src_offset
+ 4 * sizeof(float),
350 lower_format
, instance_divisor
, vbo_index
);
352 /* The values here are undefined. Fill in some conservative
355 init_velement(&velements
[idx
], src_offset
, PIPE_FORMAT_R32G32_UINT
,
356 instance_divisor
, vbo_index
);
360 const unsigned format
= st_pipe_vertex_format(vformat
);
362 init_velement(&velements
[idx
], src_offset
,
363 format
, instance_divisor
, vbo_index
);
368 set_vertex_attribs(struct st_context
*st
,
369 struct pipe_vertex_buffer
*vbuffers
,
370 unsigned num_vbuffers
,
371 struct pipe_vertex_element
*velements
,
372 unsigned num_velements
)
374 struct cso_context
*cso
= st
->cso_context
;
376 cso_set_vertex_buffers(cso
, 0, num_vbuffers
, vbuffers
);
377 if (st
->last_num_vbuffers
> num_vbuffers
) {
378 /* Unbind remaining buffers, if any. */
379 cso_set_vertex_buffers(cso
, num_vbuffers
,
380 st
->last_num_vbuffers
- num_vbuffers
, NULL
);
382 st
->last_num_vbuffers
= num_vbuffers
;
383 cso_set_vertex_elements(cso
, num_velements
, velements
);
387 st_setup_arrays(struct st_context
*st
,
388 const struct st_vertex_program
*vp
,
389 const struct st_common_variant
*vp_variant
,
390 struct pipe_vertex_element
*velements
,
391 struct pipe_vertex_buffer
*vbuffer
, unsigned *num_vbuffers
)
393 struct gl_context
*ctx
= st
->ctx
;
394 const struct gl_vertex_array_object
*vao
= ctx
->Array
._DrawVAO
;
395 const GLbitfield inputs_read
= vp_variant
->vert_attrib_mask
;
396 const ubyte
*input_to_index
= vp
->input_to_index
;
398 /* Process attribute array data. */
399 GLbitfield mask
= inputs_read
& _mesa_draw_array_bits(ctx
);
401 /* The attribute index to start pulling a binding */
402 const gl_vert_attrib i
= ffs(mask
) - 1;
403 const struct gl_vertex_buffer_binding
*const binding
404 = _mesa_draw_buffer_binding(vao
, i
);
405 const unsigned bufidx
= (*num_vbuffers
)++;
407 if (_mesa_is_bufferobj(binding
->BufferObj
)) {
408 /* Set the binding */
409 struct st_buffer_object
*stobj
= st_buffer_object(binding
->BufferObj
);
410 vbuffer
[bufidx
].buffer
.resource
= stobj
? stobj
->buffer
: NULL
;
411 vbuffer
[bufidx
].is_user_buffer
= false;
412 vbuffer
[bufidx
].buffer_offset
= _mesa_draw_binding_offset(binding
);
413 if (st
->has_signed_vertex_buffer_offset
) {
414 /* 'buffer_offset' will be interpreted as an signed int, so make sure
415 * the user supplied offset is not negative (application bug).
417 if ((int) vbuffer
[bufidx
].buffer_offset
< 0) {
418 assert ((int) vbuffer
[bufidx
].buffer_offset
>= 0);
419 /* Fallback if assert are disabled: we can't disable this attribute
420 * since other parts expects it (e.g: velements, vp_variant), so
421 * use a non-buggy offset value instead */
422 vbuffer
[bufidx
].buffer_offset
= 0;
426 /* Set the binding */
427 const void *ptr
= (const void *)_mesa_draw_binding_offset(binding
);
428 vbuffer
[bufidx
].buffer
.user
= ptr
;
429 vbuffer
[bufidx
].is_user_buffer
= true;
430 vbuffer
[bufidx
].buffer_offset
= 0;
432 if (!binding
->InstanceDivisor
)
433 st
->draw_needs_minmax_index
= true;
435 vbuffer
[bufidx
].stride
= binding
->Stride
; /* in bytes */
437 const GLbitfield boundmask
= _mesa_draw_bound_attrib_bits(binding
);
438 GLbitfield attrmask
= mask
& boundmask
;
439 /* Mark the those attributes as processed */
441 /* We can assume that we have array for the binding */
443 /* Walk attributes belonging to the binding */
445 const gl_vert_attrib attr
= u_bit_scan(&attrmask
);
446 const struct gl_array_attributes
*const attrib
447 = _mesa_draw_array_attrib(vao
, attr
);
448 const GLuint off
= _mesa_draw_attributes_relative_offset(attrib
);
449 init_velement_lowered(vp
, velements
, &attrib
->Format
, off
,
450 binding
->InstanceDivisor
, bufidx
,
451 input_to_index
[attr
]);
457 st_setup_current(struct st_context
*st
,
458 const struct st_vertex_program
*vp
,
459 const struct st_common_variant
*vp_variant
,
460 struct pipe_vertex_element
*velements
,
461 struct pipe_vertex_buffer
*vbuffer
, unsigned *num_vbuffers
)
463 struct gl_context
*ctx
= st
->ctx
;
464 const GLbitfield inputs_read
= vp_variant
->vert_attrib_mask
;
466 /* Process values that should have better been uniforms in the application */
467 GLbitfield curmask
= inputs_read
& _mesa_draw_current_bits(ctx
);
469 const ubyte
*input_to_index
= vp
->input_to_index
;
470 /* For each attribute, upload the maximum possible size. */
471 GLubyte data
[VERT_ATTRIB_MAX
* sizeof(GLdouble
) * 4];
472 GLubyte
*cursor
= data
;
473 const unsigned bufidx
= (*num_vbuffers
)++;
474 unsigned max_alignment
= 1;
477 const gl_vert_attrib attr
= u_bit_scan(&curmask
);
478 const struct gl_array_attributes
*const attrib
479 = _mesa_draw_current_attrib(ctx
, attr
);
480 const unsigned size
= attrib
->Format
._ElementSize
;
481 const unsigned alignment
= util_next_power_of_two(size
);
482 max_alignment
= MAX2(max_alignment
, alignment
);
483 memcpy(cursor
, attrib
->Ptr
, size
);
484 if (alignment
!= size
)
485 memset(cursor
+ size
, 0, alignment
- size
);
487 init_velement_lowered(vp
, velements
, &attrib
->Format
, cursor
- data
, 0,
488 bufidx
, input_to_index
[attr
]);
493 vbuffer
[bufidx
].is_user_buffer
= false;
494 vbuffer
[bufidx
].buffer
.resource
= NULL
;
495 /* vbuffer[bufidx].buffer_offset is set below */
496 vbuffer
[bufidx
].stride
= 0;
498 /* Use const_uploader for zero-stride vertex attributes, because
499 * it may use a better memory placement than stream_uploader.
500 * The reason is that zero-stride attributes can be fetched many
501 * times (thousands of times), so a better placement is going to
504 struct u_upload_mgr
*uploader
= st
->can_bind_const_buffer_as_vertex
?
505 st
->pipe
->const_uploader
:
506 st
->pipe
->stream_uploader
;
507 u_upload_data(uploader
,
508 0, cursor
- data
, max_alignment
, data
,
509 &vbuffer
[bufidx
].buffer_offset
,
510 &vbuffer
[bufidx
].buffer
.resource
);
511 /* Always unmap. The uploader might use explicit flushes. */
512 u_upload_unmap(uploader
);
517 st_setup_current_user(struct st_context
*st
,
518 const struct st_vertex_program
*vp
,
519 const struct st_common_variant
*vp_variant
,
520 struct pipe_vertex_element
*velements
,
521 struct pipe_vertex_buffer
*vbuffer
, unsigned *num_vbuffers
)
523 struct gl_context
*ctx
= st
->ctx
;
524 const GLbitfield inputs_read
= vp_variant
->vert_attrib_mask
;
525 const ubyte
*input_to_index
= vp
->input_to_index
;
527 /* Process values that should have better been uniforms in the application */
528 GLbitfield curmask
= inputs_read
& _mesa_draw_current_bits(ctx
);
529 /* For each attribute, make an own user buffer binding. */
531 const gl_vert_attrib attr
= u_bit_scan(&curmask
);
532 const struct gl_array_attributes
*const attrib
533 = _mesa_draw_current_attrib(ctx
, attr
);
534 const unsigned bufidx
= (*num_vbuffers
)++;
536 init_velement_lowered(vp
, velements
, &attrib
->Format
, 0, 0,
537 bufidx
, input_to_index
[attr
]);
539 vbuffer
[bufidx
].is_user_buffer
= true;
540 vbuffer
[bufidx
].buffer
.user
= attrib
->Ptr
;
541 vbuffer
[bufidx
].buffer_offset
= 0;
542 vbuffer
[bufidx
].stride
= 0;
547 st_update_array(struct st_context
*st
)
549 /* vertex program validation must be done before this */
550 /* _NEW_PROGRAM, ST_NEW_VS_STATE */
551 const struct st_vertex_program
*vp
= (struct st_vertex_program
*)st
->vp
;
552 const struct st_common_variant
*vp_variant
= st
->vp_variant
;
554 struct pipe_vertex_buffer vbuffer
[PIPE_MAX_ATTRIBS
];
555 unsigned num_vbuffers
= 0, first_upload_vbuffer
;
556 struct pipe_vertex_element velements
[PIPE_MAX_ATTRIBS
];
557 unsigned num_velements
;
559 st
->draw_needs_minmax_index
= false;
561 /* ST_NEW_VERTEX_ARRAYS alias ctx->DriverFlags.NewArray */
563 st_setup_arrays(st
, vp
, vp_variant
, velements
, vbuffer
, &num_vbuffers
);
565 /* _NEW_CURRENT_ATTRIB */
566 /* Setup current uploads */
567 first_upload_vbuffer
= num_vbuffers
;
568 st_setup_current(st
, vp
, vp_variant
, velements
, vbuffer
, &num_vbuffers
);
570 /* Set the array into cso */
571 num_velements
= vp
->num_inputs
+ vp_variant
->key
.passthrough_edgeflags
;
572 set_vertex_attribs(st
, vbuffer
, num_vbuffers
, velements
, num_velements
);
574 /* Unreference uploaded buffer resources. */
575 for (unsigned i
= first_upload_vbuffer
; i
< num_vbuffers
; ++i
) {
576 pipe_resource_reference(&vbuffer
[i
].buffer
.resource
, NULL
);