1
2 /**************************************************************************
3 *
4 * Copyright 2007 VMware, Inc.
5 * Copyright 2012 Marek Olšák <maraeo@gmail.com>
6 * All Rights Reserved.
7 *
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:
15 *
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial portions
18 * of the Software.
19 *
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.
27 *
28 **************************************************************************/
29
30 /*
31 * This converts the VBO's vertex attribute/array information into
32 * Gallium vertex state and binds it.
33 *
34 * Authors:
35 * Keith Whitwell <keithw@vmware.com>
36 * Marek Olšák <maraeo@gmail.com>
37 */
38
39 #include "st_context.h"
40 #include "st_atom.h"
41 #include "st_draw.h"
42 #include "st_program.h"
43
44 #include "cso_cache/cso_context.h"
45 #include "util/u_math.h"
46 #include "util/u_upload_mgr.h"
47 #include "main/bufferobj.h"
48 #include "main/glformats.h"
49 #include "main/varray.h"
50 #include "main/arrayobj.h"
51
52 enum st_update_flag {
53 UPDATE_ALL,
54 UPDATE_BUFFERS_ONLY,
55 };
56
57 /* Always inline the non-64bit element code, so that the compiler can see
58 * that velements is on the stack.
59 */
60 static void ALWAYS_INLINE
init_velement(struct pipe_vertex_element * velements,const struct gl_vertex_format * vformat,int src_offset,unsigned instance_divisor,int vbo_index,bool dual_slot,int idx)61 init_velement(struct pipe_vertex_element *velements,
62 const struct gl_vertex_format *vformat,
63 int src_offset, unsigned instance_divisor,
64 int vbo_index, bool dual_slot, int idx)
65 {
66 velements[idx].src_offset = src_offset;
67 velements[idx].src_format = vformat->_PipeFormat;
68 velements[idx].instance_divisor = instance_divisor;
69 velements[idx].vertex_buffer_index = vbo_index;
70 velements[idx].dual_slot = dual_slot;
71 assert(velements[idx].src_format);
72 }
73
74 /* ALWAYS_INLINE helps the compiler realize that most of the parameters are
75 * on the stack.
76 */
77 template<util_popcnt POPCNT, st_update_flag UPDATE> void ALWAYS_INLINE
setup_arrays(struct st_context * st,const struct gl_vertex_array_object * vao,const GLbitfield dual_slot_inputs,const GLbitfield inputs_read,const GLbitfield nonzero_divisor_attribs,const GLbitfield enabled_attribs,const GLbitfield enabled_user_attribs,struct cso_velems_state * velements,struct pipe_vertex_buffer * vbuffer,unsigned * num_vbuffers,bool * has_user_vertex_buffers)78 setup_arrays(struct st_context *st,
79 const struct gl_vertex_array_object *vao,
80 const GLbitfield dual_slot_inputs,
81 const GLbitfield inputs_read,
82 const GLbitfield nonzero_divisor_attribs,
83 const GLbitfield enabled_attribs,
84 const GLbitfield enabled_user_attribs,
85 struct cso_velems_state *velements,
86 struct pipe_vertex_buffer *vbuffer, unsigned *num_vbuffers,
87 bool *has_user_vertex_buffers)
88 {
89 struct gl_context *ctx = st->ctx;
90
91 /* Process attribute array data. */
92 GLbitfield mask = inputs_read & enabled_attribs;
93 GLbitfield userbuf_attribs = inputs_read & enabled_user_attribs;
94
95 *has_user_vertex_buffers = userbuf_attribs != 0;
96 st->draw_needs_minmax_index =
97 (userbuf_attribs & ~nonzero_divisor_attribs) != 0;
98
99 if (vao->IsDynamic) {
100 while (mask) {
101 const gl_vert_attrib attr = (gl_vert_attrib)u_bit_scan(&mask);
102 const struct gl_array_attributes *const attrib =
103 _mesa_draw_array_attrib(vao, attr);
104 const struct gl_vertex_buffer_binding *const binding =
105 &vao->BufferBinding[attrib->BufferBindingIndex];
106 const unsigned bufidx = (*num_vbuffers)++;
107
108 /* Set the vertex buffer. */
109 if (binding->BufferObj) {
110 vbuffer[bufidx].buffer.resource =
111 _mesa_get_bufferobj_reference(ctx, binding->BufferObj);
112 vbuffer[bufidx].is_user_buffer = false;
113 vbuffer[bufidx].buffer_offset = binding->Offset +
114 attrib->RelativeOffset;
115 } else {
116 vbuffer[bufidx].buffer.user = attrib->Ptr;
117 vbuffer[bufidx].is_user_buffer = true;
118 vbuffer[bufidx].buffer_offset = 0;
119 }
120 vbuffer[bufidx].stride = binding->Stride; /* in bytes */
121
122 if (UPDATE == UPDATE_BUFFERS_ONLY)
123 continue;
124
125 /* Set the vertex element. */
126 init_velement(velements->velems, &attrib->Format, 0,
127 binding->InstanceDivisor, bufidx,
128 dual_slot_inputs & BITFIELD_BIT(attr),
129 util_bitcount_fast<POPCNT>(inputs_read & BITFIELD_MASK(attr)));
130 }
131 return;
132 }
133
134 while (mask) {
135 /* The attribute index to start pulling a binding */
136 const gl_vert_attrib i = (gl_vert_attrib)(ffs(mask) - 1);
137 const struct gl_vertex_buffer_binding *const binding
138 = _mesa_draw_buffer_binding(vao, i);
139 const unsigned bufidx = (*num_vbuffers)++;
140
141 if (binding->BufferObj) {
142 /* Set the binding */
143 vbuffer[bufidx].buffer.resource =
144 _mesa_get_bufferobj_reference(ctx, binding->BufferObj);
145 vbuffer[bufidx].is_user_buffer = false;
146 vbuffer[bufidx].buffer_offset = _mesa_draw_binding_offset(binding);
147 } else {
148 /* Set the binding */
149 const void *ptr = (const void *)_mesa_draw_binding_offset(binding);
150 vbuffer[bufidx].buffer.user = ptr;
151 vbuffer[bufidx].is_user_buffer = true;
152 vbuffer[bufidx].buffer_offset = 0;
153 }
154 vbuffer[bufidx].stride = binding->Stride; /* in bytes */
155
156 const GLbitfield boundmask = _mesa_draw_bound_attrib_bits(binding);
157 GLbitfield attrmask = mask & boundmask;
158 /* Mark the those attributes as processed */
159 mask &= ~boundmask;
160 /* We can assume that we have array for the binding */
161 assert(attrmask);
162
163 if (UPDATE == UPDATE_BUFFERS_ONLY)
164 continue;
165
166 /* Walk attributes belonging to the binding */
167 do {
168 const gl_vert_attrib attr = (gl_vert_attrib)u_bit_scan(&attrmask);
169 const struct gl_array_attributes *const attrib
170 = _mesa_draw_array_attrib(vao, attr);
171 const GLuint off = _mesa_draw_attributes_relative_offset(attrib);
172 init_velement(velements->velems, &attrib->Format, off,
173 binding->InstanceDivisor, bufidx,
174 dual_slot_inputs & BITFIELD_BIT(attr),
175 util_bitcount_fast<POPCNT>(inputs_read & BITFIELD_MASK(attr)));
176 } while (attrmask);
177 }
178 }
179
180 /* Only used by the select/feedback mode. */
181 void
st_setup_arrays(struct st_context * st,const struct gl_vertex_program * vp,const struct st_common_variant * vp_variant,struct cso_velems_state * velements,struct pipe_vertex_buffer * vbuffer,unsigned * num_vbuffers,bool * has_user_vertex_buffers)182 st_setup_arrays(struct st_context *st,
183 const struct gl_vertex_program *vp,
184 const struct st_common_variant *vp_variant,
185 struct cso_velems_state *velements,
186 struct pipe_vertex_buffer *vbuffer, unsigned *num_vbuffers,
187 bool *has_user_vertex_buffers)
188 {
189 struct gl_context *ctx = st->ctx;
190
191 setup_arrays<POPCNT_NO, UPDATE_ALL>
192 (st, ctx->Array._DrawVAO, vp->Base.DualSlotInputs,
193 vp_variant->vert_attrib_mask, _mesa_draw_nonzero_divisor_bits(ctx),
194 _mesa_draw_array_bits(ctx), _mesa_draw_user_array_bits(ctx),
195 velements, vbuffer, num_vbuffers, has_user_vertex_buffers);
196 }
197
198 /* ALWAYS_INLINE helps the compiler realize that most of the parameters are
199 * on the stack.
200 *
201 * Return the index of the vertex buffer where current attribs have been
202 * uploaded.
203 */
204 template<util_popcnt POPCNT, st_update_flag UPDATE> void ALWAYS_INLINE
st_setup_current(struct st_context * st,const struct gl_vertex_program * vp,const struct st_common_variant * vp_variant,struct cso_velems_state * velements,struct pipe_vertex_buffer * vbuffer,unsigned * num_vbuffers)205 st_setup_current(struct st_context *st,
206 const struct gl_vertex_program *vp,
207 const struct st_common_variant *vp_variant,
208 struct cso_velems_state *velements,
209 struct pipe_vertex_buffer *vbuffer, unsigned *num_vbuffers)
210 {
211 struct gl_context *ctx = st->ctx;
212 const GLbitfield inputs_read = vp_variant->vert_attrib_mask;
213 const GLbitfield dual_slot_inputs = vp->Base.DualSlotInputs;
214
215 /* Process values that should have better been uniforms in the application */
216 GLbitfield curmask = inputs_read & _mesa_draw_current_bits(ctx);
217 if (curmask) {
218 /* For each attribute, upload the maximum possible size. */
219 GLubyte data[VERT_ATTRIB_MAX * sizeof(GLdouble) * 4];
220 GLubyte *cursor = data;
221 const unsigned bufidx = (*num_vbuffers)++;
222 unsigned max_alignment = 1;
223
224 do {
225 const gl_vert_attrib attr = (gl_vert_attrib)u_bit_scan(&curmask);
226 const struct gl_array_attributes *const attrib
227 = _mesa_draw_current_attrib(ctx, attr);
228 const unsigned size = attrib->Format._ElementSize;
229 const unsigned alignment = util_next_power_of_two(size);
230 max_alignment = MAX2(max_alignment, alignment);
231 memcpy(cursor, attrib->Ptr, size);
232 if (alignment != size)
233 memset(cursor + size, 0, alignment - size);
234
235 if (UPDATE == UPDATE_ALL) {
236 init_velement(velements->velems, &attrib->Format, cursor - data,
237 0, bufidx, dual_slot_inputs & BITFIELD_BIT(attr),
238 util_bitcount_fast<POPCNT>(inputs_read & BITFIELD_MASK(attr)));
239 }
240
241 cursor += alignment;
242 } while (curmask);
243
244 vbuffer[bufidx].is_user_buffer = false;
245 vbuffer[bufidx].buffer.resource = NULL;
246 /* vbuffer[bufidx].buffer_offset is set below */
247 vbuffer[bufidx].stride = 0;
248
249 /* Use const_uploader for zero-stride vertex attributes, because
250 * it may use a better memory placement than stream_uploader.
251 * The reason is that zero-stride attributes can be fetched many
252 * times (thousands of times), so a better placement is going to
253 * perform better.
254 */
255 struct u_upload_mgr *uploader = st->can_bind_const_buffer_as_vertex ?
256 st->pipe->const_uploader :
257 st->pipe->stream_uploader;
258 u_upload_data(uploader,
259 0, cursor - data, max_alignment, data,
260 &vbuffer[bufidx].buffer_offset,
261 &vbuffer[bufidx].buffer.resource);
262 /* Always unmap. The uploader might use explicit flushes. */
263 u_upload_unmap(uploader);
264 }
265 }
266
267 /* Only used by the select/feedback mode. */
268 void
st_setup_current_user(struct st_context * st,const struct gl_vertex_program * vp,const struct st_common_variant * vp_variant,struct cso_velems_state * velements,struct pipe_vertex_buffer * vbuffer,unsigned * num_vbuffers)269 st_setup_current_user(struct st_context *st,
270 const struct gl_vertex_program *vp,
271 const struct st_common_variant *vp_variant,
272 struct cso_velems_state *velements,
273 struct pipe_vertex_buffer *vbuffer, unsigned *num_vbuffers)
274 {
275 struct gl_context *ctx = st->ctx;
276 const GLbitfield inputs_read = vp_variant->vert_attrib_mask;
277 const GLbitfield dual_slot_inputs = vp->Base.DualSlotInputs;
278
279 /* Process values that should have better been uniforms in the application */
280 GLbitfield curmask = inputs_read & _mesa_draw_current_bits(ctx);
281 /* For each attribute, make an own user buffer binding. */
282 while (curmask) {
283 const gl_vert_attrib attr = (gl_vert_attrib)u_bit_scan(&curmask);
284 const struct gl_array_attributes *const attrib
285 = _mesa_draw_current_attrib(ctx, attr);
286 const unsigned bufidx = (*num_vbuffers)++;
287
288 init_velement(velements->velems, &attrib->Format, 0, 0,
289 bufidx, dual_slot_inputs & BITFIELD_BIT(attr),
290 util_bitcount(inputs_read & BITFIELD_MASK(attr)));
291
292 vbuffer[bufidx].is_user_buffer = true;
293 vbuffer[bufidx].buffer.user = attrib->Ptr;
294 vbuffer[bufidx].buffer_offset = 0;
295 vbuffer[bufidx].stride = 0;
296 }
297 }
298
299 template<util_popcnt POPCNT, st_update_flag UPDATE> void ALWAYS_INLINE
st_update_array_templ(struct st_context * st)300 st_update_array_templ(struct st_context *st)
301 {
302 struct gl_context *ctx = st->ctx;
303
304 /* vertex program validation must be done before this */
305 /* _NEW_PROGRAM, ST_NEW_VS_STATE */
306 const struct gl_vertex_program *vp = (struct gl_vertex_program *)st->vp;
307 const struct st_common_variant *vp_variant = st->vp_variant;
308
309 struct pipe_vertex_buffer vbuffer[PIPE_MAX_ATTRIBS];
310 unsigned num_vbuffers = 0;
311 struct cso_velems_state velements;
312 bool uses_user_vertex_buffers;
313
314 /* ST_NEW_VERTEX_ARRAYS */
315 /* Setup arrays */
316 setup_arrays<POPCNT, UPDATE>
317 (st, ctx->Array._DrawVAO, vp->Base.DualSlotInputs,
318 vp_variant->vert_attrib_mask, _mesa_draw_nonzero_divisor_bits(ctx),
319 _mesa_draw_array_bits(ctx), _mesa_draw_user_array_bits(ctx),
320 &velements, vbuffer, &num_vbuffers, &uses_user_vertex_buffers);
321
322 /* _NEW_CURRENT_ATTRIB */
323 /* Setup zero-stride attribs. */
324 st_setup_current<POPCNT, UPDATE>(st, vp, vp_variant, &velements, vbuffer,
325 &num_vbuffers);
326
327 unsigned unbind_trailing_vbuffers =
328 st->last_num_vbuffers > num_vbuffers ?
329 st->last_num_vbuffers - num_vbuffers : 0;
330 st->last_num_vbuffers = num_vbuffers;
331
332 struct cso_context *cso = st->cso_context;
333
334 if (UPDATE == UPDATE_ALL) {
335 velements.count = vp->num_inputs + vp_variant->key.passthrough_edgeflags;
336
337 /* Set vertex buffers and elements. */
338 cso_set_vertex_buffers_and_elements(cso, &velements,
339 num_vbuffers,
340 unbind_trailing_vbuffers,
341 true,
342 uses_user_vertex_buffers,
343 vbuffer);
344 /* The driver should clear this after it has processed the update. */
345 ctx->Array.NewVertexElements = false;
346 st->uses_user_vertex_buffers = uses_user_vertex_buffers;
347 } else {
348 /* Only vertex buffers. */
349 cso_set_vertex_buffers(cso, 0, num_vbuffers, unbind_trailing_vbuffers,
350 true, vbuffer);
351 /* This can change only when we update vertex elements. */
352 assert(st->uses_user_vertex_buffers == uses_user_vertex_buffers);
353 }
354 }
355
356 template<util_popcnt POPCNT> void ALWAYS_INLINE
st_update_array_impl(struct st_context * st)357 st_update_array_impl(struct st_context *st)
358 {
359 struct gl_context *ctx = st->ctx;
360
361 /* Changing from user to non-user buffers and vice versa can switch between
362 * cso and u_vbuf, which means that we need to update vertex elements even
363 * when they have not changed.
364 */
365 if (ctx->Array.NewVertexElements ||
366 st->uses_user_vertex_buffers !=
367 !!(st->vp_variant->vert_attrib_mask & _mesa_draw_user_array_bits(ctx))) {
368 st_update_array_templ<POPCNT, UPDATE_ALL>(st);
369 } else {
370 st_update_array_templ<POPCNT, UPDATE_BUFFERS_ONLY>(st);
371 }
372 }
373
374 void
st_update_array(struct st_context * st)375 st_update_array(struct st_context *st)
376 {
377 st_update_array_impl<POPCNT_NO>(st);
378 }
379
380 void
st_update_array_with_popcnt(struct st_context * st)381 st_update_array_with_popcnt(struct st_context *st)
382 {
383 st_update_array_impl<POPCNT_YES>(st);
384 }
385
386 struct pipe_vertex_state *
st_create_gallium_vertex_state(struct gl_context * ctx,const struct gl_vertex_array_object * vao,struct gl_buffer_object * indexbuf,uint32_t enabled_attribs)387 st_create_gallium_vertex_state(struct gl_context *ctx,
388 const struct gl_vertex_array_object *vao,
389 struct gl_buffer_object *indexbuf,
390 uint32_t enabled_attribs)
391 {
392 struct st_context *st = st_context(ctx);
393 const GLbitfield inputs_read = enabled_attribs;
394 const GLbitfield dual_slot_inputs = 0; /* always zero */
395 struct pipe_vertex_buffer vbuffer[PIPE_MAX_ATTRIBS];
396 unsigned num_vbuffers = 0;
397 struct cso_velems_state velements;
398 bool uses_user_vertex_buffers;
399
400 setup_arrays<POPCNT_NO, UPDATE_ALL>(st, vao, dual_slot_inputs, inputs_read, 0,
401 inputs_read, 0, &velements, vbuffer, &num_vbuffers,
402 &uses_user_vertex_buffers);
403
404 if (num_vbuffers != 1 || uses_user_vertex_buffers) {
405 assert(!"this should never happen with display lists");
406 return NULL;
407 }
408
409 velements.count = util_bitcount(inputs_read);
410
411 struct pipe_screen *screen = st->screen;
412 struct pipe_vertex_state *state =
413 screen->create_vertex_state(screen, &vbuffer[0], velements.velems,
414 velements.count,
415 indexbuf ?
416 indexbuf->buffer : NULL,
417 enabled_attribs);
418
419 for (unsigned i = 0; i < num_vbuffers; i++)
420 pipe_vertex_buffer_unreference(&vbuffer[i]);
421 return state;
422 }
423