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