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