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 static void set_velement(struct pipe_vertex_element
*velement
,
54 int src_offset
, int format
,
55 int instance_divisor
, int vbo_index
)
57 velement
->src_offset
= src_offset
;
58 velement
->src_format
= format
;
59 velement
->instance_divisor
= instance_divisor
;
60 velement
->vertex_buffer_index
= vbo_index
;
61 assert(velement
->src_format
);
64 static void init_velement_64bit(const struct st_vertex_program
*vp
,
65 struct pipe_vertex_element
*velements
,
66 const struct gl_vertex_format
*vformat
,
67 int src_offset
, int instance_divisor
,
68 int vbo_index
, int idx
)
70 const GLubyte nr_components
= vformat
->Size
;
73 if (nr_components
< 2)
74 lower_format
= PIPE_FORMAT_R32G32_UINT
;
76 lower_format
= PIPE_FORMAT_R32G32B32A32_UINT
;
78 set_velement(&velements
[idx
], src_offset
,
79 lower_format
, instance_divisor
, vbo_index
);
82 if (idx
< vp
->num_inputs
&&
83 vp
->index_to_input
[idx
] == ST_DOUBLE_ATTRIB_PLACEHOLDER
) {
84 if (nr_components
>= 3) {
85 if (nr_components
== 3)
86 lower_format
= PIPE_FORMAT_R32G32_UINT
;
88 lower_format
= PIPE_FORMAT_R32G32B32A32_UINT
;
90 set_velement(&velements
[idx
], src_offset
+ 4 * sizeof(float),
91 lower_format
, instance_divisor
, vbo_index
);
93 /* The values here are undefined. Fill in some conservative
96 set_velement(&velements
[idx
], src_offset
, PIPE_FORMAT_R32G32_UINT
,
97 instance_divisor
, vbo_index
);
102 /* Always inline the non-64bit element code, so that the compiler can see
103 * that velements is on the stack.
105 static void ALWAYS_INLINE
106 init_velement(const struct st_vertex_program
*vp
,
107 struct pipe_vertex_element
*velements
,
108 const struct gl_vertex_format
*vformat
,
109 int src_offset
, int instance_divisor
,
110 int vbo_index
, int idx
)
112 if (!vformat
->Doubles
) {
113 velements
[idx
].src_offset
= src_offset
;
114 velements
[idx
].src_format
= vformat
->_PipeFormat
;
115 velements
[idx
].instance_divisor
= instance_divisor
;
116 velements
[idx
].vertex_buffer_index
= vbo_index
;
117 assert(velements
[idx
].src_format
);
121 init_velement_64bit(vp
, velements
, vformat
, src_offset
, instance_divisor
,
125 /* ALWAYS_INLINE helps the compiler realize that most of the parameters are
129 #ifndef _MSC_VER /* MSVC doesn't like inlining public functions */
132 st_setup_arrays(struct st_context
*st
,
133 const struct st_vertex_program
*vp
,
134 const struct st_common_variant
*vp_variant
,
135 struct cso_velems_state
*velements
,
136 struct pipe_vertex_buffer
*vbuffer
, unsigned *num_vbuffers
,
137 bool *has_user_vertex_buffers
)
139 struct gl_context
*ctx
= st
->ctx
;
140 const struct gl_vertex_array_object
*vao
= ctx
->Array
._DrawVAO
;
141 const GLbitfield inputs_read
= vp_variant
->vert_attrib_mask
;
142 const ubyte
*input_to_index
= vp
->input_to_index
;
144 /* Process attribute array data. */
145 GLbitfield mask
= inputs_read
& _mesa_draw_array_bits(ctx
);
146 GLbitfield userbuf_attribs
= inputs_read
& _mesa_draw_user_array_bits(ctx
);
148 *has_user_vertex_buffers
= userbuf_attribs
!= 0;
149 st
->draw_needs_minmax_index
=
150 (userbuf_attribs
& ~_mesa_draw_nonzero_divisor_bits(ctx
)) != 0;
152 if (vao
->IsDynamic
) {
154 const gl_vert_attrib attr
= u_bit_scan(&mask
);
155 const struct gl_array_attributes
*const attrib
=
156 _mesa_draw_array_attrib(vao
, attr
);
157 const struct gl_vertex_buffer_binding
*const binding
=
158 &vao
->BufferBinding
[attrib
->BufferBindingIndex
];
159 const unsigned bufidx
= (*num_vbuffers
)++;
161 /* Set the vertex buffer. */
162 if (binding
->BufferObj
) {
163 struct st_buffer_object
*stobj
= st_buffer_object(binding
->BufferObj
);
165 vbuffer
[bufidx
].buffer
.resource
= stobj
? stobj
->buffer
: NULL
;
166 vbuffer
[bufidx
].is_user_buffer
= false;
167 vbuffer
[bufidx
].buffer_offset
= binding
->Offset
+
168 attrib
->RelativeOffset
;
170 vbuffer
[bufidx
].buffer
.user
= attrib
->Ptr
;
171 vbuffer
[bufidx
].is_user_buffer
= true;
172 vbuffer
[bufidx
].buffer_offset
= 0;
174 vbuffer
[bufidx
].stride
= binding
->Stride
; /* in bytes */
176 /* Set the vertex element. */
177 init_velement(vp
, velements
->velems
, &attrib
->Format
, 0,
178 binding
->InstanceDivisor
, bufidx
,
179 input_to_index
[attr
]);
185 /* The attribute index to start pulling a binding */
186 const gl_vert_attrib i
= ffs(mask
) - 1;
187 const struct gl_vertex_buffer_binding
*const binding
188 = _mesa_draw_buffer_binding(vao
, i
);
189 const unsigned bufidx
= (*num_vbuffers
)++;
191 if (binding
->BufferObj
) {
192 /* Set the binding */
193 struct st_buffer_object
*stobj
= st_buffer_object(binding
->BufferObj
);
195 vbuffer
[bufidx
].buffer
.resource
= stobj
? stobj
->buffer
: NULL
;
196 vbuffer
[bufidx
].is_user_buffer
= false;
197 vbuffer
[bufidx
].buffer_offset
= _mesa_draw_binding_offset(binding
);
199 /* Set the binding */
200 const void *ptr
= (const void *)_mesa_draw_binding_offset(binding
);
201 vbuffer
[bufidx
].buffer
.user
= ptr
;
202 vbuffer
[bufidx
].is_user_buffer
= true;
203 vbuffer
[bufidx
].buffer_offset
= 0;
205 vbuffer
[bufidx
].stride
= binding
->Stride
; /* in bytes */
207 const GLbitfield boundmask
= _mesa_draw_bound_attrib_bits(binding
);
208 GLbitfield attrmask
= mask
& boundmask
;
209 /* Mark the those attributes as processed */
211 /* We can assume that we have array for the binding */
213 /* Walk attributes belonging to the binding */
215 const gl_vert_attrib attr
= u_bit_scan(&attrmask
);
216 const struct gl_array_attributes
*const attrib
217 = _mesa_draw_array_attrib(vao
, attr
);
218 const GLuint off
= _mesa_draw_attributes_relative_offset(attrib
);
219 init_velement(vp
, velements
->velems
, &attrib
->Format
, off
,
220 binding
->InstanceDivisor
, bufidx
,
221 input_to_index
[attr
]);
226 /* ALWAYS_INLINE helps the compiler realize that most of the parameters are
229 * Return the index of the vertex buffer where current attribs have been
232 static int ALWAYS_INLINE
233 st_setup_current(struct st_context
*st
,
234 const struct st_vertex_program
*vp
,
235 const struct st_common_variant
*vp_variant
,
236 struct cso_velems_state
*velements
,
237 struct pipe_vertex_buffer
*vbuffer
, unsigned *num_vbuffers
)
239 struct gl_context
*ctx
= st
->ctx
;
240 const GLbitfield inputs_read
= vp_variant
->vert_attrib_mask
;
242 /* Process values that should have better been uniforms in the application */
243 GLbitfield curmask
= inputs_read
& _mesa_draw_current_bits(ctx
);
245 const ubyte
*input_to_index
= vp
->input_to_index
;
246 /* For each attribute, upload the maximum possible size. */
247 GLubyte data
[VERT_ATTRIB_MAX
* sizeof(GLdouble
) * 4];
248 GLubyte
*cursor
= data
;
249 const unsigned bufidx
= (*num_vbuffers
)++;
250 unsigned max_alignment
= 1;
253 const gl_vert_attrib attr
= u_bit_scan(&curmask
);
254 const struct gl_array_attributes
*const attrib
255 = _mesa_draw_current_attrib(ctx
, attr
);
256 const unsigned size
= attrib
->Format
._ElementSize
;
257 const unsigned alignment
= util_next_power_of_two(size
);
258 max_alignment
= MAX2(max_alignment
, alignment
);
259 memcpy(cursor
, attrib
->Ptr
, size
);
260 if (alignment
!= size
)
261 memset(cursor
+ size
, 0, alignment
- size
);
263 init_velement(vp
, velements
->velems
, &attrib
->Format
, cursor
- data
,
264 0, bufidx
, input_to_index
[attr
]);
269 vbuffer
[bufidx
].is_user_buffer
= false;
270 vbuffer
[bufidx
].buffer
.resource
= NULL
;
271 /* vbuffer[bufidx].buffer_offset is set below */
272 vbuffer
[bufidx
].stride
= 0;
274 /* Use const_uploader for zero-stride vertex attributes, because
275 * it may use a better memory placement than stream_uploader.
276 * The reason is that zero-stride attributes can be fetched many
277 * times (thousands of times), so a better placement is going to
280 struct u_upload_mgr
*uploader
= st
->can_bind_const_buffer_as_vertex
?
281 st
->pipe
->const_uploader
:
282 st
->pipe
->stream_uploader
;
283 u_upload_data(uploader
,
284 0, cursor
- data
, max_alignment
, data
,
285 &vbuffer
[bufidx
].buffer_offset
,
286 &vbuffer
[bufidx
].buffer
.resource
);
287 /* Always unmap. The uploader might use explicit flushes. */
288 u_upload_unmap(uploader
);
295 st_setup_current_user(struct st_context
*st
,
296 const struct st_vertex_program
*vp
,
297 const struct st_common_variant
*vp_variant
,
298 struct cso_velems_state
*velements
,
299 struct pipe_vertex_buffer
*vbuffer
, unsigned *num_vbuffers
)
301 struct gl_context
*ctx
= st
->ctx
;
302 const GLbitfield inputs_read
= vp_variant
->vert_attrib_mask
;
303 const ubyte
*input_to_index
= vp
->input_to_index
;
305 /* Process values that should have better been uniforms in the application */
306 GLbitfield curmask
= inputs_read
& _mesa_draw_current_bits(ctx
);
307 /* For each attribute, make an own user buffer binding. */
309 const gl_vert_attrib attr
= u_bit_scan(&curmask
);
310 const struct gl_array_attributes
*const attrib
311 = _mesa_draw_current_attrib(ctx
, attr
);
312 const unsigned bufidx
= (*num_vbuffers
)++;
314 init_velement(vp
, velements
->velems
, &attrib
->Format
, 0, 0,
315 bufidx
, input_to_index
[attr
]);
317 vbuffer
[bufidx
].is_user_buffer
= true;
318 vbuffer
[bufidx
].buffer
.user
= attrib
->Ptr
;
319 vbuffer
[bufidx
].buffer_offset
= 0;
320 vbuffer
[bufidx
].stride
= 0;
325 st_update_array(struct st_context
*st
)
327 /* vertex program validation must be done before this */
328 /* _NEW_PROGRAM, ST_NEW_VS_STATE */
329 const struct st_vertex_program
*vp
= (struct st_vertex_program
*)st
->vp
;
330 const struct st_common_variant
*vp_variant
= st
->vp_variant
;
332 struct pipe_vertex_buffer vbuffer
[PIPE_MAX_ATTRIBS
];
333 unsigned num_vbuffers
= 0;
334 struct cso_velems_state velements
;
335 bool uses_user_vertex_buffers
;
337 /* ST_NEW_VERTEX_ARRAYS alias ctx->DriverFlags.NewArray */
339 st_setup_arrays(st
, vp
, vp_variant
, &velements
, vbuffer
, &num_vbuffers
,
340 &uses_user_vertex_buffers
);
342 /* _NEW_CURRENT_ATTRIB */
343 /* Setup zero-stride attribs. */
344 int current_attrib_buffer
=
345 st_setup_current(st
, vp
, vp_variant
, &velements
, vbuffer
, &num_vbuffers
);
347 velements
.count
= vp
->num_inputs
+ vp_variant
->key
.passthrough_edgeflags
;
349 /* Set vertex buffers and elements. */
350 struct cso_context
*cso
= st
->cso_context
;
351 unsigned unbind_trailing_vbuffers
=
352 st
->last_num_vbuffers
> num_vbuffers
?
353 st
->last_num_vbuffers
- num_vbuffers
: 0;
354 cso_set_vertex_buffers_and_elements(cso
, &velements
,
356 unbind_trailing_vbuffers
,
357 vbuffer
, uses_user_vertex_buffers
);
358 st
->last_num_vbuffers
= num_vbuffers
;
360 /* Unreference uploaded current attrib buffer. */
361 if (current_attrib_buffer
>= 0)
362 pipe_resource_reference(&vbuffer
[current_attrib_buffer
].buffer
.resource
, NULL
);