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
52enum 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 */
60static void ALWAYS_INLINE
61init_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 */
77template<util_popcnt POPCNT, st_update_flag UPDATE> void ALWAYS_INLINE
78setup_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. */
181void
182st_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 */
204template<util_popcnt POPCNT, st_update_flag UPDATE> void ALWAYS_INLINE
205st_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. */
268void
269st_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
299template<util_popcnt POPCNT, st_update_flag UPDATE> void ALWAYS_INLINE
300st_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
356template<util_popcnt POPCNT> void ALWAYS_INLINE
357st_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
374void
375st_update_array(struct st_context *st)
376{
377   st_update_array_impl<POPCNT_NO>(st);
378}
379
380void
381st_update_array_with_popcnt(struct st_context *st)
382{
383   st_update_array_impl<POPCNT_YES>(st);
384}
385
386struct pipe_vertex_state *
387st_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