• 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_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  */
56 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)57 init_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  */
73 static 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)74 setup_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 
169 void
st_setup_arrays(struct st_context * st,const struct st_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)170 st_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  */
192 static void ALWAYS_INLINE
st_setup_current(struct st_context * st,const struct st_vertex_program * vp,const struct st_common_variant * vp_variant,struct cso_velems_state * velements,struct pipe_vertex_buffer * vbuffer,unsigned * num_vbuffers)193 st_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 
253 void
st_setup_current_user(struct st_context * st,const struct st_vertex_program * vp,const struct st_common_variant * vp_variant,struct cso_velems_state * velements,struct pipe_vertex_buffer * vbuffer,unsigned * num_vbuffers)254 st_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 
284 void
st_update_array(struct st_context * st)285 st_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 
326 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)327 st_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