X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Ftransformfeedback.c;h=a73746335fe50d402a8c3edc6bb925a0aabddb33;hb=c1df492d03862f75698ba5d50d4f46cd528ffc0d;hp=61f2f4f11d01de8776625c7921e44dbdc21a6a28;hpb=1ad516207d2297b14fe26627e5bb599a9f704ac5;p=mesa.git diff --git a/src/mesa/main/transformfeedback.c b/src/mesa/main/transformfeedback.c index 61f2f4f11d0..a73746335fe 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 @@ -31,11 +32,9 @@ #include "buffers.h" -#include "bufferobj.h" #include "context.h" #include "hash.h" #include "macros.h" -#include "mfeatures.h" #include "mtypes.h" #include "transformfeedback.h" #include "shaderapi.h" @@ -44,6 +43,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. @@ -80,6 +114,7 @@ reference_transform_feedback_object(struct gl_transform_feedback_object **ptr, } else { obj->RefCount++; + obj->EverBound = GL_TRUE; *ptr = obj; } } @@ -169,16 +204,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; - } + _mesa_init_transform_feedback_object(obj, name); return obj; } @@ -193,6 +239,7 @@ delete_transform_feedback(struct gl_context *ctx, _mesa_reference_buffer_object(ctx, &obj->Buffers[i], NULL); } + free(obj->Label); free(obj); } @@ -328,24 +375,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, @@ -383,7 +454,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; @@ -401,6 +474,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); } @@ -420,7 +498,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; @@ -441,7 +521,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. */ @@ -452,19 +532,12 @@ bind_buffer_range(struct gl_context *ctx, GLuint index, bufObj); /* The per-attribute binding point */ - _mesa_reference_buffer_object(ctx, - &obj->Buffers[index], - bufObj); - - obj->BufferNames[index] = bufObj->Name; - - obj->Offset[index] = offset; - obj->RequestedSize[index] = size; + _mesa_set_transform_feedback_binding(ctx, obj, index, bufObj, offset, size); } /** - * 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. */ @@ -508,7 +581,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. */ @@ -537,7 +610,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. */ @@ -592,7 +665,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 @@ -604,6 +677,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; @@ -685,14 +768,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 @@ -755,8 +838,6 @@ _mesa_GenTransformFeedbacks(GLsizei n, GLuint *names) GLuint first; GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glGenTransformFeedbacks(n < 0)"); return; @@ -793,14 +874,19 @@ _mesa_GenTransformFeedbacks(GLsizei n, GLuint *names) GLboolean GLAPIENTRY _mesa_IsTransformFeedback(GLuint name) { + struct gl_transform_feedback_object *obj; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); - if (name && _mesa_lookup_transform_feedback_object(ctx, name)) - return GL_TRUE; - else + if (name == 0) + return GL_FALSE; + + obj = _mesa_lookup_transform_feedback_object(ctx, name); + if (obj == NULL) return GL_FALSE; + + return obj->EverBound; } @@ -819,8 +905,7 @@ _mesa_BindTransformFeedback(GLenum target, GLuint name) return; } - if (ctx->TransformFeedback.CurrentObject->Active && - !ctx->TransformFeedback.CurrentObject->Paused) { + if (_mesa_is_xfb_active_and_unpaused(ctx)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBindTransformFeedback(transform is active, or not paused)"); return; @@ -848,8 +933,6 @@ _mesa_DeleteTransformFeedbacks(GLsizei n, const GLuint *names) GLint i; GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteTransformFeedbacks(n < 0)"); return; @@ -890,13 +973,15 @@ _mesa_PauseTransformFeedback(void) obj = ctx->TransformFeedback.CurrentObject; - if (!obj->Active || obj->Paused) { + if (!_mesa_is_xfb_active_and_unpaused(ctx)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glPauseTransformFeedback(feedback not active or already paused)"); return; } - FLUSH_VERTICES(ctx, _NEW_TRANSFORM_FEEDBACK); + FLUSH_VERTICES(ctx, 0); + ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback; + obj->Paused = GL_TRUE; assert(ctx->Driver.PauseTransformFeedback); @@ -922,7 +1007,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);