Added few more stubs so that control reaches to DestroyDevice().
[mesa.git] / src / mesa / state_tracker / st_atom_array.c
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 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
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
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
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
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
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
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 }