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_cb_bufferobjects.h"
42#include "st_draw.h"
43#include "st_program.h"
44
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"
52
53/* Always inline the non-64bit element code, so that the compiler can see
54 * that velements is on the stack.
55 */
56static void ALWAYS_INLINE
57init_velement(struct pipe_vertex_element *velements,
58              const struct gl_vertex_format *vformat,
59              int src_offset, unsigned instance_divisor,
60              int vbo_index, bool dual_slot, int idx)
61{
62   velements[idx].src_offset = src_offset;
63   velements[idx].src_format = vformat->_PipeFormat;
64   velements[idx].instance_divisor = instance_divisor;
65   velements[idx].vertex_buffer_index = vbo_index;
66   velements[idx].dual_slot = dual_slot;
67   assert(velements[idx].src_format);
68}
69
70/* ALWAYS_INLINE helps the compiler realize that most of the parameters are
71 * on the stack.
72 */
73static void ALWAYS_INLINE
74setup_arrays(struct st_context *st,
75             const struct gl_vertex_array_object *vao,
76             const GLbitfield dual_slot_inputs,
77             const GLbitfield inputs_read,
78             const GLbitfield nonzero_divisor_attribs,
79             const GLbitfield enabled_attribs,
80             const GLbitfield enabled_user_attribs,
81             struct cso_velems_state *velements,
82             struct pipe_vertex_buffer *vbuffer, unsigned *num_vbuffers,
83             bool *has_user_vertex_buffers)
84{
85   struct gl_context *ctx = st->ctx;
86
87   /* Process attribute array data. */
88   GLbitfield mask = inputs_read & enabled_attribs;
89   GLbitfield userbuf_attribs = inputs_read & enabled_user_attribs;
90
91   *has_user_vertex_buffers = userbuf_attribs != 0;
92   st->draw_needs_minmax_index =
93      (userbuf_attribs & ~nonzero_divisor_attribs) != 0;
94
95   if (vao->IsDynamic) {
96      while (mask) {
97         const gl_vert_attrib attr = u_bit_scan(&mask);
98         const struct gl_array_attributes *const attrib =
99            _mesa_draw_array_attrib(vao, attr);
100         const struct gl_vertex_buffer_binding *const binding =
101            &vao->BufferBinding[attrib->BufferBindingIndex];
102         const unsigned bufidx = (*num_vbuffers)++;
103
104         /* Set the vertex buffer. */
105         if (binding->BufferObj) {
106            vbuffer[bufidx].buffer.resource =
107               st_get_buffer_reference(ctx, binding->BufferObj);
108            vbuffer[bufidx].is_user_buffer = false;
109            vbuffer[bufidx].buffer_offset = binding->Offset +
110                                            attrib->RelativeOffset;
111         } else {
112            vbuffer[bufidx].buffer.user = attrib->Ptr;
113            vbuffer[bufidx].is_user_buffer = true;
114            vbuffer[bufidx].buffer_offset = 0;
115         }
116         vbuffer[bufidx].stride = binding->Stride; /* in bytes */
117
118         /* Set the vertex element. */
119         init_velement(velements->velems, &attrib->Format, 0,
120                       binding->InstanceDivisor, bufidx,
121                       dual_slot_inputs & BITFIELD_BIT(attr),
122                       util_bitcount(inputs_read & BITFIELD_MASK(attr)));
123      }
124      return;
125   }
126
127   while (mask) {
128      /* The attribute index to start pulling a binding */
129      const gl_vert_attrib i = ffs(mask) - 1;
130      const struct gl_vertex_buffer_binding *const binding
131         = _mesa_draw_buffer_binding(vao, i);
132      const unsigned bufidx = (*num_vbuffers)++;
133
134      if (binding->BufferObj) {
135         /* Set the binding */
136         vbuffer[bufidx].buffer.resource =
137            st_get_buffer_reference(ctx, binding->BufferObj);
138         vbuffer[bufidx].is_user_buffer = false;
139         vbuffer[bufidx].buffer_offset = _mesa_draw_binding_offset(binding);
140      } else {
141         /* Set the binding */
142         const void *ptr = (const void *)_mesa_draw_binding_offset(binding);
143         vbuffer[bufidx].buffer.user = ptr;
144         vbuffer[bufidx].is_user_buffer = true;
145         vbuffer[bufidx].buffer_offset = 0;
146      }
147      vbuffer[bufidx].stride = binding->Stride; /* in bytes */
148
149      const GLbitfield boundmask = _mesa_draw_bound_attrib_bits(binding);
150      GLbitfield attrmask = mask & boundmask;
151      /* Mark the those attributes as processed */
152      mask &= ~boundmask;
153      /* We can assume that we have array for the binding */
154      assert(attrmask);
155      /* Walk attributes belonging to the binding */
156      do {
157         const gl_vert_attrib attr = u_bit_scan(&attrmask);
158         const struct gl_array_attributes *const attrib
159            = _mesa_draw_array_attrib(vao, attr);
160         const GLuint off = _mesa_draw_attributes_relative_offset(attrib);
161         init_velement(velements->velems, &attrib->Format, off,
162                       binding->InstanceDivisor, bufidx,
163                       dual_slot_inputs & BITFIELD_BIT(attr),
164                       util_bitcount(inputs_read & BITFIELD_MASK(attr)));
165      } while (attrmask);
166   }
167}
168
169void
170st_setup_arrays(struct st_context *st,
171                const struct st_vertex_program *vp,
172                const struct st_common_variant *vp_variant,
173                struct cso_velems_state *velements,
174                struct pipe_vertex_buffer *vbuffer, unsigned *num_vbuffers,
175                bool *has_user_vertex_buffers)
176{
177   struct gl_context *ctx = st->ctx;
178
179   setup_arrays(st, ctx->Array._DrawVAO, vp->Base.Base.DualSlotInputs,
180                vp_variant->vert_attrib_mask,
181                _mesa_draw_nonzero_divisor_bits(ctx),
182                _mesa_draw_array_bits(ctx), _mesa_draw_user_array_bits(ctx),
183                velements, vbuffer, num_vbuffers, has_user_vertex_buffers);
184}
185
186/* ALWAYS_INLINE helps the compiler realize that most of the parameters are
187 * on the stack.
188 *
189 * Return the index of the vertex buffer where current attribs have been
190 * uploaded.
191 */
192static void ALWAYS_INLINE
193st_setup_current(struct st_context *st,
194                 const struct st_vertex_program *vp,
195                 const struct st_common_variant *vp_variant,
196                 struct cso_velems_state *velements,
197                 struct pipe_vertex_buffer *vbuffer, unsigned *num_vbuffers)
198{
199   struct gl_context *ctx = st->ctx;
200   const GLbitfield inputs_read = vp_variant->vert_attrib_mask;
201   const GLbitfield dual_slot_inputs = vp->Base.Base.DualSlotInputs;
202
203   /* Process values that should have better been uniforms in the application */
204   GLbitfield curmask = inputs_read & _mesa_draw_current_bits(ctx);
205   if (curmask) {
206      /* For each attribute, upload the maximum possible size. */
207      GLubyte data[VERT_ATTRIB_MAX * sizeof(GLdouble) * 4];
208      GLubyte *cursor = data;
209      const unsigned bufidx = (*num_vbuffers)++;
210      unsigned max_alignment = 1;
211
212      do {
213         const gl_vert_attrib attr = u_bit_scan(&curmask);
214         const struct gl_array_attributes *const attrib
215            = _mesa_draw_current_attrib(ctx, attr);
216         const unsigned size = attrib->Format._ElementSize;
217         const unsigned alignment = util_next_power_of_two(size);
218         max_alignment = MAX2(max_alignment, alignment);
219         memcpy(cursor, attrib->Ptr, size);
220         if (alignment != size)
221            memset(cursor + size, 0, alignment - size);
222
223         init_velement(velements->velems, &attrib->Format, cursor - data,
224                       0, bufidx, dual_slot_inputs & BITFIELD_BIT(attr),
225                       util_bitcount(inputs_read & BITFIELD_MASK(attr)));
226
227         cursor += alignment;
228      } while (curmask);
229
230      vbuffer[bufidx].is_user_buffer = false;
231      vbuffer[bufidx].buffer.resource = NULL;
232      /* vbuffer[bufidx].buffer_offset is set below */
233      vbuffer[bufidx].stride = 0;
234
235      /* Use const_uploader for zero-stride vertex attributes, because
236       * it may use a better memory placement than stream_uploader.
237       * The reason is that zero-stride attributes can be fetched many
238       * times (thousands of times), so a better placement is going to
239       * perform better.
240       */
241      struct u_upload_mgr *uploader = st->can_bind_const_buffer_as_vertex ?
242                                      st->pipe->const_uploader :
243                                      st->pipe->stream_uploader;
244      u_upload_data(uploader,
245                    0, cursor - data, max_alignment, data,
246                    &vbuffer[bufidx].buffer_offset,
247                    &vbuffer[bufidx].buffer.resource);
248      /* Always unmap. The uploader might use explicit flushes. */
249      u_upload_unmap(uploader);
250   }
251}
252
253void
254st_setup_current_user(struct st_context *st,
255                      const struct st_vertex_program *vp,
256                      const struct st_common_variant *vp_variant,
257                      struct cso_velems_state *velements,
258                      struct pipe_vertex_buffer *vbuffer, unsigned *num_vbuffers)
259{
260   struct gl_context *ctx = st->ctx;
261   const GLbitfield inputs_read = vp_variant->vert_attrib_mask;
262   const GLbitfield dual_slot_inputs = vp->Base.Base.DualSlotInputs;
263
264   /* Process values that should have better been uniforms in the application */
265   GLbitfield curmask = inputs_read & _mesa_draw_current_bits(ctx);
266   /* For each attribute, make an own user buffer binding. */
267   while (curmask) {
268      const gl_vert_attrib attr = u_bit_scan(&curmask);
269      const struct gl_array_attributes *const attrib
270         = _mesa_draw_current_attrib(ctx, attr);
271      const unsigned bufidx = (*num_vbuffers)++;
272
273      init_velement(velements->velems, &attrib->Format, 0, 0,
274                    bufidx, dual_slot_inputs & BITFIELD_BIT(attr),
275                    util_bitcount(inputs_read & BITFIELD_MASK(attr)));
276
277      vbuffer[bufidx].is_user_buffer = true;
278      vbuffer[bufidx].buffer.user = attrib->Ptr;
279      vbuffer[bufidx].buffer_offset = 0;
280      vbuffer[bufidx].stride = 0;
281   }
282}
283
284void
285st_update_array(struct st_context *st)
286{
287   struct gl_context *ctx = st->ctx;
288   /* vertex program validation must be done before this */
289   /* _NEW_PROGRAM, ST_NEW_VS_STATE */
290   const struct st_vertex_program *vp = (struct st_vertex_program *)st->vp;
291   const struct st_common_variant *vp_variant = st->vp_variant;
292
293   struct pipe_vertex_buffer vbuffer[PIPE_MAX_ATTRIBS];
294   unsigned num_vbuffers = 0;
295   struct cso_velems_state velements;
296   bool uses_user_vertex_buffers;
297
298   /* ST_NEW_VERTEX_ARRAYS alias ctx->DriverFlags.NewArray */
299   /* Setup arrays */
300   setup_arrays(st, ctx->Array._DrawVAO, vp->Base.Base.DualSlotInputs,
301                vp_variant->vert_attrib_mask,
302                _mesa_draw_nonzero_divisor_bits(ctx),
303                _mesa_draw_array_bits(ctx), _mesa_draw_user_array_bits(ctx),
304                &velements, vbuffer, &num_vbuffers, &uses_user_vertex_buffers);
305
306   /* _NEW_CURRENT_ATTRIB */
307   /* Setup zero-stride attribs. */
308   st_setup_current(st, vp, vp_variant, &velements, vbuffer, &num_vbuffers);
309
310   velements.count = vp->num_inputs + vp_variant->key.passthrough_edgeflags;
311
312   /* Set vertex buffers and elements. */
313   struct cso_context *cso = st->cso_context;
314   unsigned unbind_trailing_vbuffers =
315      st->last_num_vbuffers > num_vbuffers ?
316         st->last_num_vbuffers - num_vbuffers : 0;
317   cso_set_vertex_buffers_and_elements(cso, &velements,
318                                       num_vbuffers,
319                                       unbind_trailing_vbuffers,
320                                       true,
321                                       uses_user_vertex_buffers,
322                                       vbuffer);
323   st->last_num_vbuffers = num_vbuffers;
324}
325
326struct pipe_vertex_state *
327st_create_gallium_vertex_state(struct gl_context *ctx,
328                               const struct gl_vertex_array_object *vao,
329                               struct gl_buffer_object *indexbuf,
330                               uint32_t enabled_attribs)
331{
332   struct st_context *st = st_context(ctx);
333   const GLbitfield inputs_read = enabled_attribs;
334   const GLbitfield dual_slot_inputs = 0; /* always zero */
335   struct pipe_vertex_buffer vbuffer[PIPE_MAX_ATTRIBS];
336   unsigned num_vbuffers = 0;
337   struct cso_velems_state velements;
338   bool uses_user_vertex_buffers;
339
340   setup_arrays(st, vao, dual_slot_inputs, inputs_read, 0, inputs_read, 0,
341                &velements, vbuffer, &num_vbuffers, &uses_user_vertex_buffers);
342
343   if (num_vbuffers != 1 || uses_user_vertex_buffers) {
344      assert(!"this should never happen with display lists");
345      return NULL;
346   }
347
348   velements.count = util_bitcount(inputs_read);
349
350   struct pipe_screen *screen = st->screen;
351   struct pipe_vertex_state *state =
352      screen->create_vertex_state(screen, &vbuffer[0], velements.velems,
353                                  velements.count,
354                                  indexbuf ?
355                                    st_buffer_object(indexbuf)->buffer : NULL,
356                                  enabled_attribs);
357
358   for (unsigned i = 0; i < num_vbuffers; i++)
359      pipe_vertex_buffer_unreference(&vbuffer[i]);
360   return state;
361}
362