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_draw.h" 42#include "st_program.h" 43 44#include "cso_cache/cso_context.h" 45#include "util/u_math.h" 46#include "util/u_upload_mgr.h" 47#include "main/bufferobj.h" 48#include "main/glformats.h" 49#include "main/varray.h" 50#include "main/arrayobj.h" 51 52enum st_update_flag { 53 UPDATE_ALL, 54 UPDATE_BUFFERS_ONLY, 55}; 56 57/* Always inline the non-64bit element code, so that the compiler can see 58 * that velements is on the stack. 59 */ 60static void ALWAYS_INLINE 61init_velement(struct pipe_vertex_element *velements, 62 const struct gl_vertex_format *vformat, 63 int src_offset, unsigned instance_divisor, 64 int vbo_index, bool dual_slot, int idx) 65{ 66 velements[idx].src_offset = src_offset; 67 velements[idx].src_format = vformat->_PipeFormat; 68 velements[idx].instance_divisor = instance_divisor; 69 velements[idx].vertex_buffer_index = vbo_index; 70 velements[idx].dual_slot = dual_slot; 71 assert(velements[idx].src_format); 72} 73 74/* ALWAYS_INLINE helps the compiler realize that most of the parameters are 75 * on the stack. 76 */ 77template<util_popcnt POPCNT, st_update_flag UPDATE> void ALWAYS_INLINE 78setup_arrays(struct st_context *st, 79 const struct gl_vertex_array_object *vao, 80 const GLbitfield dual_slot_inputs, 81 const GLbitfield inputs_read, 82 const GLbitfield nonzero_divisor_attribs, 83 const GLbitfield enabled_attribs, 84 const GLbitfield enabled_user_attribs, 85 struct cso_velems_state *velements, 86 struct pipe_vertex_buffer *vbuffer, unsigned *num_vbuffers, 87 bool *has_user_vertex_buffers) 88{ 89 struct gl_context *ctx = st->ctx; 90 91 /* Process attribute array data. */ 92 GLbitfield mask = inputs_read & enabled_attribs; 93 GLbitfield userbuf_attribs = inputs_read & enabled_user_attribs; 94 95 *has_user_vertex_buffers = userbuf_attribs != 0; 96 st->draw_needs_minmax_index = 97 (userbuf_attribs & ~nonzero_divisor_attribs) != 0; 98 99 if (vao->IsDynamic) { 100 while (mask) { 101 const gl_vert_attrib attr = (gl_vert_attrib)u_bit_scan(&mask); 102 const struct gl_array_attributes *const attrib = 103 _mesa_draw_array_attrib(vao, attr); 104 const struct gl_vertex_buffer_binding *const binding = 105 &vao->BufferBinding[attrib->BufferBindingIndex]; 106 const unsigned bufidx = (*num_vbuffers)++; 107 108 /* Set the vertex buffer. */ 109 if (binding->BufferObj) { 110 vbuffer[bufidx].buffer.resource = 111 _mesa_get_bufferobj_reference(ctx, binding->BufferObj); 112 vbuffer[bufidx].is_user_buffer = false; 113 vbuffer[bufidx].buffer_offset = binding->Offset + 114 attrib->RelativeOffset; 115 } else { 116 vbuffer[bufidx].buffer.user = attrib->Ptr; 117 vbuffer[bufidx].is_user_buffer = true; 118 vbuffer[bufidx].buffer_offset = 0; 119 } 120 vbuffer[bufidx].stride = binding->Stride; /* in bytes */ 121 122 if (UPDATE == UPDATE_BUFFERS_ONLY) 123 continue; 124 125 /* Set the vertex element. */ 126 init_velement(velements->velems, &attrib->Format, 0, 127 binding->InstanceDivisor, bufidx, 128 dual_slot_inputs & BITFIELD_BIT(attr), 129 util_bitcount_fast<POPCNT>(inputs_read & BITFIELD_MASK(attr))); 130 } 131 return; 132 } 133 134 while (mask) { 135 /* The attribute index to start pulling a binding */ 136 const gl_vert_attrib i = (gl_vert_attrib)(ffs(mask) - 1); 137 const struct gl_vertex_buffer_binding *const binding 138 = _mesa_draw_buffer_binding(vao, i); 139 const unsigned bufidx = (*num_vbuffers)++; 140 141 if (binding->BufferObj) { 142 /* Set the binding */ 143 vbuffer[bufidx].buffer.resource = 144 _mesa_get_bufferobj_reference(ctx, binding->BufferObj); 145 vbuffer[bufidx].is_user_buffer = false; 146 vbuffer[bufidx].buffer_offset = _mesa_draw_binding_offset(binding); 147 } else { 148 /* Set the binding */ 149 const void *ptr = (const void *)_mesa_draw_binding_offset(binding); 150 vbuffer[bufidx].buffer.user = ptr; 151 vbuffer[bufidx].is_user_buffer = true; 152 vbuffer[bufidx].buffer_offset = 0; 153 } 154 vbuffer[bufidx].stride = binding->Stride; /* in bytes */ 155 156 const GLbitfield boundmask = _mesa_draw_bound_attrib_bits(binding); 157 GLbitfield attrmask = mask & boundmask; 158 /* Mark the those attributes as processed */ 159 mask &= ~boundmask; 160 /* We can assume that we have array for the binding */ 161 assert(attrmask); 162 163 if (UPDATE == UPDATE_BUFFERS_ONLY) 164 continue; 165 166 /* Walk attributes belonging to the binding */ 167 do { 168 const gl_vert_attrib attr = (gl_vert_attrib)u_bit_scan(&attrmask); 169 const struct gl_array_attributes *const attrib 170 = _mesa_draw_array_attrib(vao, attr); 171 const GLuint off = _mesa_draw_attributes_relative_offset(attrib); 172 init_velement(velements->velems, &attrib->Format, off, 173 binding->InstanceDivisor, bufidx, 174 dual_slot_inputs & BITFIELD_BIT(attr), 175 util_bitcount_fast<POPCNT>(inputs_read & BITFIELD_MASK(attr))); 176 } while (attrmask); 177 } 178} 179 180/* Only used by the select/feedback mode. */ 181void 182st_setup_arrays(struct st_context *st, 183 const struct gl_vertex_program *vp, 184 const struct st_common_variant *vp_variant, 185 struct cso_velems_state *velements, 186 struct pipe_vertex_buffer *vbuffer, unsigned *num_vbuffers, 187 bool *has_user_vertex_buffers) 188{ 189 struct gl_context *ctx = st->ctx; 190 191 setup_arrays<POPCNT_NO, UPDATE_ALL> 192 (st, ctx->Array._DrawVAO, vp->Base.DualSlotInputs, 193 vp_variant->vert_attrib_mask, _mesa_draw_nonzero_divisor_bits(ctx), 194 _mesa_draw_array_bits(ctx), _mesa_draw_user_array_bits(ctx), 195 velements, vbuffer, num_vbuffers, has_user_vertex_buffers); 196} 197 198/* ALWAYS_INLINE helps the compiler realize that most of the parameters are 199 * on the stack. 200 * 201 * Return the index of the vertex buffer where current attribs have been 202 * uploaded. 203 */ 204template<util_popcnt POPCNT, st_update_flag UPDATE> void ALWAYS_INLINE 205st_setup_current(struct st_context *st, 206 const struct gl_vertex_program *vp, 207 const struct st_common_variant *vp_variant, 208 struct cso_velems_state *velements, 209 struct pipe_vertex_buffer *vbuffer, unsigned *num_vbuffers) 210{ 211 struct gl_context *ctx = st->ctx; 212 const GLbitfield inputs_read = vp_variant->vert_attrib_mask; 213 const GLbitfield dual_slot_inputs = vp->Base.DualSlotInputs; 214 215 /* Process values that should have better been uniforms in the application */ 216 GLbitfield curmask = inputs_read & _mesa_draw_current_bits(ctx); 217 if (curmask) { 218 /* For each attribute, upload the maximum possible size. */ 219 GLubyte data[VERT_ATTRIB_MAX * sizeof(GLdouble) * 4]; 220 GLubyte *cursor = data; 221 const unsigned bufidx = (*num_vbuffers)++; 222 unsigned max_alignment = 1; 223 224 do { 225 const gl_vert_attrib attr = (gl_vert_attrib)u_bit_scan(&curmask); 226 const struct gl_array_attributes *const attrib 227 = _mesa_draw_current_attrib(ctx, attr); 228 const unsigned size = attrib->Format._ElementSize; 229 const unsigned alignment = util_next_power_of_two(size); 230 max_alignment = MAX2(max_alignment, alignment); 231 memcpy(cursor, attrib->Ptr, size); 232 if (alignment != size) 233 memset(cursor + size, 0, alignment - size); 234 235 if (UPDATE == UPDATE_ALL) { 236 init_velement(velements->velems, &attrib->Format, cursor - data, 237 0, bufidx, dual_slot_inputs & BITFIELD_BIT(attr), 238 util_bitcount_fast<POPCNT>(inputs_read & BITFIELD_MASK(attr))); 239 } 240 241 cursor += alignment; 242 } while (curmask); 243 244 vbuffer[bufidx].is_user_buffer = false; 245 vbuffer[bufidx].buffer.resource = NULL; 246 /* vbuffer[bufidx].buffer_offset is set below */ 247 vbuffer[bufidx].stride = 0; 248 249 /* Use const_uploader for zero-stride vertex attributes, because 250 * it may use a better memory placement than stream_uploader. 251 * The reason is that zero-stride attributes can be fetched many 252 * times (thousands of times), so a better placement is going to 253 * perform better. 254 */ 255 struct u_upload_mgr *uploader = st->can_bind_const_buffer_as_vertex ? 256 st->pipe->const_uploader : 257 st->pipe->stream_uploader; 258 u_upload_data(uploader, 259 0, cursor - data, max_alignment, data, 260 &vbuffer[bufidx].buffer_offset, 261 &vbuffer[bufidx].buffer.resource); 262 /* Always unmap. The uploader might use explicit flushes. */ 263 u_upload_unmap(uploader); 264 } 265} 266 267/* Only used by the select/feedback mode. */ 268void 269st_setup_current_user(struct st_context *st, 270 const struct gl_vertex_program *vp, 271 const struct st_common_variant *vp_variant, 272 struct cso_velems_state *velements, 273 struct pipe_vertex_buffer *vbuffer, unsigned *num_vbuffers) 274{ 275 struct gl_context *ctx = st->ctx; 276 const GLbitfield inputs_read = vp_variant->vert_attrib_mask; 277 const GLbitfield dual_slot_inputs = vp->Base.DualSlotInputs; 278 279 /* Process values that should have better been uniforms in the application */ 280 GLbitfield curmask = inputs_read & _mesa_draw_current_bits(ctx); 281 /* For each attribute, make an own user buffer binding. */ 282 while (curmask) { 283 const gl_vert_attrib attr = (gl_vert_attrib)u_bit_scan(&curmask); 284 const struct gl_array_attributes *const attrib 285 = _mesa_draw_current_attrib(ctx, attr); 286 const unsigned bufidx = (*num_vbuffers)++; 287 288 init_velement(velements->velems, &attrib->Format, 0, 0, 289 bufidx, dual_slot_inputs & BITFIELD_BIT(attr), 290 util_bitcount(inputs_read & BITFIELD_MASK(attr))); 291 292 vbuffer[bufidx].is_user_buffer = true; 293 vbuffer[bufidx].buffer.user = attrib->Ptr; 294 vbuffer[bufidx].buffer_offset = 0; 295 vbuffer[bufidx].stride = 0; 296 } 297} 298 299template<util_popcnt POPCNT, st_update_flag UPDATE> void ALWAYS_INLINE 300st_update_array_templ(struct st_context *st) 301{ 302 struct gl_context *ctx = st->ctx; 303 304 /* vertex program validation must be done before this */ 305 /* _NEW_PROGRAM, ST_NEW_VS_STATE */ 306 const struct gl_vertex_program *vp = (struct gl_vertex_program *)st->vp; 307 const struct st_common_variant *vp_variant = st->vp_variant; 308 309 struct pipe_vertex_buffer vbuffer[PIPE_MAX_ATTRIBS]; 310 unsigned num_vbuffers = 0; 311 struct cso_velems_state velements; 312 bool uses_user_vertex_buffers; 313 314 /* ST_NEW_VERTEX_ARRAYS */ 315 /* Setup arrays */ 316 setup_arrays<POPCNT, UPDATE> 317 (st, ctx->Array._DrawVAO, vp->Base.DualSlotInputs, 318 vp_variant->vert_attrib_mask, _mesa_draw_nonzero_divisor_bits(ctx), 319 _mesa_draw_array_bits(ctx), _mesa_draw_user_array_bits(ctx), 320 &velements, vbuffer, &num_vbuffers, &uses_user_vertex_buffers); 321 322 /* _NEW_CURRENT_ATTRIB */ 323 /* Setup zero-stride attribs. */ 324 st_setup_current<POPCNT, UPDATE>(st, vp, vp_variant, &velements, vbuffer, 325 &num_vbuffers); 326 327 unsigned unbind_trailing_vbuffers = 328 st->last_num_vbuffers > num_vbuffers ? 329 st->last_num_vbuffers - num_vbuffers : 0; 330 st->last_num_vbuffers = num_vbuffers; 331 332 struct cso_context *cso = st->cso_context; 333 334 if (UPDATE == UPDATE_ALL) { 335 velements.count = vp->num_inputs + vp_variant->key.passthrough_edgeflags; 336 337 /* Set vertex buffers and elements. */ 338 cso_set_vertex_buffers_and_elements(cso, &velements, 339 num_vbuffers, 340 unbind_trailing_vbuffers, 341 true, 342 uses_user_vertex_buffers, 343 vbuffer); 344 /* The driver should clear this after it has processed the update. */ 345 ctx->Array.NewVertexElements = false; 346 st->uses_user_vertex_buffers = uses_user_vertex_buffers; 347 } else { 348 /* Only vertex buffers. */ 349 cso_set_vertex_buffers(cso, 0, num_vbuffers, unbind_trailing_vbuffers, 350 true, vbuffer); 351 /* This can change only when we update vertex elements. */ 352 assert(st->uses_user_vertex_buffers == uses_user_vertex_buffers); 353 } 354} 355 356template<util_popcnt POPCNT> void ALWAYS_INLINE 357st_update_array_impl(struct st_context *st) 358{ 359 struct gl_context *ctx = st->ctx; 360 361 /* Changing from user to non-user buffers and vice versa can switch between 362 * cso and u_vbuf, which means that we need to update vertex elements even 363 * when they have not changed. 364 */ 365 if (ctx->Array.NewVertexElements || 366 st->uses_user_vertex_buffers != 367 !!(st->vp_variant->vert_attrib_mask & _mesa_draw_user_array_bits(ctx))) { 368 st_update_array_templ<POPCNT, UPDATE_ALL>(st); 369 } else { 370 st_update_array_templ<POPCNT, UPDATE_BUFFERS_ONLY>(st); 371 } 372} 373 374void 375st_update_array(struct st_context *st) 376{ 377 st_update_array_impl<POPCNT_NO>(st); 378} 379 380void 381st_update_array_with_popcnt(struct st_context *st) 382{ 383 st_update_array_impl<POPCNT_YES>(st); 384} 385 386struct pipe_vertex_state * 387st_create_gallium_vertex_state(struct gl_context *ctx, 388 const struct gl_vertex_array_object *vao, 389 struct gl_buffer_object *indexbuf, 390 uint32_t enabled_attribs) 391{ 392 struct st_context *st = st_context(ctx); 393 const GLbitfield inputs_read = enabled_attribs; 394 const GLbitfield dual_slot_inputs = 0; /* always zero */ 395 struct pipe_vertex_buffer vbuffer[PIPE_MAX_ATTRIBS]; 396 unsigned num_vbuffers = 0; 397 struct cso_velems_state velements; 398 bool uses_user_vertex_buffers; 399 400 setup_arrays<POPCNT_NO, UPDATE_ALL>(st, vao, dual_slot_inputs, inputs_read, 0, 401 inputs_read, 0, &velements, vbuffer, &num_vbuffers, 402 &uses_user_vertex_buffers); 403 404 if (num_vbuffers != 1 || uses_user_vertex_buffers) { 405 assert(!"this should never happen with display lists"); 406 return NULL; 407 } 408 409 velements.count = util_bitcount(inputs_read); 410 411 struct pipe_screen *screen = st->screen; 412 struct pipe_vertex_state *state = 413 screen->create_vertex_state(screen, &vbuffer[0], velements.velems, 414 velements.count, 415 indexbuf ? 416 indexbuf->buffer : NULL, 417 enabled_attribs); 418 419 for (unsigned i = 0; i < num_vbuffers; i++) 420 pipe_vertex_buffer_unreference(&vbuffer[i]); 421 return state; 422} 423