2 * Mesa 3-D graphics library
4 * Copyright (C) 2010 VMware, Inc. All Rights Reserved.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 * Vertex transform feedback support.
34 #include "bufferobj.h"
37 #include "mfeatures.h"
39 #include "transformfeedback.h"
40 #include "shaderapi.h"
41 #include "shaderobj.h"
42 #include "main/dispatch.h"
44 #include "program/prog_parameter.h"
47 #if FEATURE_EXT_transform_feedback
51 * Do reference counting of transform feedback buffers.
54 reference_transform_feedback_object(struct gl_transform_feedback_object **ptr,
55 struct gl_transform_feedback_object *obj)
61 /* Unreference the old object */
62 struct gl_transform_feedback_object *oldObj = *ptr;
64 ASSERT(oldObj->RefCount > 0);
67 if (oldObj->RefCount == 0) {
68 GET_CURRENT_CONTEXT(ctx);
70 ctx->Driver.DeleteTransformFeedback(ctx, oldObj);
78 /* reference new object */
79 if (obj->RefCount == 0) {
80 _mesa_problem(NULL, "referencing deleted transform feedback object");
92 * Check if the given primitive mode (as in glBegin(mode)) is compatible
93 * with the current transform feedback mode (if it's enabled).
94 * This is to be called from glBegin(), glDrawArrays(), glDrawElements(), etc.
96 * \return GL_TRUE if the mode is OK, GL_FALSE otherwise.
99 _mesa_validate_primitive_mode(struct gl_context *ctx, GLenum mode)
101 if (ctx->TransformFeedback.CurrentObject->Active) {
104 return ctx->TransformFeedback.Mode == GL_POINTS;
108 return ctx->TransformFeedback.Mode == GL_LINES;
110 return ctx->TransformFeedback.Mode == GL_TRIANGLES;
118 * Check that all the buffer objects currently bound for transform
119 * feedback actually exist. Raise a GL_INVALID_OPERATION error if
120 * any buffers are missing.
121 * \return GL_TRUE for success, GL_FALSE if error
124 _mesa_validate_transform_feedback_buffers(struct gl_context *ctx)
133 * Per-context init for transform feedback.
136 _mesa_init_transform_feedback(struct gl_context *ctx)
138 /* core mesa expects this, even a dummy one, to be available */
139 ASSERT(ctx->Driver.NewTransformFeedback);
141 ctx->TransformFeedback.DefaultObject =
142 ctx->Driver.NewTransformFeedback(ctx, 0);
144 assert(ctx->TransformFeedback.DefaultObject->RefCount == 1);
146 reference_transform_feedback_object(&ctx->TransformFeedback.CurrentObject,
147 ctx->TransformFeedback.DefaultObject);
149 assert(ctx->TransformFeedback.DefaultObject->RefCount == 2);
151 ctx->TransformFeedback.Objects = _mesa_NewHashTable();
153 _mesa_reference_buffer_object(ctx,
154 &ctx->TransformFeedback.CurrentBuffer,
155 ctx->Shared->NullBufferObj);
161 * Callback for _mesa_HashDeleteAll().
164 delete_cb(GLuint key, void *data, void *userData)
166 struct gl_context *ctx = (struct gl_context *) userData;
167 struct gl_transform_feedback_object *obj =
168 (struct gl_transform_feedback_object *) data;
170 ctx->Driver.DeleteTransformFeedback(ctx, obj);
175 * Per-context free/clean-up for transform feedback.
178 _mesa_free_transform_feedback(struct gl_context *ctx)
180 /* core mesa expects this, even a dummy one, to be available */
181 ASSERT(ctx->Driver.NewTransformFeedback);
183 _mesa_reference_buffer_object(ctx,
184 &ctx->TransformFeedback.CurrentBuffer,
187 /* Delete all feedback objects */
188 _mesa_HashDeleteAll(ctx->TransformFeedback.Objects, delete_cb, ctx);
189 _mesa_DeleteHashTable(ctx->TransformFeedback.Objects);
191 /* Delete the default feedback object */
192 assert(ctx->Driver.DeleteTransformFeedback);
193 ctx->Driver.DeleteTransformFeedback(ctx,
194 ctx->TransformFeedback.DefaultObject);
196 ctx->TransformFeedback.CurrentObject = NULL;
200 #else /* FEATURE_EXT_transform_feedback */
202 /* forward declarations */
203 static struct gl_transform_feedback_object *
204 new_transform_feedback(struct gl_context *ctx, GLuint name);
207 delete_transform_feedback(struct gl_context *ctx,
208 struct gl_transform_feedback_object *obj);
210 /* dummy per-context init/clean-up for transform feedback */
212 _mesa_init_transform_feedback(struct gl_context *ctx)
214 ctx->TransformFeedback.DefaultObject = new_transform_feedback(ctx, 0);
215 ctx->TransformFeedback.CurrentObject = ctx->TransformFeedback.DefaultObject;
216 _mesa_reference_buffer_object(ctx,
217 &ctx->TransformFeedback.CurrentBuffer,
218 ctx->Shared->NullBufferObj);
222 _mesa_free_transform_feedback(struct gl_context *ctx)
224 _mesa_reference_buffer_object(ctx,
225 &ctx->TransformFeedback.CurrentBuffer,
227 ctx->TransformFeedback.CurrentObject = NULL;
228 delete_transform_feedback(ctx, ctx->TransformFeedback.DefaultObject);
231 #endif /* FEATURE_EXT_transform_feedback */
234 /** Default fallback for ctx->Driver.NewTransformFeedback() */
235 static struct gl_transform_feedback_object *
236 new_transform_feedback(struct gl_context *ctx, GLuint name)
238 struct gl_transform_feedback_object *obj;
239 obj = CALLOC_STRUCT(gl_transform_feedback_object);
247 /** Default fallback for ctx->Driver.DeleteTransformFeedback() */
249 delete_transform_feedback(struct gl_context *ctx,
250 struct gl_transform_feedback_object *obj)
254 for (i = 0; i < Elements(obj->Buffers); i++) {
255 _mesa_reference_buffer_object(ctx, &obj->Buffers[i], NULL);
262 #if FEATURE_EXT_transform_feedback
265 /** Default fallback for ctx->Driver.BeginTransformFeedback() */
267 begin_transform_feedback(struct gl_context *ctx, GLenum mode,
268 struct gl_transform_feedback_object *obj)
273 /** Default fallback for ctx->Driver.EndTransformFeedback() */
275 end_transform_feedback(struct gl_context *ctx,
276 struct gl_transform_feedback_object *obj)
281 /** Default fallback for ctx->Driver.PauseTransformFeedback() */
283 pause_transform_feedback(struct gl_context *ctx,
284 struct gl_transform_feedback_object *obj)
289 /** Default fallback for ctx->Driver.ResumeTransformFeedback() */
291 resume_transform_feedback(struct gl_context *ctx,
292 struct gl_transform_feedback_object *obj)
297 /** Default fallback for ctx->Driver.DrawTransformFeedback() */
299 draw_transform_feedback(struct gl_context *ctx, GLenum mode,
300 struct gl_transform_feedback_object *obj)
304 * Get number of vertices in obj's feedback buffer.
305 * Call ctx->Exec.DrawArrays(mode, 0, count);
311 * Plug in default device driver functions for transform feedback.
312 * Most drivers will override some/all of these.
315 _mesa_init_transform_feedback_functions(struct dd_function_table *driver)
317 driver->NewTransformFeedback = new_transform_feedback;
318 driver->DeleteTransformFeedback = delete_transform_feedback;
319 driver->BeginTransformFeedback = begin_transform_feedback;
320 driver->EndTransformFeedback = end_transform_feedback;
321 driver->PauseTransformFeedback = pause_transform_feedback;
322 driver->ResumeTransformFeedback = resume_transform_feedback;
323 driver->DrawTransformFeedback = draw_transform_feedback;
328 _mesa_init_transform_feedback_dispatch(struct _glapi_table *disp)
330 SET_BeginTransformFeedbackEXT(disp, _mesa_BeginTransformFeedback);
331 SET_EndTransformFeedbackEXT(disp, _mesa_EndTransformFeedback);
332 SET_BindBufferRangeEXT(disp, _mesa_BindBufferRange);
333 SET_BindBufferBaseEXT(disp, _mesa_BindBufferBase);
334 SET_BindBufferOffsetEXT(disp, _mesa_BindBufferOffsetEXT);
335 SET_TransformFeedbackVaryingsEXT(disp, _mesa_TransformFeedbackVaryings);
336 SET_GetTransformFeedbackVaryingEXT(disp, _mesa_GetTransformFeedbackVarying);
341 ** Begin API functions
346 _mesa_BeginTransformFeedback(GLenum mode)
348 struct gl_transform_feedback_object *obj;
349 GET_CURRENT_CONTEXT(ctx);
351 obj = ctx->TransformFeedback.CurrentObject;
360 _mesa_error(ctx, GL_INVALID_ENUM, "glBeginTransformFeedback(mode)");
365 _mesa_error(ctx, GL_INVALID_OPERATION,
366 "glBeginTransformFeedback(already active)");
370 obj->Active = GL_TRUE;
371 ctx->TransformFeedback.Mode = mode;
373 assert(ctx->Driver.BeginTransformFeedback);
374 ctx->Driver.BeginTransformFeedback(ctx, mode, obj);
379 _mesa_EndTransformFeedback(void)
381 struct gl_transform_feedback_object *obj;
382 GET_CURRENT_CONTEXT(ctx);
384 obj = ctx->TransformFeedback.CurrentObject;
387 _mesa_error(ctx, GL_INVALID_OPERATION,
388 "glEndTransformFeedback(not active)");
392 ctx->TransformFeedback.CurrentObject->Active = GL_FALSE;
394 assert(ctx->Driver.EndTransformFeedback);
395 ctx->Driver.EndTransformFeedback(ctx, obj);
400 * Helper used by BindBufferRange() and BindBufferBase().
403 bind_buffer_range(struct gl_context *ctx, GLuint index,
404 struct gl_buffer_object *bufObj,
405 GLintptr offset, GLsizeiptr size)
407 struct gl_transform_feedback_object *obj =
408 ctx->TransformFeedback.CurrentObject;
410 /* The general binding point */
411 _mesa_reference_buffer_object(ctx,
412 &ctx->TransformFeedback.CurrentBuffer,
415 /* The per-attribute binding point */
416 _mesa_reference_buffer_object(ctx,
417 &obj->Buffers[index],
420 obj->BufferNames[index] = bufObj->Name;
422 obj->Offset[index] = offset;
423 obj->Size[index] = size;
428 * Specify a buffer object to receive vertex shader results. Plus,
429 * specify the starting offset to place the results, and max size.
432 _mesa_BindBufferRange(GLenum target, GLuint index,
433 GLuint buffer, GLintptr offset, GLsizeiptr size)
435 struct gl_transform_feedback_object *obj;
436 struct gl_buffer_object *bufObj;
437 GET_CURRENT_CONTEXT(ctx);
439 if (target != GL_TRANSFORM_FEEDBACK_BUFFER) {
440 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferRange(target)");
444 obj = ctx->TransformFeedback.CurrentObject;
447 _mesa_error(ctx, GL_INVALID_OPERATION,
448 "glBindBufferRange(transform feedback active)");
452 if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) {
453 _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index);
457 if ((size <= 0) || (size & 0x3)) {
458 /* must be positive and multiple of four */
459 _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(size%d)", (int) size);
464 /* must be multiple of four */
465 _mesa_error(ctx, GL_INVALID_VALUE,
466 "glBindBufferRange(offset=%d)", (int) offset);
470 bufObj = _mesa_lookup_bufferobj(ctx, buffer);
472 _mesa_error(ctx, GL_INVALID_OPERATION,
473 "glBindBufferRange(invalid buffer=%u)", buffer);
477 if (offset + size >= bufObj->Size) {
478 _mesa_error(ctx, GL_INVALID_VALUE,
479 "glBindBufferRange(offset + size %d > buffer size %d)",
480 (int) (offset + size), (int) (bufObj->Size));
484 bind_buffer_range(ctx, index, bufObj, offset, size);
489 * Specify a buffer object to receive vertex shader results.
490 * As above, but start at offset = 0.
493 _mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer)
495 struct gl_transform_feedback_object *obj;
496 struct gl_buffer_object *bufObj;
498 GET_CURRENT_CONTEXT(ctx);
500 if (target != GL_TRANSFORM_FEEDBACK_BUFFER) {
501 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferBase(target)");
505 obj = ctx->TransformFeedback.CurrentObject;
508 _mesa_error(ctx, GL_INVALID_OPERATION,
509 "glBindBufferBase(transform feedback active)");
513 if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) {
514 _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index);
518 bufObj = _mesa_lookup_bufferobj(ctx, buffer);
520 _mesa_error(ctx, GL_INVALID_OPERATION,
521 "glBindBufferBase(invalid buffer=%u)", buffer);
525 /* default size is the buffer size rounded down to nearest
528 size = bufObj->Size & ~0x3;
530 bind_buffer_range(ctx, index, bufObj, 0, size);
535 * Specify a buffer object to receive vertex shader results, plus the
536 * offset in the buffer to start placing results.
537 * This function is part of GL_EXT_transform_feedback, but not GL3.
540 _mesa_BindBufferOffsetEXT(GLenum target, GLuint index, GLuint buffer,
543 struct gl_transform_feedback_object *obj;
544 struct gl_buffer_object *bufObj;
545 GET_CURRENT_CONTEXT(ctx);
548 if (target != GL_TRANSFORM_FEEDBACK_BUFFER) {
549 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferOffsetEXT(target)");
553 obj = ctx->TransformFeedback.CurrentObject;
556 _mesa_error(ctx, GL_INVALID_OPERATION,
557 "glBindBufferOffsetEXT(transform feedback active)");
561 if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) {
562 _mesa_error(ctx, GL_INVALID_VALUE,
563 "glBindBufferOffsetEXT(index=%d)", index);
567 bufObj = _mesa_lookup_bufferobj(ctx, buffer);
569 _mesa_error(ctx, GL_INVALID_OPERATION,
570 "glBindBufferOffsetEXT(invalid buffer=%u)", buffer);
574 /* default size is the buffer size rounded down to nearest
577 size = (bufObj->Size - offset) & ~0x3;
579 bind_buffer_range(ctx, index, bufObj, offset, size);
584 * This function specifies the vertex shader outputs to be written
585 * to the feedback buffer(s), and in what order.
588 _mesa_TransformFeedbackVaryings(GLuint program, GLsizei count,
589 const GLchar **varyings, GLenum bufferMode)
591 struct gl_shader_program *shProg;
593 GET_CURRENT_CONTEXT(ctx);
595 switch (bufferMode) {
596 case GL_INTERLEAVED_ATTRIBS:
598 case GL_SEPARATE_ATTRIBS:
601 _mesa_error(ctx, GL_INVALID_ENUM,
602 "glTransformFeedbackVaryings(bufferMode)");
606 if (count < 0 || count > ctx->Const.MaxTransformFeedbackSeparateAttribs) {
607 _mesa_error(ctx, GL_INVALID_VALUE,
608 "glTransformFeedbackVaryings(count=%d)", count);
612 shProg = _mesa_lookup_shader_program(ctx, program);
614 _mesa_error(ctx, GL_INVALID_VALUE,
615 "glTransformFeedbackVaryings(program=%u)", program);
619 /* free existing varyings, if any */
620 for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) {
621 free(shProg->TransformFeedback.VaryingNames[i]);
623 free(shProg->TransformFeedback.VaryingNames);
625 /* allocate new memory for varying names */
626 shProg->TransformFeedback.VaryingNames =
627 (GLchar **) malloc(count * sizeof(GLchar *));
629 if (!shProg->TransformFeedback.VaryingNames) {
630 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTransformFeedbackVaryings()");
634 /* Save the new names and the count */
635 for (i = 0; i < (GLuint) count; i++) {
636 shProg->TransformFeedback.VaryingNames[i] = _mesa_strdup(varyings[i]);
638 shProg->TransformFeedback.NumVarying = count;
640 shProg->TransformFeedback.BufferMode = bufferMode;
642 /* The varyings won't be used until shader link time */
647 * Get info about the vertex shader's outputs which are to be written
648 * to the feedback buffer(s).
651 _mesa_GetTransformFeedbackVarying(GLuint program, GLuint index,
652 GLsizei bufSize, GLsizei *length,
653 GLsizei *size, GLenum *type, GLchar *name)
655 const struct gl_shader_program *shProg;
656 const GLchar *varyingName;
658 GET_CURRENT_CONTEXT(ctx);
660 shProg = _mesa_lookup_shader_program(ctx, program);
662 _mesa_error(ctx, GL_INVALID_VALUE,
663 "glGetTransformFeedbackVaryings(program=%u)", program);
667 if (index >= shProg->TransformFeedback.NumVarying) {
668 _mesa_error(ctx, GL_INVALID_VALUE,
669 "glGetTransformFeedbackVaryings(index=%u)", index);
673 varyingName = shProg->TransformFeedback.VaryingNames[index];
675 v = _mesa_lookup_parameter_index(shProg->Varying, -1, varyingName);
677 struct gl_program_parameter *param = &shProg->Varying->Parameters[v];
679 /* return the varying's name and length */
680 _mesa_copy_string(name, bufSize, length, varyingName);
682 /* return the datatype and value's size (in datatype units) */
684 *type = param->DataType;
701 static struct gl_transform_feedback_object *
702 lookup_transform_feedback_object(struct gl_context *ctx, GLuint name)
705 return ctx->TransformFeedback.DefaultObject;
708 return (struct gl_transform_feedback_object *)
709 _mesa_HashLookup(ctx->TransformFeedback.Objects, name);
714 * Create new transform feedback objects. Transform feedback objects
715 * encapsulate the state related to transform feedback to allow quickly
716 * switching state (and drawing the results, below).
717 * Part of GL_ARB_transform_feedback2.
720 _mesa_GenTransformFeedbacks(GLsizei n, GLuint *names)
723 GET_CURRENT_CONTEXT(ctx);
725 ASSERT_OUTSIDE_BEGIN_END(ctx);
728 _mesa_error(ctx, GL_INVALID_VALUE, "glGenTransformFeedbacks(n < 0)");
735 /* we don't need contiguous IDs, but this might be faster */
736 first = _mesa_HashFindFreeKeyBlock(ctx->TransformFeedback.Objects, n);
739 for (i = 0; i < n; i++) {
740 struct gl_transform_feedback_object *obj
741 = ctx->Driver.NewTransformFeedback(ctx, first + i);
743 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTransformFeedbacks");
746 names[i] = first + i;
747 _mesa_HashInsert(ctx->TransformFeedback.Objects, first + i, obj);
751 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTransformFeedbacks");
757 * Is the given ID a transform feedback object?
758 * Part of GL_ARB_transform_feedback2.
761 _mesa_IsTransformFeedback(GLuint name)
763 GET_CURRENT_CONTEXT(ctx);
765 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
767 if (name && lookup_transform_feedback_object(ctx, name))
775 * Bind the given transform feedback object.
776 * Part of GL_ARB_transform_feedback2.
779 _mesa_BindTransformFeedback(GLenum target, GLuint name)
781 struct gl_transform_feedback_object *obj;
782 GET_CURRENT_CONTEXT(ctx);
784 if (target != GL_TRANSFORM_FEEDBACK) {
785 _mesa_error(ctx, GL_INVALID_ENUM, "glBindTransformFeedback(target)");
789 if (ctx->TransformFeedback.CurrentObject->Active &&
790 !ctx->TransformFeedback.CurrentObject->Paused) {
791 _mesa_error(ctx, GL_INVALID_OPERATION,
792 "glBindTransformFeedback(transform is active, or not paused)");
796 obj = lookup_transform_feedback_object(ctx, name);
798 _mesa_error(ctx, GL_INVALID_OPERATION,
799 "glBindTransformFeedback(name=%u)", name);
803 reference_transform_feedback_object(&ctx->TransformFeedback.CurrentObject,
809 * Delete the given transform feedback objects.
810 * Part of GL_ARB_transform_feedback2.
813 _mesa_DeleteTransformFeedbacks(GLsizei n, const GLuint *names)
816 GET_CURRENT_CONTEXT(ctx);
818 ASSERT_OUTSIDE_BEGIN_END(ctx);
821 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteTransformFeedbacks(n < 0)");
828 for (i = 0; i < n; i++) {
830 struct gl_transform_feedback_object *obj
831 = lookup_transform_feedback_object(ctx, names[i]);
834 _mesa_error(ctx, GL_INVALID_OPERATION,
835 "glDeleteTransformFeedbacks(object %u is active)",
839 _mesa_HashRemove(ctx->TransformFeedback.Objects, names[i]);
840 /* unref, but object may not be deleted until later */
841 reference_transform_feedback_object(&obj, NULL);
849 * Pause transform feedback.
850 * Part of GL_ARB_transform_feedback2.
853 _mesa_PauseTransformFeedback(void)
855 struct gl_transform_feedback_object *obj;
856 GET_CURRENT_CONTEXT(ctx);
858 obj = ctx->TransformFeedback.CurrentObject;
860 if (!obj->Active || obj->Paused) {
861 _mesa_error(ctx, GL_INVALID_OPERATION,
862 "glPauseTransformFeedback(feedback not active or already paused)");
866 obj->Paused = GL_TRUE;
868 assert(ctx->Driver.PauseTransformFeedback);
869 ctx->Driver.PauseTransformFeedback(ctx, obj);
874 * Resume transform feedback.
875 * Part of GL_ARB_transform_feedback2.
878 _mesa_ResumeTransformFeedback(void)
880 struct gl_transform_feedback_object *obj;
881 GET_CURRENT_CONTEXT(ctx);
883 obj = ctx->TransformFeedback.CurrentObject;
885 if (!obj->Active || !obj->Paused) {
886 _mesa_error(ctx, GL_INVALID_OPERATION,
887 "glResumeTransformFeedback(feedback not active or not paused)");
891 obj->Paused = GL_FALSE;
893 assert(ctx->Driver.ResumeTransformFeedback);
894 ctx->Driver.ResumeTransformFeedback(ctx, obj);
899 * Draw the vertex data in a transform feedback object.
900 * \param mode GL_POINTS, GL_LINES, GL_TRIANGLE_STRIP, etc.
901 * \param name the transform feedback object
902 * The number of vertices comes from the transform feedback object.
903 * User still has to setup of the vertex attribute info with
904 * glVertexPointer, glColorPointer, etc.
905 * Part of GL_ARB_transform_feedback2.
908 _mesa_DrawTransformFeedback(GLenum mode, GLuint name)
910 GET_CURRENT_CONTEXT(ctx);
911 struct gl_transform_feedback_object *obj =
912 lookup_transform_feedback_object(ctx, name);
914 if (mode > GL_POLYGON) {
915 _mesa_error(ctx, GL_INVALID_ENUM,
916 "glDrawTransformFeedback(mode=0x%x)", mode);
920 _mesa_error(ctx, GL_INVALID_VALUE,
921 "glDrawTransformFeedback(name = %u)", name);
925 /* XXX check if EndTransformFeedback has never been called while
926 * the object was bound
929 assert(ctx->Driver.DrawTransformFeedback);
930 ctx->Driver.DrawTransformFeedback(ctx, mode, obj);
934 #endif /* FEATURE_EXT_transform_feedback */