st/mesa: verify that vertex buffer offset isn't negative
[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 /* vertex_formats[gltype - GL_BYTE][integer*2 + normalized][size - 1] */
54 static const uint16_t vertex_formats[][4][4] = {
55 { /* GL_BYTE */
56 {
57 PIPE_FORMAT_R8_SSCALED,
58 PIPE_FORMAT_R8G8_SSCALED,
59 PIPE_FORMAT_R8G8B8_SSCALED,
60 PIPE_FORMAT_R8G8B8A8_SSCALED
61 },
62 {
63 PIPE_FORMAT_R8_SNORM,
64 PIPE_FORMAT_R8G8_SNORM,
65 PIPE_FORMAT_R8G8B8_SNORM,
66 PIPE_FORMAT_R8G8B8A8_SNORM
67 },
68 {
69 PIPE_FORMAT_R8_SINT,
70 PIPE_FORMAT_R8G8_SINT,
71 PIPE_FORMAT_R8G8B8_SINT,
72 PIPE_FORMAT_R8G8B8A8_SINT
73 },
74 },
75 { /* GL_UNSIGNED_BYTE */
76 {
77 PIPE_FORMAT_R8_USCALED,
78 PIPE_FORMAT_R8G8_USCALED,
79 PIPE_FORMAT_R8G8B8_USCALED,
80 PIPE_FORMAT_R8G8B8A8_USCALED
81 },
82 {
83 PIPE_FORMAT_R8_UNORM,
84 PIPE_FORMAT_R8G8_UNORM,
85 PIPE_FORMAT_R8G8B8_UNORM,
86 PIPE_FORMAT_R8G8B8A8_UNORM
87 },
88 {
89 PIPE_FORMAT_R8_UINT,
90 PIPE_FORMAT_R8G8_UINT,
91 PIPE_FORMAT_R8G8B8_UINT,
92 PIPE_FORMAT_R8G8B8A8_UINT
93 },
94 },
95 { /* GL_SHORT */
96 {
97 PIPE_FORMAT_R16_SSCALED,
98 PIPE_FORMAT_R16G16_SSCALED,
99 PIPE_FORMAT_R16G16B16_SSCALED,
100 PIPE_FORMAT_R16G16B16A16_SSCALED
101 },
102 {
103 PIPE_FORMAT_R16_SNORM,
104 PIPE_FORMAT_R16G16_SNORM,
105 PIPE_FORMAT_R16G16B16_SNORM,
106 PIPE_FORMAT_R16G16B16A16_SNORM
107 },
108 {
109 PIPE_FORMAT_R16_SINT,
110 PIPE_FORMAT_R16G16_SINT,
111 PIPE_FORMAT_R16G16B16_SINT,
112 PIPE_FORMAT_R16G16B16A16_SINT
113 },
114 },
115 { /* GL_UNSIGNED_SHORT */
116 {
117 PIPE_FORMAT_R16_USCALED,
118 PIPE_FORMAT_R16G16_USCALED,
119 PIPE_FORMAT_R16G16B16_USCALED,
120 PIPE_FORMAT_R16G16B16A16_USCALED
121 },
122 {
123 PIPE_FORMAT_R16_UNORM,
124 PIPE_FORMAT_R16G16_UNORM,
125 PIPE_FORMAT_R16G16B16_UNORM,
126 PIPE_FORMAT_R16G16B16A16_UNORM
127 },
128 {
129 PIPE_FORMAT_R16_UINT,
130 PIPE_FORMAT_R16G16_UINT,
131 PIPE_FORMAT_R16G16B16_UINT,
132 PIPE_FORMAT_R16G16B16A16_UINT
133 },
134 },
135 { /* GL_INT */
136 {
137 PIPE_FORMAT_R32_SSCALED,
138 PIPE_FORMAT_R32G32_SSCALED,
139 PIPE_FORMAT_R32G32B32_SSCALED,
140 PIPE_FORMAT_R32G32B32A32_SSCALED
141 },
142 {
143 PIPE_FORMAT_R32_SNORM,
144 PIPE_FORMAT_R32G32_SNORM,
145 PIPE_FORMAT_R32G32B32_SNORM,
146 PIPE_FORMAT_R32G32B32A32_SNORM
147 },
148 {
149 PIPE_FORMAT_R32_SINT,
150 PIPE_FORMAT_R32G32_SINT,
151 PIPE_FORMAT_R32G32B32_SINT,
152 PIPE_FORMAT_R32G32B32A32_SINT
153 },
154 },
155 { /* GL_UNSIGNED_INT */
156 {
157 PIPE_FORMAT_R32_USCALED,
158 PIPE_FORMAT_R32G32_USCALED,
159 PIPE_FORMAT_R32G32B32_USCALED,
160 PIPE_FORMAT_R32G32B32A32_USCALED
161 },
162 {
163 PIPE_FORMAT_R32_UNORM,
164 PIPE_FORMAT_R32G32_UNORM,
165 PIPE_FORMAT_R32G32B32_UNORM,
166 PIPE_FORMAT_R32G32B32A32_UNORM
167 },
168 {
169 PIPE_FORMAT_R32_UINT,
170 PIPE_FORMAT_R32G32_UINT,
171 PIPE_FORMAT_R32G32B32_UINT,
172 PIPE_FORMAT_R32G32B32A32_UINT
173 },
174 },
175 { /* GL_FLOAT */
176 {
177 PIPE_FORMAT_R32_FLOAT,
178 PIPE_FORMAT_R32G32_FLOAT,
179 PIPE_FORMAT_R32G32B32_FLOAT,
180 PIPE_FORMAT_R32G32B32A32_FLOAT
181 },
182 {
183 PIPE_FORMAT_R32_FLOAT,
184 PIPE_FORMAT_R32G32_FLOAT,
185 PIPE_FORMAT_R32G32B32_FLOAT,
186 PIPE_FORMAT_R32G32B32A32_FLOAT
187 },
188 },
189 {{0}}, /* GL_2_BYTES */
190 {{0}}, /* GL_3_BYTES */
191 {{0}}, /* GL_4_BYTES */
192 { /* GL_DOUBLE */
193 {
194 PIPE_FORMAT_R64_FLOAT,
195 PIPE_FORMAT_R64G64_FLOAT,
196 PIPE_FORMAT_R64G64B64_FLOAT,
197 PIPE_FORMAT_R64G64B64A64_FLOAT
198 },
199 {
200 PIPE_FORMAT_R64_FLOAT,
201 PIPE_FORMAT_R64G64_FLOAT,
202 PIPE_FORMAT_R64G64B64_FLOAT,
203 PIPE_FORMAT_R64G64B64A64_FLOAT
204 },
205 },
206 { /* GL_HALF_FLOAT */
207 {
208 PIPE_FORMAT_R16_FLOAT,
209 PIPE_FORMAT_R16G16_FLOAT,
210 PIPE_FORMAT_R16G16B16_FLOAT,
211 PIPE_FORMAT_R16G16B16A16_FLOAT
212 },
213 {
214 PIPE_FORMAT_R16_FLOAT,
215 PIPE_FORMAT_R16G16_FLOAT,
216 PIPE_FORMAT_R16G16B16_FLOAT,
217 PIPE_FORMAT_R16G16B16A16_FLOAT
218 },
219 },
220 { /* GL_FIXED */
221 {
222 PIPE_FORMAT_R32_FIXED,
223 PIPE_FORMAT_R32G32_FIXED,
224 PIPE_FORMAT_R32G32B32_FIXED,
225 PIPE_FORMAT_R32G32B32A32_FIXED
226 },
227 {
228 PIPE_FORMAT_R32_FIXED,
229 PIPE_FORMAT_R32G32_FIXED,
230 PIPE_FORMAT_R32G32B32_FIXED,
231 PIPE_FORMAT_R32G32B32A32_FIXED
232 },
233 },
234 };
235
236
237 /**
238 * Return a PIPE_FORMAT_x for the given GL datatype and size.
239 */
240 static enum pipe_format
241 st_pipe_vertex_format(const struct gl_vertex_format *vformat)
242 {
243 const GLubyte size = vformat->Size;
244 const GLenum16 format = vformat->Format;
245 const bool normalized = vformat->Normalized;
246 const bool integer = vformat->Integer;
247 GLenum16 type = vformat->Type;
248 unsigned index;
249
250 assert(size >= 1 && size <= 4);
251 assert(format == GL_RGBA || format == GL_BGRA);
252 assert(vformat->_ElementSize == _mesa_bytes_per_vertex_attrib(size, type));
253
254 switch (type) {
255 case GL_HALF_FLOAT_OES:
256 type = GL_HALF_FLOAT;
257 break;
258
259 case GL_INT_2_10_10_10_REV:
260 assert(size == 4 && !integer);
261
262 if (format == GL_BGRA) {
263 if (normalized)
264 return PIPE_FORMAT_B10G10R10A2_SNORM;
265 else
266 return PIPE_FORMAT_B10G10R10A2_SSCALED;
267 } else {
268 if (normalized)
269 return PIPE_FORMAT_R10G10B10A2_SNORM;
270 else
271 return PIPE_FORMAT_R10G10B10A2_SSCALED;
272 }
273 break;
274
275 case GL_UNSIGNED_INT_2_10_10_10_REV:
276 assert(size == 4 && !integer);
277
278 if (format == GL_BGRA) {
279 if (normalized)
280 return PIPE_FORMAT_B10G10R10A2_UNORM;
281 else
282 return PIPE_FORMAT_B10G10R10A2_USCALED;
283 } else {
284 if (normalized)
285 return PIPE_FORMAT_R10G10B10A2_UNORM;
286 else
287 return PIPE_FORMAT_R10G10B10A2_USCALED;
288 }
289 break;
290
291 case GL_UNSIGNED_INT_10F_11F_11F_REV:
292 assert(size == 3 && !integer && format == GL_RGBA);
293 return PIPE_FORMAT_R11G11B10_FLOAT;
294
295 case GL_UNSIGNED_BYTE:
296 if (format == GL_BGRA) {
297 /* this is an odd-ball case */
298 assert(normalized);
299 return PIPE_FORMAT_B8G8R8A8_UNORM;
300 }
301 break;
302 }
303
304 index = integer*2 + normalized;
305 assert(index <= 2);
306 assert(type >= GL_BYTE && type <= GL_FIXED);
307 return vertex_formats[type - GL_BYTE][index][size-1];
308 }
309
310 static void init_velement(struct pipe_vertex_element *velement,
311 int src_offset, int format,
312 int instance_divisor, int vbo_index)
313 {
314 velement->src_offset = src_offset;
315 velement->src_format = format;
316 velement->instance_divisor = instance_divisor;
317 velement->vertex_buffer_index = vbo_index;
318 assert(velement->src_format);
319 }
320
321 static void init_velement_lowered(const struct st_vertex_program *vp,
322 struct pipe_vertex_element *velements,
323 const struct gl_vertex_format *vformat,
324 int src_offset, int instance_divisor,
325 int vbo_index, int idx)
326 {
327 const GLubyte nr_components = vformat->Size;
328
329 if (vformat->Doubles) {
330 int lower_format;
331
332 if (nr_components < 2)
333 lower_format = PIPE_FORMAT_R32G32_UINT;
334 else
335 lower_format = PIPE_FORMAT_R32G32B32A32_UINT;
336
337 init_velement(&velements[idx], src_offset,
338 lower_format, instance_divisor, vbo_index);
339 idx++;
340
341 if (idx < vp->num_inputs &&
342 vp->index_to_input[idx] == ST_DOUBLE_ATTRIB_PLACEHOLDER) {
343 if (nr_components >= 3) {
344 if (nr_components == 3)
345 lower_format = PIPE_FORMAT_R32G32_UINT;
346 else
347 lower_format = PIPE_FORMAT_R32G32B32A32_UINT;
348
349 init_velement(&velements[idx], src_offset + 4 * sizeof(float),
350 lower_format, instance_divisor, vbo_index);
351 } else {
352 /* The values here are undefined. Fill in some conservative
353 * dummy values.
354 */
355 init_velement(&velements[idx], src_offset, PIPE_FORMAT_R32G32_UINT,
356 instance_divisor, vbo_index);
357 }
358 }
359 } else {
360 const unsigned format = st_pipe_vertex_format(vformat);
361
362 init_velement(&velements[idx], src_offset,
363 format, instance_divisor, vbo_index);
364 }
365 }
366
367 static void
368 set_vertex_attribs(struct st_context *st,
369 struct pipe_vertex_buffer *vbuffers,
370 unsigned num_vbuffers,
371 struct pipe_vertex_element *velements,
372 unsigned num_velements)
373 {
374 struct cso_context *cso = st->cso_context;
375
376 cso_set_vertex_buffers(cso, 0, num_vbuffers, vbuffers);
377 if (st->last_num_vbuffers > num_vbuffers) {
378 /* Unbind remaining buffers, if any. */
379 cso_set_vertex_buffers(cso, num_vbuffers,
380 st->last_num_vbuffers - num_vbuffers, NULL);
381 }
382 st->last_num_vbuffers = num_vbuffers;
383 cso_set_vertex_elements(cso, num_velements, velements);
384 }
385
386 void
387 st_setup_arrays(struct st_context *st,
388 const struct st_vertex_program *vp,
389 const struct st_vp_variant *vp_variant,
390 struct pipe_vertex_element *velements,
391 struct pipe_vertex_buffer *vbuffer, unsigned *num_vbuffers)
392 {
393 struct gl_context *ctx = st->ctx;
394 const struct gl_vertex_array_object *vao = ctx->Array._DrawVAO;
395 const GLbitfield inputs_read = vp_variant->vert_attrib_mask;
396 const ubyte *input_to_index = vp->input_to_index;
397
398 /* Process attribute array data. */
399 GLbitfield mask = inputs_read & _mesa_draw_array_bits(ctx);
400 while (mask) {
401 /* The attribute index to start pulling a binding */
402 const gl_vert_attrib i = ffs(mask) - 1;
403 const struct gl_vertex_buffer_binding *const binding
404 = _mesa_draw_buffer_binding(vao, i);
405 const unsigned bufidx = (*num_vbuffers)++;
406
407 if (_mesa_is_bufferobj(binding->BufferObj)) {
408 /* Set the binding */
409 struct st_buffer_object *stobj = st_buffer_object(binding->BufferObj);
410 vbuffer[bufidx].buffer.resource = stobj ? stobj->buffer : NULL;
411 vbuffer[bufidx].is_user_buffer = false;
412 vbuffer[bufidx].buffer_offset = _mesa_draw_binding_offset(binding);
413 if (st->has_signed_vertex_buffer_offset) {
414 /* 'buffer_offset' will be interpreted as an signed int, so make sure
415 * the user supplied offset is not negative (application bug).
416 */
417 if ((int) vbuffer[bufidx].buffer_offset < 0) {
418 assert ((int) vbuffer[bufidx].buffer_offset >= 0);
419 /* Fallback if assert are disabled: we can't disable this attribute
420 * since other parts expects it (e.g: velements, vp_variant), so
421 * use a non-buggy offset value instead */
422 vbuffer[bufidx].buffer_offset = 0;
423 }
424 }
425 } else {
426 /* Set the binding */
427 const void *ptr = (const void *)_mesa_draw_binding_offset(binding);
428 vbuffer[bufidx].buffer.user = ptr;
429 vbuffer[bufidx].is_user_buffer = true;
430 vbuffer[bufidx].buffer_offset = 0;
431
432 if (!binding->InstanceDivisor)
433 st->draw_needs_minmax_index = true;
434 }
435 vbuffer[bufidx].stride = binding->Stride; /* in bytes */
436
437 const GLbitfield boundmask = _mesa_draw_bound_attrib_bits(binding);
438 GLbitfield attrmask = mask & boundmask;
439 /* Mark the those attributes as processed */
440 mask &= ~boundmask;
441 /* We can assume that we have array for the binding */
442 assert(attrmask);
443 /* Walk attributes belonging to the binding */
444 while (attrmask) {
445 const gl_vert_attrib attr = u_bit_scan(&attrmask);
446 const struct gl_array_attributes *const attrib
447 = _mesa_draw_array_attrib(vao, attr);
448 const GLuint off = _mesa_draw_attributes_relative_offset(attrib);
449 init_velement_lowered(vp, velements, &attrib->Format, off,
450 binding->InstanceDivisor, bufidx,
451 input_to_index[attr]);
452 }
453 }
454 }
455
456 void
457 st_setup_current(struct st_context *st,
458 const struct st_vertex_program *vp,
459 const struct st_vp_variant *vp_variant,
460 struct pipe_vertex_element *velements,
461 struct pipe_vertex_buffer *vbuffer, unsigned *num_vbuffers)
462 {
463 struct gl_context *ctx = st->ctx;
464 const GLbitfield inputs_read = vp_variant->vert_attrib_mask;
465
466 /* Process values that should have better been uniforms in the application */
467 GLbitfield curmask = inputs_read & _mesa_draw_current_bits(ctx);
468 if (curmask) {
469 /* vertex program validation must be done before this */
470 const struct st_vertex_program *vp = st->vp;
471 const ubyte *input_to_index = vp->input_to_index;
472 /* For each attribute, upload the maximum possible size. */
473 GLubyte data[VERT_ATTRIB_MAX * sizeof(GLdouble) * 4];
474 GLubyte *cursor = data;
475 const unsigned bufidx = (*num_vbuffers)++;
476 unsigned max_alignment = 1;
477
478 while (curmask) {
479 const gl_vert_attrib attr = u_bit_scan(&curmask);
480 const struct gl_array_attributes *const attrib
481 = _mesa_draw_current_attrib(ctx, attr);
482 const unsigned size = attrib->Format._ElementSize;
483 const unsigned alignment = util_next_power_of_two(size);
484 max_alignment = MAX2(max_alignment, alignment);
485 memcpy(cursor, attrib->Ptr, size);
486 if (alignment != size)
487 memset(cursor + size, 0, alignment - size);
488
489 init_velement_lowered(vp, velements, &attrib->Format, cursor - data, 0,
490 bufidx, input_to_index[attr]);
491
492 cursor += alignment;
493 }
494
495 vbuffer[bufidx].is_user_buffer = false;
496 vbuffer[bufidx].buffer.resource = NULL;
497 /* vbuffer[bufidx].buffer_offset is set below */
498 vbuffer[bufidx].stride = 0;
499
500 /* Use const_uploader for zero-stride vertex attributes, because
501 * it may use a better memory placement than stream_uploader.
502 * The reason is that zero-stride attributes can be fetched many
503 * times (thousands of times), so a better placement is going to
504 * perform better.
505 */
506 struct u_upload_mgr *uploader = st->can_bind_const_buffer_as_vertex ?
507 st->pipe->const_uploader :
508 st->pipe->stream_uploader;
509 u_upload_data(uploader,
510 0, cursor - data, max_alignment, data,
511 &vbuffer[bufidx].buffer_offset,
512 &vbuffer[bufidx].buffer.resource);
513 /* Always unmap. The uploader might use explicit flushes. */
514 u_upload_unmap(uploader);
515 }
516 }
517
518 void
519 st_setup_current_user(struct st_context *st,
520 const struct st_vertex_program *vp,
521 const struct st_vp_variant *vp_variant,
522 struct pipe_vertex_element *velements,
523 struct pipe_vertex_buffer *vbuffer, unsigned *num_vbuffers)
524 {
525 struct gl_context *ctx = st->ctx;
526 const GLbitfield inputs_read = vp_variant->vert_attrib_mask;
527 const ubyte *input_to_index = vp->input_to_index;
528
529 /* Process values that should have better been uniforms in the application */
530 GLbitfield curmask = inputs_read & _mesa_draw_current_bits(ctx);
531 /* For each attribute, make an own user buffer binding. */
532 while (curmask) {
533 const gl_vert_attrib attr = u_bit_scan(&curmask);
534 const struct gl_array_attributes *const attrib
535 = _mesa_draw_current_attrib(ctx, attr);
536 const unsigned bufidx = (*num_vbuffers)++;
537
538 init_velement_lowered(vp, velements, &attrib->Format, 0, 0,
539 bufidx, input_to_index[attr]);
540
541 vbuffer[bufidx].is_user_buffer = true;
542 vbuffer[bufidx].buffer.user = attrib->Ptr;
543 vbuffer[bufidx].buffer_offset = 0;
544 vbuffer[bufidx].stride = 0;
545 }
546 }
547
548 void
549 st_update_array(struct st_context *st)
550 {
551 /* vertex program validation must be done before this */
552 /* _NEW_PROGRAM, ST_NEW_VS_STATE */
553 const struct st_vertex_program *vp = st->vp;
554 const struct st_vp_variant *vp_variant = st->vp_variant;
555
556 struct pipe_vertex_buffer vbuffer[PIPE_MAX_ATTRIBS];
557 unsigned num_vbuffers = 0, first_upload_vbuffer;
558 struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS];
559 unsigned num_velements;
560
561 st->draw_needs_minmax_index = false;
562
563 /* ST_NEW_VERTEX_ARRAYS alias ctx->DriverFlags.NewArray */
564 /* Setup arrays */
565 st_setup_arrays(st, vp, vp_variant, velements, vbuffer, &num_vbuffers);
566
567 /* _NEW_CURRENT_ATTRIB */
568 /* Setup current uploads */
569 first_upload_vbuffer = num_vbuffers;
570 st_setup_current(st, vp, vp_variant, velements, vbuffer, &num_vbuffers);
571
572 /* Set the array into cso */
573 num_velements = vp_variant->num_inputs;
574 set_vertex_attribs(st, vbuffer, num_vbuffers, velements, num_velements);
575
576 /* Unreference uploaded buffer resources. */
577 for (unsigned i = first_upload_vbuffer; i < num_vbuffers; ++i) {
578 pipe_resource_reference(&vbuffer[i].buffer.resource, NULL);
579 }
580 }