X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Ftransformfeedback.c;h=abeb25e87340e3e109a4354505e9e3ddb3b6769b;hb=c03477050a6f51e601f75cb3c061a3e16a5b7171;hp=d0118c5f7c74d2f1c349dde63fe49b899fcc0075;hpb=b76f6d9557ff27140e18cf8aa2b57db8876d5d4d;p=mesa.git diff --git a/src/mesa/main/transformfeedback.c b/src/mesa/main/transformfeedback.c index d0118c5f7c7..abeb25e8734 100644 --- a/src/mesa/main/transformfeedback.c +++ b/src/mesa/main/transformfeedback.c @@ -16,14 +16,15 @@ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. */ /* - * Vertex transform feedback support. + * Transform feedback support. * * Authors: * Brian Paul @@ -43,6 +44,41 @@ #include "program/prog_parameter.h" +struct using_program_tuple +{ + struct gl_shader_program *shProg; + bool found; +}; + +static void +active_xfb_object_references_program(GLuint key, void *data, void *user_data) +{ + struct using_program_tuple *callback_data = user_data; + struct gl_transform_feedback_object *obj = data; + if (obj->Active && obj->shader_program == callback_data->shProg) + callback_data->found = true; +} + +/** + * Return true if any active transform feedback object is using a program. + */ +bool +_mesa_transform_feedback_is_using_program(struct gl_context *ctx, + struct gl_shader_program *shProg) +{ + struct using_program_tuple callback_data; + callback_data.shProg = shProg; + callback_data.found = false; + + _mesa_HashWalk(ctx->TransformFeedback.Objects, + active_xfb_object_references_program, &callback_data); + + /* Also check DefaultObject, as it's not in the Objects hash table. */ + active_xfb_object_references_program(0, ctx->TransformFeedback.DefaultObject, + &callback_data); + + return callback_data.found; +} /** * Do reference counting of transform feedback buffers. @@ -169,17 +205,27 @@ _mesa_free_transform_feedback(struct gl_context *ctx) } +/** Initialize the fields of a gl_transform_feedback_object. */ +void +_mesa_init_transform_feedback_object(struct gl_transform_feedback_object *obj, + GLuint name) +{ + if (!obj) + return; + + obj->Name = name; + obj->RefCount = 1; + obj->EverBound = GL_FALSE; +} + + /** Default fallback for ctx->Driver.NewTransformFeedback() */ static struct gl_transform_feedback_object * new_transform_feedback(struct gl_context *ctx, GLuint name) { struct gl_transform_feedback_object *obj; obj = CALLOC_STRUCT(gl_transform_feedback_object); - if (obj) { - obj->Name = name; - obj->RefCount = 1; - obj->EverBound = GL_FALSE; - } + _mesa_init_transform_feedback_object(obj, name); return obj; } @@ -194,6 +240,7 @@ delete_transform_feedback(struct gl_context *ctx, _mesa_reference_buffer_object(ctx, &obj->Buffers[i], NULL); } + free(obj->Label); free(obj); } @@ -329,24 +376,48 @@ _mesa_compute_max_transform_feedback_vertices( **/ +/** + * Figure out which stage of the pipeline is the source of transform feedback + * data given the current context state, and return its gl_shader_program. + * + * If no active program can generate transform feedback data (i.e. no vertex + * shader is active), returns NULL. + */ +static struct gl_shader_program * +get_xfb_source(struct gl_context *ctx) +{ + int i; + for (i = MESA_SHADER_GEOMETRY; i >= MESA_SHADER_VERTEX; i--) { + if (ctx->_Shader->CurrentProgram[i] != NULL) + return ctx->_Shader->CurrentProgram[i]; + } + return NULL; +} + + void GLAPIENTRY _mesa_BeginTransformFeedback(GLenum mode) { struct gl_transform_feedback_object *obj; - struct gl_transform_feedback_info *info; + struct gl_transform_feedback_info *info = NULL; + struct gl_shader_program *source; GLuint i; unsigned vertices_per_prim; GET_CURRENT_CONTEXT(ctx); obj = ctx->TransformFeedback.CurrentObject; - if (ctx->Shader.CurrentVertexProgram == NULL) { + /* Figure out what pipeline stage is the source of data for transform + * feedback. + */ + source = get_xfb_source(ctx); + if (source == NULL) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginTransformFeedback(no program active)"); return; } - info = &ctx->Shader.CurrentVertexProgram->LinkedTransformFeedback; + info = &source->LinkedTransformFeedback; if (info->NumOutputs == 0) { _mesa_error(ctx, GL_INVALID_OPERATION, @@ -384,7 +455,9 @@ _mesa_BeginTransformFeedback(GLenum mode) } } - FLUSH_VERTICES(ctx, _NEW_TRANSFORM_FEEDBACK); + FLUSH_VERTICES(ctx, 0); + ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback; + obj->Active = GL_TRUE; ctx->TransformFeedback.Mode = mode; @@ -402,6 +475,11 @@ _mesa_BeginTransformFeedback(GLenum mode) obj->GlesRemainingPrims = max_vertices / vertices_per_prim; } + if (obj->shader_program != source) { + ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedbackProg; + obj->shader_program = source; + } + assert(ctx->Driver.BeginTransformFeedback); ctx->Driver.BeginTransformFeedback(ctx, mode, obj); } @@ -421,7 +499,9 @@ _mesa_EndTransformFeedback(void) return; } - FLUSH_VERTICES(ctx, _NEW_TRANSFORM_FEEDBACK); + FLUSH_VERTICES(ctx, 0); + ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback; + ctx->TransformFeedback.CurrentObject->Active = GL_FALSE; ctx->TransformFeedback.CurrentObject->Paused = GL_FALSE; ctx->TransformFeedback.CurrentObject->EndedAnytime = GL_TRUE; @@ -442,7 +522,7 @@ bind_buffer_range(struct gl_context *ctx, GLuint index, struct gl_transform_feedback_object *obj = ctx->TransformFeedback.CurrentObject; - /* Note: no need to FLUSH_VERTICES or flag _NEW_TRANSFORM_FEEDBACK, because + /* Note: no need to FLUSH_VERTICES or flag NewTransformFeedback, because * transform feedback buffers can't be changed while transform feedback is * active. */ @@ -465,7 +545,7 @@ bind_buffer_range(struct gl_context *ctx, GLuint index, /** - * Specify a buffer object to receive vertex shader results. Plus, + * Specify a buffer object to receive transform feedback results. Plus, * specify the starting offset to place the results, and max size. * Called from the glBindBufferRange() function. */ @@ -509,7 +589,7 @@ _mesa_bind_buffer_range_transform_feedback(struct gl_context *ctx, /** - * Specify a buffer object to receive vertex shader results. + * Specify a buffer object to receive transform feedback results. * As above, but start at offset = 0. * Called from the glBindBufferBase() function. */ @@ -538,7 +618,7 @@ _mesa_bind_buffer_base_transform_feedback(struct gl_context *ctx, /** - * Specify a buffer object to receive vertex shader results, plus the + * Specify a buffer object to receive transform feedback results, plus the * offset in the buffer to start placing results. * This function is part of GL_EXT_transform_feedback, but not GL3. */ @@ -593,7 +673,7 @@ _mesa_BindBufferOffsetEXT(GLenum target, GLuint index, GLuint buffer, /** - * This function specifies the vertex shader outputs to be written + * This function specifies the transform feedback outputs to be written * to the feedback buffer(s), and in what order. */ void GLAPIENTRY @@ -605,6 +685,16 @@ _mesa_TransformFeedbackVaryings(GLuint program, GLsizei count, GLint i; GET_CURRENT_CONTEXT(ctx); + /* From the ARB_transform_feedback2 specification: + * "The error INVALID_OPERATION is generated by TransformFeedbackVaryings + * if the current transform feedback object is active, even if paused." + */ + if (ctx->TransformFeedback.CurrentObject->Active) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTransformFeedbackVaryings(current object is active)"); + return; + } + switch (bufferMode) { case GL_INTERLEAVED_ATTRIBS: break; @@ -686,14 +776,14 @@ _mesa_TransformFeedbackVaryings(GLuint program, GLsizei count, shProg->TransformFeedback.BufferMode = bufferMode; - /* No need to set _NEW_TRANSFORM_FEEDBACK (or invoke FLUSH_VERTICES) since + /* No need to invoke FLUSH_VERTICES or flag NewTransformFeedback since * the varyings won't be used until shader link time. */ } /** - * Get info about the vertex shader's outputs which are to be written + * Get info about the transform feedback outputs which are to be written * to the feedback buffer(s). */ void GLAPIENTRY @@ -897,7 +987,9 @@ _mesa_PauseTransformFeedback(void) return; } - FLUSH_VERTICES(ctx, _NEW_TRANSFORM_FEEDBACK); + FLUSH_VERTICES(ctx, 0); + ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback; + obj->Paused = GL_TRUE; assert(ctx->Driver.PauseTransformFeedback); @@ -923,7 +1015,20 @@ _mesa_ResumeTransformFeedback(void) return; } - FLUSH_VERTICES(ctx, _NEW_TRANSFORM_FEEDBACK); + /* From the ARB_transform_feedback2 specification: + * "The error INVALID_OPERATION is generated by ResumeTransformFeedback if + * the program object being used by the current transform feedback object + * is not active." + */ + if (obj->shader_program != get_xfb_source(ctx)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glResumeTransformFeedback(wrong program bound)"); + return; + } + + FLUSH_VERTICES(ctx, 0); + ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback; + obj->Paused = GL_FALSE; assert(ctx->Driver.ResumeTransformFeedback);