From d1698d4311a63e1054e458ae1a27d7684595faee Mon Sep 17 00:00:00 2001 From: =?utf8?q?Mathias=20Fr=C3=B6hlich?= Date: Sun, 1 Apr 2018 20:18:36 +0200 Subject: [PATCH] mesa: Compute effective buffer bindings in the vao. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Compute VAO buffer binding information past the position/generic0 mapping. Scan for duplicate buffer bindings and collapse them into derived effective buffer binding index and effective attribute mask variables. Provide a set of helper functions to access the distilled information in the VAO. All of them prefixed with _mesa_draw_... to indicate that they are meant to query draw information. v2: Also group user space arrays containing interleaved arrays. Add _Eff*Offset to be copied on attribute and binding copy. Update comments. Reviewed-by: Brian Paul Signed-off-by: Mathias Fröhlich --- src/mesa/main/arrayobj.c | 390 ++++++++++++++++++++++++++++++++++++- src/mesa/main/arrayobj.h | 186 ++++++++++++++++++ src/mesa/main/attrib.c | 1 + src/mesa/main/mtypes.h | 64 ++++++ src/mesa/main/varray.c | 9 + src/mesa/vbo/vbo.h | 8 + src/mesa/vbo/vbo_context.c | 17 ++ src/mesa/vbo/vbo_private.h | 14 +- 8 files changed, 682 insertions(+), 7 deletions(-) diff --git a/src/mesa/main/arrayobj.c b/src/mesa/main/arrayobj.c index 899d4dec01c..05af50ef400 100644 --- a/src/mesa/main/arrayobj.c +++ b/src/mesa/main/arrayobj.c @@ -451,8 +451,116 @@ _mesa_initialize_vao(struct gl_context *ctx, /** - * Updates the derived gl_vertex_arrays when a gl_array_attributes - * or a gl_vertex_buffer_binding has changed. + * Compute the offset range for the provided binding. + * + * This is a helper function for the below. + */ +static void +compute_vbo_offset_range(const struct gl_vertex_array_object *vao, + const struct gl_vertex_buffer_binding *binding, + GLsizeiptr* min, GLsizeiptr* max) +{ + /* The function is meant to work on VBO bindings */ + assert(_mesa_is_bufferobj(binding->BufferObj)); + + /* Start with an inverted range of relative offsets. */ + GLuint min_offset = ~(GLuint)0; + GLuint max_offset = 0; + + /* We work on the unmapped originaly VAO array entries. */ + GLbitfield mask = vao->_Enabled & binding->_BoundArrays; + /* The binding should be active somehow, not to return inverted ranges */ + assert(mask); + while (mask) { + const int i = u_bit_scan(&mask); + const GLuint off = vao->VertexAttrib[i].RelativeOffset; + min_offset = MIN2(off, min_offset); + max_offset = MAX2(off, max_offset); + } + + *min = binding->Offset + (GLsizeiptr)min_offset; + *max = binding->Offset + (GLsizeiptr)max_offset; +} + + +/** + * Update the unique binding and pos/generic0 map tracking in the vao. + * + * The idea is to build up information in the vao so that a consuming + * backend can execute the following to set up buffer and vertex element + * information: + * + * const GLbitfield inputs_read = VERT_BIT_ALL; // backend vp inputs + * + * // Attribute data is in a VBO. + * GLbitfield vbomask = inputs_read & _mesa_draw_vbo_array_bits(ctx); + * while (vbomask) { + * // The attribute index to start pulling a binding + * const gl_vert_attrib i = ffs(vbomask) - 1; + * const struct gl_vertex_buffer_binding *const binding + * = _mesa_draw_buffer_binding(vao, i); + * + * + * + * const GLbitfield boundmask = _mesa_draw_bound_attrib_bits(binding); + * GLbitfield attrmask = vbomask & boundmask; + * assert(attrmask); + * // Walk attributes belonging to the binding + * while (attrmask) { + * const gl_vert_attrib attr = u_bit_scan(&attrmask); + * const struct gl_array_attributes *const attrib + * = _mesa_draw_array_attrib(vao, attr); + * + * + * } + * vbomask &= ~boundmask; + * } + * + * // Process user space buffers + * GLbitfield usermask = inputs_read & _mesa_draw_user_array_bits(ctx); + * while (usermask) { + * // The attribute index to start pulling a binding + * const gl_vert_attrib i = ffs(usermask) - 1; + * const struct gl_vertex_buffer_binding *const binding + * = _mesa_draw_buffer_binding(vao, i); + * + * + * + * const GLbitfield boundmask = _mesa_draw_bound_attrib_bits(binding); + * GLbitfield attrmask = usermask & boundmask; + * assert(attrmask); + * // Walk interleaved attributes with a common stride and instance divisor + * while (attrmask) { + * const gl_vert_attrib attr = u_bit_scan(&attrmask); + * const struct gl_array_attributes *const attrib + * = _mesa_draw_array_attrib(vao, attr); + * + * + * } + * usermask &= ~boundmask; + * } + * + * // Process values that should have better been uniforms in the application + * GLbitfield curmask = inputs_read & _mesa_draw_current_bits(ctx); + * while (curmask) { + * const gl_vert_attrib attr = u_bit_scan(&curmask); + * const struct gl_array_attributes *const attrib + * = _mesa_draw_current_attrib(ctx, attr); + * + * + * } + * + * + * Note that the scan below must not incoporate any context state. + * The rationale is that once a VAO is finalized it should not + * be touched anymore. That means, do not incorporate the + * gl_context::Array._DrawVAOEnabledAttribs bitmask into this scan. + * A backend driver may further reduce the handled vertex processing + * inputs based on their vertex shader inputs. But scanning for + * collapsable binding points to reduce relocs is done based on the + * enabled arrays. + * Also VAOs may be shared between contexts due to their use in dlists + * thus no context state should bleed into the VAO. */ void _mesa_update_vao_derived_arrays(struct gl_context *ctx, @@ -461,11 +569,281 @@ _mesa_update_vao_derived_arrays(struct gl_context *ctx, /* Make sure we do not run into problems with shared objects */ assert(!vao->SharedAndImmutable || vao->NewArrays == 0); - /* - * Stay tuned, the next series scans for duplicate bindings in this - * function. So that drivers can easily know the minimum unique set - * of bindings. + /* Limit used for common binding scanning below. */ + const GLsizeiptr MaxRelativeOffset = + ctx->Const.MaxVertexAttribRelativeOffset; + + /* The gl_vertex_array_object::_AttributeMapMode denotes the way + * VERT_ATTRIB_{POS,GENERIC0} mapping is done. + * + * This mapping is used to map between the OpenGL api visible + * VERT_ATTRIB_* arrays to mesa driver arrayinputs or shader inputs. + * The mapping only depends on the enabled bits of the + * VERT_ATTRIB_{POS,GENERIC0} arrays and is tracked in the VAO. + * + * This map needs to be applied when finally translating to the bitmasks + * as consumed by the driver backends. The duplicate scanning is here + * can as well be done in the OpenGL API numbering without this map. */ + const gl_attribute_map_mode mode = vao->_AttributeMapMode; + /* Enabled array bits. */ + const GLbitfield enabled = vao->_Enabled; + /* VBO array bits. */ + const GLbitfield vbos = vao->VertexAttribBufferMask; + + /* Compute and store effectively enabled and mapped vbo arrays */ + vao->_EffEnabledVBO = _mesa_vao_enable_to_vp_inputs(mode, enabled & vbos); + /* Walk those enabled arrays that have a real vbo attached */ + GLbitfield mask = enabled; + while (mask) { + /* Do not use u_bit_scan as we can walk multiple attrib arrays at once */ + const int i = ffs(mask) - 1; + /* The binding from the first to be processed attribute. */ + const GLuint bindex = vao->VertexAttrib[i].BufferBindingIndex; + struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[bindex]; + + /* The scan goes different for user space arrays than vbos */ + if (_mesa_is_bufferobj(binding->BufferObj)) { + /* The bound arrays. */ + const GLbitfield bound = enabled & binding->_BoundArrays; + + /* Start this current effective binding with the actual bound arrays */ + GLbitfield eff_bound_arrays = bound; + + /* + * If there is nothing left to scan just update the effective binding + * information. If the VAO is already only using a single binding point + * we end up here. So the overhead of this scan for an application + * carefully preparing the VAO for draw is low. + */ + + GLbitfield scanmask = mask & vbos & ~bound; + /* Is there something left to scan? */ + if (scanmask == 0) { + /* Just update the back reference from the attrib to the binding and + * the effective offset. + */ + GLbitfield attrmask = eff_bound_arrays; + while (attrmask) { + const int j = u_bit_scan(&attrmask); + struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j]; + + /* Update the index into the common binding point and offset */ + attrib2->_EffBufferBindingIndex = bindex; + attrib2->_EffRelativeOffset = attrib2->RelativeOffset; + assert(attrib2->_EffRelativeOffset <= MaxRelativeOffset); + + /* Only enabled arrays shall appear in the unique bindings */ + assert(attrib2->Enabled); + } + /* Finally this is the set of effectively bound arrays with the + * original binding offset. + */ + binding->_EffOffset = binding->Offset; + /* The bound arrays past the VERT_ATTRIB_{POS,GENERIC0} mapping. */ + binding->_EffBoundArrays = + _mesa_vao_enable_to_vp_inputs(mode, eff_bound_arrays); + + } else { + /* In the VBO case, scan for attribute/binding + * combinations with relative bindings in the range of + * [0, ctx->Const.MaxVertexAttribRelativeOffset]. + * Note that this does also go beyond just interleaved arrays + * as long as they use the same VBO, binding parameters and the + * offsets stay within bounds that the backend still can handle. + */ + + GLsizeiptr min_offset, max_offset; + compute_vbo_offset_range(vao, binding, &min_offset, &max_offset); + assert(max_offset <= min_offset + MaxRelativeOffset); + + /* Now scan. */ + while (scanmask) { + /* Do not use u_bit_scan as we can walk multiple + * attrib arrays at once + */ + const int j = ffs(scanmask) - 1; + const struct gl_array_attributes *attrib2 = + &vao->VertexAttrib[j]; + const struct gl_vertex_buffer_binding *binding2 = + &vao->BufferBinding[attrib2->BufferBindingIndex]; + + /* Remove those attrib bits from the mask that are bound to the + * same effective binding point. + */ + const GLbitfield bound2 = enabled & binding2->_BoundArrays; + scanmask &= ~bound2; + + /* Check if we have an identical binding */ + if (binding->Stride != binding2->Stride) + continue; + if (binding->InstanceDivisor != binding2->InstanceDivisor) + continue; + if (binding->BufferObj != binding2->BufferObj) + continue; + /* Check if we can fold both bindings into a common binding */ + GLsizeiptr min_offset2, max_offset2; + compute_vbo_offset_range(vao, binding2, + &min_offset2, &max_offset2); + /* If the relative offset is within the limits ... */ + if (min_offset + MaxRelativeOffset < max_offset2) + continue; + if (min_offset2 + MaxRelativeOffset < max_offset) + continue; + /* ... add this array to the effective binding */ + eff_bound_arrays |= bound2; + min_offset = MIN2(min_offset, min_offset2); + max_offset = MAX2(max_offset, max_offset2); + assert(max_offset <= min_offset + MaxRelativeOffset); + } + + /* Update the back reference from the attrib to the binding */ + GLbitfield attrmask = eff_bound_arrays; + while (attrmask) { + const int j = u_bit_scan(&attrmask); + struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j]; + const struct gl_vertex_buffer_binding *binding2 = + &vao->BufferBinding[attrib2->BufferBindingIndex]; + + /* Update the index into the common binding point and offset */ + attrib2->_EffBufferBindingIndex = bindex; + attrib2->_EffRelativeOffset = + binding2->Offset + attrib2->RelativeOffset - min_offset; + assert(attrib2->_EffRelativeOffset <= MaxRelativeOffset); + + /* Only enabled arrays shall appear in the unique bindings */ + assert(attrib2->Enabled); + } + /* Finally this is the set of effectively bound arrays */ + binding->_EffOffset = min_offset; + /* The bound arrays past the VERT_ATTRIB_{POS,GENERIC0} mapping. */ + binding->_EffBoundArrays = + _mesa_vao_enable_to_vp_inputs(mode, eff_bound_arrays); + } + + /* Mark all the effective bound arrays as processed. */ + mask &= ~eff_bound_arrays; + + } else { + /* Scanning of common bindings for user space arrays. + */ + + const struct gl_array_attributes *attrib = &vao->VertexAttrib[i]; + const GLbitfield bound = VERT_BIT(i); + + /* Note that user space array pointers can only happen using a one + * to one binding point to array mapping. + * The OpenGL 4.x/ARB_vertex_attrib_binding api does not support + * user space arrays collected at multiple binding points. + * The only provider of user space interleaved arrays with a single + * binding point is the mesa internal vbo module. But that one + * provides a perfect interleaved set of arrays. + * + * If this would not be true we would potentially get attribute arrays + * with user space pointers that may not lie within the + * MaxRelativeOffset range but still attached to a single binding. + * Then we would need to store the effective attribute and binding + * grouping information in a seperate array beside + * gl_array_attributes/gl_vertex_buffer_binding. + */ + assert(_mesa_bitcount(binding->_BoundArrays & vao->_Enabled) == 1 + || (vao->_Enabled & ~binding->_BoundArrays) == 0); + + /* Start this current effective binding with the array */ + GLbitfield eff_bound_arrays = bound; + + const GLubyte *ptr = attrib->Ptr; + unsigned vertex_end = attrib->_ElementSize; + + /* Walk other user space arrays and see which are interleaved + * using the same binding parameters. + */ + GLbitfield scanmask = mask & ~vbos & ~bound; + while (scanmask) { + const int j = u_bit_scan(&scanmask); + const struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j]; + const struct gl_vertex_buffer_binding *binding2 = + &vao->BufferBinding[attrib2->BufferBindingIndex]; + + /* See the comment at the same assert above. */ + assert(_mesa_bitcount(binding2->_BoundArrays & vao->_Enabled) == 1 + || (vao->_Enabled & ~binding->_BoundArrays) == 0); + + /* Check if we have an identical binding */ + if (binding->Stride != binding2->Stride) + continue; + if (binding->InstanceDivisor != binding2->InstanceDivisor) + continue; + if (ptr <= attrib2->Ptr) { + if (ptr + binding->Stride < attrib2->Ptr + attrib2->_ElementSize) + continue; + unsigned end = attrib2->Ptr + attrib2->_ElementSize - ptr; + vertex_end = MAX2(vertex_end, end); + } else { + if (attrib2->Ptr + binding->Stride < ptr + vertex_end) + continue; + vertex_end += (GLsizei)(ptr - attrib2->Ptr); + ptr = attrib2->Ptr; + } + + /* User space buffer object */ + assert(!_mesa_is_bufferobj(binding2->BufferObj)); + + eff_bound_arrays |= VERT_BIT(j); + } + + /* Update the back reference from the attrib to the binding */ + GLbitfield attrmask = eff_bound_arrays; + while (attrmask) { + const int j = u_bit_scan(&attrmask); + struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j]; + + /* Update the index into the common binding point and the offset */ + attrib2->_EffBufferBindingIndex = bindex; + attrib2->_EffRelativeOffset = attrib2->Ptr - ptr; + assert(attrib2->_EffRelativeOffset <= binding->Stride); + + /* Only enabled arrays shall appear in the unique bindings */ + assert(attrib2->Enabled); + } + /* Finally this is the set of effectively bound arrays */ + binding->_EffOffset = (GLintptr)ptr; + /* The bound arrays past the VERT_ATTRIB_{POS,GENERIC0} mapping. */ + binding->_EffBoundArrays = + _mesa_vao_enable_to_vp_inputs(mode, eff_bound_arrays); + + /* Mark all the effective bound arrays as processed. */ + mask &= ~eff_bound_arrays; + } + } + +#ifndef NDEBUG + /* Make sure the above code works as expected. */ + for (gl_vert_attrib attr = 0; attr < VERT_ATTRIB_MAX; ++attr) { + /* Query the original api defined attrib/binding information ... */ + const unsigned char *const map =_mesa_vao_attribute_map[mode]; + const struct gl_array_attributes *attrib = &vao->VertexAttrib[map[attr]]; + if (attrib->Enabled) { + const struct gl_vertex_buffer_binding *binding = + &vao->BufferBinding[attrib->BufferBindingIndex]; + /* ... and compare that with the computed attrib/binding */ + const struct gl_vertex_buffer_binding *binding2 = + &vao->BufferBinding[attrib->_EffBufferBindingIndex]; + assert(binding->Stride == binding2->Stride); + assert(binding->InstanceDivisor == binding2->InstanceDivisor); + assert(binding->BufferObj == binding2->BufferObj); + if (_mesa_is_bufferobj(binding->BufferObj)) { + assert(attrib->_EffRelativeOffset <= MaxRelativeOffset); + assert(binding->Offset + attrib->RelativeOffset == + binding2->_EffOffset + attrib->_EffRelativeOffset); + } else { + assert(attrib->_EffRelativeOffset < binding->Stride); + assert((GLintptr)attrib->Ptr == + binding2->_EffOffset + attrib->_EffRelativeOffset); + } + } + } +#endif } diff --git a/src/mesa/main/arrayobj.h b/src/mesa/main/arrayobj.h index 8da5c9ffe01..8b11c79bdb9 100644 --- a/src/mesa/main/arrayobj.h +++ b/src/mesa/main/arrayobj.h @@ -30,6 +30,7 @@ #include "glheader.h" #include "mtypes.h" #include "glformats.h" +#include "vbo/vbo.h" struct gl_context; @@ -146,6 +147,191 @@ _mesa_get_vao_vp_inputs(const struct gl_vertex_array_object *vao) } +/** + * Helper functions for consuming backends to walk the + * ctx->Array._DrawVAO for driver side array setup. + * Note that mesa provides preprocessed minimal binding information + * in the VAO. See _mesa_update_vao_derived_arrays for documentation. + */ + +/** + * Return enabled vertex attribute bits for draw. + */ +static inline GLbitfield +_mesa_draw_array_bits(const struct gl_context *ctx) +{ + return ctx->Array._DrawVAOEnabledAttribs; +} + + +/** + * Return enabled buffer object vertex attribute bits for draw. + * + * Needs the a fully updated VAO ready for draw. + */ +static inline GLbitfield +_mesa_draw_vbo_array_bits(const struct gl_context *ctx) +{ + const struct gl_vertex_array_object *const vao = ctx->Array._DrawVAO; + assert(vao->NewArrays == 0); + return vao->_EffEnabledVBO & ctx->Array._DrawVAOEnabledAttribs; +} + + +/** + * Return enabled user space vertex attribute bits for draw. + * + * Needs the a fully updated VAO ready for draw. + */ +static inline GLbitfield +_mesa_draw_user_array_bits(const struct gl_context *ctx) +{ + const struct gl_vertex_array_object *const vao = ctx->Array._DrawVAO; + assert(vao->NewArrays == 0); + return ~vao->_EffEnabledVBO & ctx->Array._DrawVAOEnabledAttribs; +} + + +/** + * Return enabled current values attribute bits for draw. + */ +static inline GLbitfield +_mesa_draw_current_bits(const struct gl_context *ctx) +{ + return ~ctx->Array._DrawVAOEnabledAttribs & VERT_BIT_ALL; +} + + +/** + * Return vertex buffer binding provided the attribute struct. + * + * Needs the a fully updated VAO ready for draw. + */ +static inline const struct gl_vertex_buffer_binding* +_mesa_draw_buffer_binding_from_attrib(const struct gl_vertex_array_object *vao, + const struct gl_array_attributes *attrib) +{ + assert(vao->NewArrays == 0); + return &vao->BufferBinding[attrib->_EffBufferBindingIndex]; +} + + +/** + * Return vertex array attribute provided the attribute number. + */ +static inline const struct gl_array_attributes* +_mesa_draw_array_attrib(const struct gl_vertex_array_object *vao, + gl_vert_attrib attr) +{ + assert(vao->NewArrays == 0); + const gl_attribute_map_mode map_mode = vao->_AttributeMapMode; + return &vao->VertexAttrib[_mesa_vao_attribute_map[map_mode][attr]]; +} + + +/** + * Return vertex buffer binding provided an attribute number. + */ +static inline const struct gl_vertex_buffer_binding* +_mesa_draw_buffer_binding(const struct gl_vertex_array_object *vao, + gl_vert_attrib attr) +{ + const struct gl_array_attributes *const attrib + = _mesa_draw_array_attrib(vao, attr); + return _mesa_draw_buffer_binding_from_attrib(vao, attrib); +} + + +/** + * Return vertex attribute bits bound at the provided binding. + * + * Needs the a fully updated VAO ready for draw. + */ +static inline GLbitfield +_mesa_draw_bound_attrib_bits(const struct gl_vertex_buffer_binding *binding) +{ + return binding->_EffBoundArrays; +} + + +/** + * Return the vertex offset bound at the provided binding. + * + * Needs the a fully updated VAO ready for draw. + */ +static inline GLintptr +_mesa_draw_binding_offset(const struct gl_vertex_buffer_binding *binding) +{ + return binding->_EffOffset; +} + + +/** + * Return the relative offset of the provided attrib. + * + * Needs the a fully updated VAO ready for draw. + */ +static inline GLushort +_mesa_draw_attributes_relative_offset(const struct gl_array_attributes *attrib) +{ + return attrib->_EffRelativeOffset; +} + + +/** + * Return a current value vertex array attribute provided the attribute number. + */ +static inline const struct gl_array_attributes* +_mesa_draw_current_attrib(const struct gl_context *ctx, gl_vert_attrib attr) +{ + return _vbo_current_attrib(ctx, attr); +} + + +/** + * Return true if we have the VERT_ATTRIB_EDGEFLAG array enabled. + */ +static inline bool +_mesa_draw_edge_flag_array_enabled(const struct gl_context *ctx) +{ + return ctx->Array._DrawVAOEnabledAttribs & VERT_BIT_EDGEFLAG; +} + + +/** + * Return the attrib for the given attribute. + */ +static inline const struct gl_array_attributes* +_mesa_draw_attrib(const struct gl_context *ctx, gl_vert_attrib attr) +{ + if (ctx->Array._DrawVAOEnabledAttribs & VERT_BIT(attr)) { + const struct gl_vertex_array_object *vao = ctx->Array._DrawVAO; + return _mesa_draw_array_attrib(vao, attr); + } else { + return _vbo_current_attrib(ctx, attr); + } +} + + +/** + * Return the attrib, binding pair for the given attribute. + */ +static inline void +_mesa_draw_attrib_and_binding(const struct gl_context *ctx, gl_vert_attrib attr, + const struct gl_array_attributes **attrib, + const struct gl_vertex_buffer_binding **binding) +{ + if (ctx->Array._DrawVAOEnabledAttribs & VERT_BIT(attr)) { + const struct gl_vertex_array_object *vao = ctx->Array._DrawVAO; + *attrib = _mesa_draw_array_attrib(vao, attr); + *binding = _mesa_draw_buffer_binding_from_attrib(vao, *attrib); + } else { + *attrib = _vbo_current_attrib(ctx, attr); + *binding = _vbo_current_binding(ctx); + } +} + + /* * API functions */ diff --git a/src/mesa/main/attrib.c b/src/mesa/main/attrib.c index 6127a556d73..e565750a891 100644 --- a/src/mesa/main/attrib.c +++ b/src/mesa/main/attrib.c @@ -1552,6 +1552,7 @@ copy_array_object(struct gl_context *ctx, /* _Enabled must be the same than on push */ dest->_Enabled = src->_Enabled; + dest->_EffEnabledVBO = src->_EffEnabledVBO; /* The bitmask of bound VBOs needs to match the VertexBinding array */ dest->VertexAttribBufferMask = src->VertexAttribBufferMask; dest->_AttributeMapMode = src->_AttributeMapMode; diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 2c87308dd73..e7517043864 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -1426,6 +1426,32 @@ struct gl_array_attributes unsigned _ElementSize:8; /**< Size of each element in bytes */ /** Index into gl_vertex_array_object::BufferBinding[] array */ unsigned BufferBindingIndex:6; + + /** + * Derived effective buffer binding index + * + * Index into the gl_vertex_buffer_binding array of the vao. + * Similar to BufferBindingIndex, but with the mapping of the + * position/generic0 attributes applied and with identical + * gl_vertex_buffer_binding entries collapsed to a single + * entry within the vao. + * + * The value is valid past calling _mesa_update_vao_derived_arrays. + * Note that _mesa_update_vao_derived_arrays is called when binding + * the VAO to Array._DrawVAO. + */ + unsigned _EffBufferBindingIndex:6; + /** + * Derived effective relative offset. + * + * Relative offset to the effective buffers offset in + * gl_vertex_buffer_binding::_EffOffset. + * + * The value is valid past calling _mesa_update_vao_derived_arrays. + * Note that _mesa_update_vao_derived_arrays is called when binding + * the VAO to Array._DrawVAO. + */ + GLushort _EffRelativeOffset; }; @@ -1441,6 +1467,35 @@ struct gl_vertex_buffer_binding GLuint InstanceDivisor; /**< GL_ARB_instanced_arrays */ struct gl_buffer_object *BufferObj; /**< GL_ARB_vertex_buffer_object */ GLbitfield _BoundArrays; /**< Arrays bound to this binding point */ + + /** + * Derived effective bound arrays. + * + * The effective binding handles enabled arrays past the + * position/generic0 attribute mapping and reduces the refered + * gl_vertex_buffer_binding entries to a unique subset. + * + * The value is valid past calling _mesa_update_vao_derived_arrays. + * Note that _mesa_update_vao_derived_arrays is called when binding + * the VAO to Array._DrawVAO. + */ + GLbitfield _EffBoundArrays; + /** + * Derived offset. + * + * The absolute offset to that we can collapse some attributes + * to this unique effective binding. + * For user space array bindings this contains the smallest pointer value + * in the bound and interleaved arrays. + * For VBO bindings this contains an offset that lets the attributes + * _EffRelativeOffset stay positive and in bounds with + * Const.MaxVertexAttribRelativeOffset + * + * The value is valid past calling _mesa_update_vao_derived_arrays. + * Note that _mesa_update_vao_derived_arrays is called when binding + * the VAO to Array._DrawVAO. + */ + GLintptr _EffOffset; }; @@ -1495,6 +1550,15 @@ struct gl_vertex_array_object /** Mask of VERT_BIT_* values indicating which arrays are enabled */ GLbitfield _Enabled; + /** + * Mask of VERT_BIT_* enabled arrays past position/generic0 mapping + * + * The value is valid past calling _mesa_update_vao_derived_arrays. + * Note that _mesa_update_vao_derived_arrays is called when binding + * the VAO to Array._DrawVAO. + */ + GLbitfield _EffEnabledVBO; + /** Denotes the way the position/generic0 attribute is mapped */ gl_attribute_map_mode _AttributeMapMode; diff --git a/src/mesa/main/varray.c b/src/mesa/main/varray.c index 5df38a14f0a..d16807b406c 100644 --- a/src/mesa/main/varray.c +++ b/src/mesa/main/varray.c @@ -604,6 +604,11 @@ update_array(struct gl_context *ctx, /* The Stride and Ptr fields are not set by update_array_format() */ struct gl_array_attributes *array = &vao->VertexAttrib[attrib]; array->Stride = stride; + /* For updating the pointer we would need to add the vao->NewArrays flag + * to the VAO. But but that is done already unconditionally in + * _mesa_update_array_format called above. + */ + assert((vao->NewArrays | ~vao->_Enabled) & VERT_BIT(attrib)); array->Ptr = ptr; /* Update the vertex buffer binding */ @@ -2868,6 +2873,8 @@ _mesa_copy_vertex_attrib_array(struct gl_context *ctx, dst->Ptr = src->Ptr; dst->Enabled = src->Enabled; dst->_ElementSize = src->_ElementSize; + dst->_EffBufferBindingIndex = src->_EffBufferBindingIndex; + dst->_EffRelativeOffset = src->_EffRelativeOffset; } void @@ -2879,6 +2886,8 @@ _mesa_copy_vertex_buffer_binding(struct gl_context *ctx, dst->Stride = src->Stride; dst->InstanceDivisor = src->InstanceDivisor; dst->_BoundArrays = src->_BoundArrays; + dst->_EffBoundArrays = src->_EffBoundArrays; + dst->_EffOffset = src->_EffOffset; _mesa_reference_buffer_object(ctx, &dst->BufferObj, src->BufferObj); } diff --git a/src/mesa/vbo/vbo.h b/src/mesa/vbo/vbo.h index 9b150662915..ca46f9baa79 100644 --- a/src/mesa/vbo/vbo.h +++ b/src/mesa/vbo/vbo.h @@ -186,6 +186,14 @@ void _vbo_update_inputs(struct gl_context *ctx, struct vbo_inputs *inputs); +const struct gl_array_attributes* +_vbo_current_attrib(const struct gl_context *ctx, gl_vert_attrib attr); + + +const struct gl_vertex_buffer_binding* +_vbo_current_binding(const struct gl_context *ctx); + + void GLAPIENTRY _es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a); diff --git a/src/mesa/vbo/vbo_context.c b/src/mesa/vbo/vbo_context.c index ada78ffd63b..cc6aada8610 100644 --- a/src/mesa/vbo/vbo_context.c +++ b/src/mesa/vbo/vbo_context.c @@ -234,6 +234,23 @@ _vbo_DestroyContext(struct gl_context *ctx) } +const struct gl_array_attributes * +_vbo_current_attrib(const struct gl_context *ctx, gl_vert_attrib attr) +{ + const struct vbo_context *vbo = vbo_context_const(ctx); + const gl_vertex_processing_mode vmp = ctx->VertexProgram._VPMode; + return &vbo->current[_vbo_attribute_alias_map[vmp][attr]]; +} + + +const struct gl_vertex_buffer_binding * +_vbo_current_binding(const struct gl_context *ctx) +{ + const struct vbo_context *vbo = vbo_context_const(ctx); + return &vbo->binding; +} + + /* * Helper function for _vbo_draw_indirect below that additionally takes a zero * initialized array of _mesa_prim scratch space memory as the last argument. diff --git a/src/mesa/vbo/vbo_private.h b/src/mesa/vbo/vbo_private.h index 589c61d675e..b69f836aa0b 100644 --- a/src/mesa/vbo/vbo_private.h +++ b/src/mesa/vbo/vbo_private.h @@ -60,6 +60,13 @@ vbo_context(struct gl_context *ctx) } +static inline const struct vbo_context * +vbo_context_const(const struct gl_context *ctx) +{ + return ctx->vbo_context; +} + + /** * Array to apply the fixed function material aliasing map to * an attribute value used in vbo processing inputs to an attribute @@ -209,7 +216,12 @@ _vbo_set_attrib_format(struct gl_context *ctx, const GLboolean doubles = vbo_attrtype_to_double_flag(type); _mesa_update_array_format(ctx, vao, attr, size, type, GL_RGBA, GL_FALSE, integer, doubles, offset); - /* Ptr for userspace arrays */ + /* Ptr for userspace arrays. + * For updating the pointer we would need to add the vao->NewArrays flag + * to the VAO. But but that is done already unconditionally in + * _mesa_update_array_format called above. + */ + assert((vao->NewArrays | ~vao->_Enabled) & VERT_BIT(attr)); vao->VertexAttrib[attr].Ptr = ADD_POINTERS(buffer_offset, offset); } -- 2.30.2