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 */ 56static void ALWAYS_INLINE 57init_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 */ 73static void ALWAYS_INLINE 74setup_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 169void 170st_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 */ 192static void ALWAYS_INLINE 193st_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 253void 254st_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 284void 285st_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 326struct pipe_vertex_state * 327st_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