[Mesa-dev] [PATCH v2 5/6] mesa: Fix corner cases of BindBufferBase with transform feedback.
Ian Romanick
idr at freedesktop.org
Tue Dec 18 11:35:27 PST 2012
On 12/15/2012 10:09 PM, Paul Berry wrote:
> This patch implements the following behaviours, which are mandated by
> the GL 4.3 and GLES3 specs.
>
> 1. Regarding the GL_TRANSFORM_FEEDBACK_BUFFER_SIZE query: "If the
> ... size was not specified when the buffer object was bound
> (e.g. if it was bound with BindBufferBase), ... zero is returned."
> (GL 4.3 section 6.7.1 "Indexed Buffer Object Limits and Binding
> Queries").
>
> 2. "BindBufferBase binds the entire buffer, even when the size of the
> buffer is changed after the binding is established. It is
> equivalent to calling BindBufferRange with offset zero, while size
> is determined by the size of the bound buffer at the time the
> binding is used." (GL 4.3 section 6.1.1 "Binding Buffer Objects to
> Indexed Targets"). I interpret "at the time the binding is used"
> to mean "at the time of the call to glBeginTransformFeedback".
>
> 3. "Regardless of the size specified with BindBufferRange, or
> indirectly with BindBufferBase, the GL will never read or write
> beyond the end of a bound buffer. In some cases this constraint may
> result in visibly different behavior when a buffer overflow would
> otherwise result, such as described for transform feedback
> operations in section 13.2.2." (GL 4.3 section 6.1.1 "Binding
> Buffer Objects to Indexed Targets").
>
> Item 1 has been part of the spec all the way back to the inception of
> the EXT_transform_feedback extension. Items 2 and 3 were added in GL
> 4.2 and GLES 3.
>
> Prior to GL 4.2, in place of items 2 and 3, the spec simply said
> "BindBufferBase is equivalent to calling BindBufferRange with offset
> zero and size equal to the size of buffer." For transform feedback,
> Mesa behaved as though this meant "...equal to the size of buffer at
> the time of the call to BindBufferBase". However, this was
> problematic because it left it ambiguous what to do if the buffer is
> shrunk between the call to BindBuffer{Base,Range} and the call to
> BeginTransformFeedback. Prior to this patch, Mesa's behaviour was to
> try to write beyond the end of the buffer, likely resulting in memory
> corruption. In light of this, I'm interpreting the spec change as a
> clarification, not an intended behavioural change, so I'm making the
> change apply regardless of API version.
>
> Fixes GLES3 conformance test transform_feedback2_pause_resume.test.
>
> Cc: Eric Anholt <eric at anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick at intel.com>
> ---
> src/mesa/main/get.c | 3 +-
> src/mesa/main/mtypes.h | 13 +++++++-
> src/mesa/main/transformfeedback.c | 69 ++++++++++++++++++++++++++++++---------
> 3 files changed, 68 insertions(+), 17 deletions(-)
>
> diff --git a/src/mesa/main/get.c b/src/mesa/main/get.c
> index f3dbda2..273a79f 100644
> --- a/src/mesa/main/get.c
> +++ b/src/mesa/main/get.c
> @@ -1574,7 +1574,8 @@ find_value_indexed(const char *func, GLenum pname, GLuint index, union value *v)
> goto invalid_value;
> if (!ctx->Extensions.EXT_transform_feedback)
> goto invalid_enum;
> - v->value_int64 = ctx->TransformFeedback.CurrentObject->Size[index];
> + v->value_int64
> + = ctx->TransformFeedback.CurrentObject->RequestedSize[index];
> return TYPE_INT64;
>
> case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
> diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
> index 18ab2db..96b84d8 100644
> --- a/src/mesa/main/mtypes.h
> +++ b/src/mesa/main/mtypes.h
> @@ -1825,8 +1825,19 @@ struct gl_transform_feedback_object
>
> /** Start of feedback data in dest buffer */
> GLintptr Offset[MAX_FEEDBACK_BUFFERS];
> - /** Max data to put into dest buffer (in bytes) */
> +
> + /**
> + * Max data to put into dest buffer (in bytes). Computed based on
> + * RequestedSize and the actual size of the buffer.
> + */
> GLsizeiptr Size[MAX_FEEDBACK_BUFFERS];
> +
> + /**
> + * Size that was specified when the buffer was bound. If the buffer was
> + * bound with glBindBufferBase() or glBindBufferOffsetEXT(), this value is
> + * zero.
> + */
> + GLsizeiptr RequestedSize[MAX_FEEDBACK_BUFFERS];
> };
>
>
> diff --git a/src/mesa/main/transformfeedback.c b/src/mesa/main/transformfeedback.c
> index 4782a6f..dd03038 100644
> --- a/src/mesa/main/transformfeedback.c
> +++ b/src/mesa/main/transformfeedback.c
> @@ -247,6 +247,55 @@ _mesa_init_transform_feedback_functions(struct dd_function_table *driver)
>
>
> /**
> + * Fill in the correct Size value for each buffer in \c obj.
> + *
> + * From the GL 4.3 spec, section 6.1.1 ("Binding Buffer Objects to Indexed
> + * Targets"):
> + *
> + * BindBufferBase binds the entire buffer, even when the size of the buffer
> + * is changed after the binding is established. It is equivalent to calling
> + * BindBufferRange with offset zero, while size is determined by the size of
> + * the bound buffer at the time the binding is used.
> + *
> + * Regardless of the size specified with BindBufferRange, or indirectly with
> + * BindBufferBase, the GL will never read or write beyond the end of a bound
> + * buffer. In some cases this constraint may result in visibly different
> + * behavior when a buffer overflow would otherwise result, such as described
> + * for transform feedback operations in section 13.2.2.
> + */
> +static void
> +compute_transform_feedback_buffer_sizes(
> + struct gl_transform_feedback_object *obj)
> +{
> + unsigned i = 0;
> + for (i = 0; i < MAX_FEEDBACK_BUFFERS; ++i) {
> + GLintptr offset = obj->Offset[i];
> + GLsizeiptr buffer_size
> + = obj->Buffers[i] == NULL ? 0 : obj->Buffers[i]->Size;
> + GLsizeiptr available_space
> + = buffer_size <= offset ? 0 : buffer_size - offset;
> + GLsizeiptr computed_size;
> + if (obj->RequestedSize[i] == 0) {
> + /* No size was specified at the time the buffer was bound, so allow
> + * writing to all available space in the buffer.
> + */
> + computed_size = available_space;
> + } else {
> + /* A size was specified at the time the buffer was bound, however
> + * it's possible that the buffer has shrunk since then. So only
> + * allow writing to the minimum of the specified size and the space
> + * available.
> + */
> + computed_size = MIN2(available_space, obj->RequestedSize[i]);
> + }
> +
> + /* Legal sizes must be multiples of four, so round down if necessary. */
> + obj->Size[i] = computed_size & ~0x3;
> + }
> +}
> +
> +
> +/**
> * Compute the maximum number of vertices that can be written to the currently
> * enabled transform feedback buffers without overflowing any of them.
> */
> @@ -337,6 +386,8 @@ _mesa_BeginTransformFeedback(GLenum mode)
> obj->Active = GL_TRUE;
> ctx->TransformFeedback.Mode = mode;
>
> + compute_transform_feedback_buffer_sizes(obj);
> +
> if (_mesa_is_gles3(ctx)) {
> /* In GLES3, we are required to track the usage of the transform
> * feedback buffer and report INVALID_OPERATION if a draw call tries to
> @@ -407,7 +458,7 @@ bind_buffer_range(struct gl_context *ctx, GLuint index,
> obj->BufferNames[index] = bufObj->Name;
>
> obj->Offset[index] = offset;
> - obj->Size[index] = size;
> + obj->RequestedSize[index] = size;
> }
>
>
> @@ -466,7 +517,6 @@ _mesa_bind_buffer_base_transform_feedback(struct gl_context *ctx,
> struct gl_buffer_object *bufObj)
> {
> struct gl_transform_feedback_object *obj;
> - GLsizeiptr size;
>
> obj = ctx->TransformFeedback.CurrentObject;
>
> @@ -481,12 +531,7 @@ _mesa_bind_buffer_base_transform_feedback(struct gl_context *ctx,
> return;
> }
>
> - /* default size is the buffer size rounded down to nearest
> - * multiple of four.
> - */
> - size = bufObj->Size & ~0x3;
> -
> - bind_buffer_range(ctx, index, bufObj, 0, size);
> + bind_buffer_range(ctx, index, bufObj, 0, 0);
> }
>
>
> @@ -502,7 +547,6 @@ _mesa_BindBufferOffsetEXT(GLenum target, GLuint index, GLuint buffer,
> struct gl_transform_feedback_object *obj;
> struct gl_buffer_object *bufObj;
> GET_CURRENT_CONTEXT(ctx);
> - GLsizeiptr size;
>
> if (target != GL_TRANSFORM_FEEDBACK_BUFFER) {
> _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferOffsetEXT(target)");
> @@ -542,12 +586,7 @@ _mesa_BindBufferOffsetEXT(GLenum target, GLuint index, GLuint buffer,
> return;
> }
>
> - /* default size is the buffer size rounded down to nearest
> - * multiple of four.
> - */
> - size = (bufObj->Size - offset) & ~0x3;
> -
> - bind_buffer_range(ctx, index, bufObj, offset, size);
> + bind_buffer_range(ctx, index, bufObj, offset, 0);
> }
>
>
>
More information about the mesa-dev
mailing list