• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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