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 */