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 "transformfeedback.h"
38 #include "shaderapi.h"
39 #include "shaderobj.h"
40 #include "main/dispatch.h"
42 #include "program/prog_parameter.h"
43 //#include "program/shader_api.h"
46 #if FEATURE_EXT_transform_feedback
50 * Do reference counting of transform feedback buffers.
53 reference_transform_feedback_object(struct gl_transform_feedback_object
**ptr
,
54 struct gl_transform_feedback_object
*obj
)
60 /* Unreference the old object */
61 struct gl_transform_feedback_object
*oldObj
= *ptr
;
63 ASSERT(oldObj
->RefCount
> 0);
66 if (oldObj
->RefCount
== 0) {
67 GET_CURRENT_CONTEXT(ctx
);
69 ctx
->Driver
.DeleteTransformFeedback(ctx
, oldObj
);
77 /* reference new object */
78 if (obj
->RefCount
== 0) {
79 _mesa_problem(NULL
, "referencing deleted transform feedback object");
91 * Check if the given primitive mode (as in glBegin(mode)) is compatible
92 * with the current transform feedback mode (if it's enabled).
93 * This is to be called from glBegin(), glDrawArrays(), glDrawElements(), etc.
95 * \return GL_TRUE if the mode is OK, GL_FALSE otherwise.
98 _mesa_validate_primitive_mode(GLcontext
*ctx
, GLenum mode
)
100 if (ctx
->TransformFeedback
.CurrentObject
->Active
) {
103 return ctx
->TransformFeedback
.Mode
== GL_POINTS
;
107 return ctx
->TransformFeedback
.Mode
== GL_LINES
;
109 return ctx
->TransformFeedback
.Mode
== GL_TRIANGLES
;
117 * Check that all the buffer objects currently bound for transform
118 * feedback actually exist. Raise a GL_INVALID_OPERATION error if
119 * any buffers are missing.
120 * \return GL_TRUE for success, GL_FALSE if error
123 _mesa_validate_transform_feedback_buffers(GLcontext
*ctx
)
132 * Per-context init for transform feedback.
135 _mesa_init_transform_feedback(GLcontext
*ctx
)
137 /* core mesa expects this, even a dummy one, to be available */
138 ASSERT(ctx
->Driver
.NewTransformFeedback
);
140 ctx
->TransformFeedback
.DefaultObject
=
141 ctx
->Driver
.NewTransformFeedback(ctx
, 0);
143 assert(ctx
->TransformFeedback
.DefaultObject
->RefCount
== 1);
145 reference_transform_feedback_object(&ctx
->TransformFeedback
.CurrentObject
,
146 ctx
->TransformFeedback
.DefaultObject
);
148 assert(ctx
->TransformFeedback
.DefaultObject
->RefCount
== 2);
150 ctx
->TransformFeedback
.Objects
= _mesa_NewHashTable();
152 _mesa_reference_buffer_object(ctx
,
153 &ctx
->TransformFeedback
.CurrentBuffer
,
154 ctx
->Shared
->NullBufferObj
);
160 * Callback for _mesa_HashDeleteAll().
163 delete_cb(GLuint key
, void *data
, void *userData
)
165 GLcontext
*ctx
= (GLcontext
*) userData
;
166 struct gl_transform_feedback_object
*obj
=
167 (struct gl_transform_feedback_object
*) data
;
169 ctx
->Driver
.DeleteTransformFeedback(ctx
, obj
);
174 * Per-context free/clean-up for transform feedback.
177 _mesa_free_transform_feedback(GLcontext
*ctx
)
179 /* core mesa expects this, even a dummy one, to be available */
180 ASSERT(ctx
->Driver
.NewTransformFeedback
);
182 _mesa_reference_buffer_object(ctx
,
183 &ctx
->TransformFeedback
.CurrentBuffer
,
186 /* Delete all feedback objects */
187 _mesa_HashDeleteAll(ctx
->TransformFeedback
.Objects
, delete_cb
, ctx
);
188 _mesa_DeleteHashTable(ctx
->TransformFeedback
.Objects
);
190 /* Delete the default feedback object */
191 assert(ctx
->Driver
.DeleteTransformFeedback
);
192 ctx
->Driver
.DeleteTransformFeedback(ctx
,
193 ctx
->TransformFeedback
.DefaultObject
);
195 ctx
->TransformFeedback
.CurrentObject
= NULL
;
199 #else /* FEATURE_EXT_transform_feedback */
201 /* forward declarations */
202 static struct gl_transform_feedback_object
*
203 new_transform_feedback(GLcontext
*ctx
, GLuint name
);
206 delete_transform_feedback(GLcontext
*ctx
,
207 struct gl_transform_feedback_object
*obj
);
209 /* dummy per-context init/clean-up for transform feedback */
211 _mesa_init_transform_feedback(GLcontext
*ctx
)
213 ctx
->TransformFeedback
.DefaultObject
= new_transform_feedback(ctx
, 0);
214 ctx
->TransformFeedback
.CurrentObject
= ctx
->TransformFeedback
.DefaultObject
;
215 _mesa_reference_buffer_object(ctx
,
216 &ctx
->TransformFeedback
.CurrentBuffer
,
217 ctx
->Shared
->NullBufferObj
);
221 _mesa_free_transform_feedback(GLcontext
*ctx
)
223 _mesa_reference_buffer_object(ctx
,
224 &ctx
->TransformFeedback
.CurrentBuffer
,
226 ctx
->TransformFeedback
.CurrentObject
= NULL
;
227 delete_transform_feedback(ctx
, ctx
->TransformFeedback
.DefaultObject
);
230 #endif /* FEATURE_EXT_transform_feedback */
233 /** Default fallback for ctx->Driver.NewTransformFeedback() */
234 static struct gl_transform_feedback_object
*
235 new_transform_feedback(GLcontext
*ctx
, GLuint name
)
237 struct gl_transform_feedback_object
*obj
;
238 obj
= CALLOC_STRUCT(gl_transform_feedback_object
);
246 /** Default fallback for ctx->Driver.DeleteTransformFeedback() */
248 delete_transform_feedback(GLcontext
*ctx
,
249 struct gl_transform_feedback_object
*obj
)
253 for (i
= 0; i
< Elements(obj
->Buffers
); i
++) {
254 _mesa_reference_buffer_object(ctx
, &obj
->Buffers
[i
], NULL
);
261 #if FEATURE_EXT_transform_feedback
264 /** Default fallback for ctx->Driver.BeginTransformFeedback() */
266 begin_transform_feedback(GLcontext
*ctx
, GLenum mode
,
267 struct gl_transform_feedback_object
*obj
)
272 /** Default fallback for ctx->Driver.EndTransformFeedback() */
274 end_transform_feedback(GLcontext
*ctx
,
275 struct gl_transform_feedback_object
*obj
)
280 /** Default fallback for ctx->Driver.PauseTransformFeedback() */
282 pause_transform_feedback(GLcontext
*ctx
,
283 struct gl_transform_feedback_object
*obj
)
288 /** Default fallback for ctx->Driver.ResumeTransformFeedback() */
290 resume_transform_feedback(GLcontext
*ctx
,
291 struct gl_transform_feedback_object
*obj
)
296 /** Default fallback for ctx->Driver.DrawTransformFeedback() */
298 draw_transform_feedback(GLcontext
*ctx
, GLenum mode
,
299 struct gl_transform_feedback_object
*obj
)
303 * Get number of vertices in obj's feedback buffer.
304 * Call ctx->Exec.DrawArrays(mode, 0, count);
310 * Plug in default device driver functions for transform feedback.
311 * Most drivers will override some/all of these.
314 _mesa_init_transform_feedback_functions(struct dd_function_table
*driver
)
316 driver
->NewTransformFeedback
= new_transform_feedback
;
317 driver
->DeleteTransformFeedback
= delete_transform_feedback
;
318 driver
->BeginTransformFeedback
= begin_transform_feedback
;
319 driver
->EndTransformFeedback
= end_transform_feedback
;
320 driver
->PauseTransformFeedback
= pause_transform_feedback
;
321 driver
->ResumeTransformFeedback
= resume_transform_feedback
;
322 driver
->DrawTransformFeedback
= draw_transform_feedback
;
327 _mesa_init_transform_feedback_dispatch(struct _glapi_table
*disp
)
329 SET_BeginTransformFeedbackEXT(disp
, _mesa_BeginTransformFeedback
);
330 SET_EndTransformFeedbackEXT(disp
, _mesa_EndTransformFeedback
);
331 SET_BindBufferRangeEXT(disp
, _mesa_BindBufferRange
);
332 SET_BindBufferBaseEXT(disp
, _mesa_BindBufferBase
);
333 SET_BindBufferOffsetEXT(disp
, _mesa_BindBufferOffsetEXT
);
334 SET_TransformFeedbackVaryingsEXT(disp
, _mesa_TransformFeedbackVaryings
);
335 SET_GetTransformFeedbackVaryingEXT(disp
, _mesa_GetTransformFeedbackVarying
);
340 ** Begin API functions
345 _mesa_BeginTransformFeedback(GLenum mode
)
347 struct gl_transform_feedback_object
*obj
;
348 GET_CURRENT_CONTEXT(ctx
);
350 obj
= ctx
->TransformFeedback
.CurrentObject
;
359 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBeginTransformFeedback(mode)");
364 _mesa_error(ctx
, GL_INVALID_OPERATION
,
365 "glBeginTransformFeedback(already active)");
369 obj
->Active
= GL_TRUE
;
370 ctx
->TransformFeedback
.Mode
= mode
;
372 assert(ctx
->Driver
.BeginTransformFeedback
);
373 ctx
->Driver
.BeginTransformFeedback(ctx
, mode
, obj
);
378 _mesa_EndTransformFeedback(void)
380 struct gl_transform_feedback_object
*obj
;
381 GET_CURRENT_CONTEXT(ctx
);
383 obj
= ctx
->TransformFeedback
.CurrentObject
;
386 _mesa_error(ctx
, GL_INVALID_OPERATION
,
387 "glEndTransformFeedback(not active)");
391 ctx
->TransformFeedback
.CurrentObject
->Active
= GL_FALSE
;
393 assert(ctx
->Driver
.EndTransformFeedback
);
394 ctx
->Driver
.EndTransformFeedback(ctx
, obj
);
399 * Helper used by BindBufferRange() and BindBufferBase().
402 bind_buffer_range(GLcontext
*ctx
, GLuint index
,
403 struct gl_buffer_object
*bufObj
,
404 GLintptr offset
, GLsizeiptr size
)
406 struct gl_transform_feedback_object
*obj
=
407 ctx
->TransformFeedback
.CurrentObject
;
409 /* The general binding point */
410 _mesa_reference_buffer_object(ctx
,
411 &ctx
->TransformFeedback
.CurrentBuffer
,
414 /* The per-attribute binding point */
415 _mesa_reference_buffer_object(ctx
,
416 &obj
->Buffers
[index
],
419 obj
->BufferNames
[index
] = bufObj
->Name
;
421 obj
->Offset
[index
] = offset
;
422 obj
->Size
[index
] = size
;
427 * Specify a buffer object to receive vertex shader results. Plus,
428 * specify the starting offset to place the results, and max size.
431 _mesa_BindBufferRange(GLenum target
, GLuint index
,
432 GLuint buffer
, GLintptr offset
, GLsizeiptr size
)
434 struct gl_transform_feedback_object
*obj
;
435 struct gl_buffer_object
*bufObj
;
436 GET_CURRENT_CONTEXT(ctx
);
438 if (target
!= GL_TRANSFORM_FEEDBACK_BUFFER
) {
439 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBindBufferRange(target)");
443 obj
= ctx
->TransformFeedback
.CurrentObject
;
446 _mesa_error(ctx
, GL_INVALID_OPERATION
,
447 "glBindBufferRange(transform feedback active)");
451 if (index
>= ctx
->Const
.MaxTransformFeedbackSeparateAttribs
) {
452 _mesa_error(ctx
, GL_INVALID_VALUE
, "glBindBufferRange(index=%d)", index
);
456 if ((size
<= 0) || (size
& 0x3)) {
457 /* must be positive and multiple of four */
458 _mesa_error(ctx
, GL_INVALID_VALUE
, "glBindBufferRange(size%d)", (int) size
);
463 /* must be multiple of four */
464 _mesa_error(ctx
, GL_INVALID_VALUE
,
465 "glBindBufferRange(offset=%d)", (int) offset
);
469 bufObj
= _mesa_lookup_bufferobj(ctx
, buffer
);
471 _mesa_error(ctx
, GL_INVALID_OPERATION
,
472 "glBindBufferRange(invalid buffer=%u)", buffer
);
476 if (offset
+ size
>= bufObj
->Size
) {
477 _mesa_error(ctx
, GL_INVALID_VALUE
,
478 "glBindBufferRange(offset + size %d > buffer size %d)",
479 (int) (offset
+ size
), (int) (bufObj
->Size
));
483 bind_buffer_range(ctx
, index
, bufObj
, offset
, size
);
488 * Specify a buffer object to receive vertex shader results.
489 * As above, but start at offset = 0.
492 _mesa_BindBufferBase(GLenum target
, GLuint index
, GLuint buffer
)
494 struct gl_transform_feedback_object
*obj
;
495 struct gl_buffer_object
*bufObj
;
497 GET_CURRENT_CONTEXT(ctx
);
499 if (target
!= GL_TRANSFORM_FEEDBACK_BUFFER
) {
500 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBindBufferBase(target)");
504 obj
= ctx
->TransformFeedback
.CurrentObject
;
507 _mesa_error(ctx
, GL_INVALID_OPERATION
,
508 "glBindBufferRange(transform feedback active)");
512 if (index
>= ctx
->Const
.MaxTransformFeedbackSeparateAttribs
) {
513 _mesa_error(ctx
, GL_INVALID_VALUE
, "glBindBufferBase(index=%d)", index
);
517 bufObj
= _mesa_lookup_bufferobj(ctx
, buffer
);
519 _mesa_error(ctx
, GL_INVALID_OPERATION
,
520 "glBindBufferBase(invalid buffer=%u)", buffer
);
524 /* default size is the buffer size rounded down to nearest
527 size
= bufObj
->Size
& ~0x3;
529 bind_buffer_range(ctx
, index
, bufObj
, 0, size
);
534 * Specify a buffer object to receive vertex shader results, plus the
535 * offset in the buffer to start placing results.
536 * This function is part of GL_EXT_transform_feedback, but not GL3.
539 _mesa_BindBufferOffsetEXT(GLenum target
, GLuint index
, GLuint buffer
,
542 struct gl_transform_feedback_object
*obj
;
543 struct gl_buffer_object
*bufObj
;
544 GET_CURRENT_CONTEXT(ctx
);
547 if (target
!= GL_TRANSFORM_FEEDBACK_BUFFER
) {
548 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBindBufferOffsetEXT(target)");
552 obj
= ctx
->TransformFeedback
.CurrentObject
;
555 _mesa_error(ctx
, GL_INVALID_OPERATION
,
556 "glBindBufferRange(transform feedback active)");
560 if (index
>= ctx
->Const
.MaxTransformFeedbackSeparateAttribs
) {
561 _mesa_error(ctx
, GL_INVALID_VALUE
,
562 "glBindBufferOffsetEXT(index=%d)", index
);
566 bufObj
= _mesa_lookup_bufferobj(ctx
, buffer
);
568 _mesa_error(ctx
, GL_INVALID_OPERATION
,
569 "glBindBufferOffsetEXT(invalid buffer=%u)", buffer
);
573 /* default size is the buffer size rounded down to nearest
576 size
= (bufObj
->Size
- offset
) & ~0x3;
578 bind_buffer_range(ctx
, index
, bufObj
, offset
, size
);
583 * This function specifies the vertex shader outputs to be written
584 * to the feedback buffer(s), and in what order.
587 _mesa_TransformFeedbackVaryings(GLuint program
, GLsizei count
,
588 const GLchar
**varyings
, GLenum bufferMode
)
590 struct gl_shader_program
*shProg
;
592 GET_CURRENT_CONTEXT(ctx
);
594 switch (bufferMode
) {
595 case GL_INTERLEAVED_ATTRIBS
:
597 case GL_SEPARATE_ATTRIBS
:
600 _mesa_error(ctx
, GL_INVALID_ENUM
,
601 "glTransformFeedbackVaryings(bufferMode)");
605 if (count
< 0 || count
> ctx
->Const
.MaxTransformFeedbackSeparateAttribs
) {
606 _mesa_error(ctx
, GL_INVALID_VALUE
,
607 "glTransformFeedbackVaryings(count=%d)", count
);
611 shProg
= _mesa_lookup_shader_program(ctx
, program
);
613 _mesa_error(ctx
, GL_INVALID_VALUE
,
614 "glTransformFeedbackVaryings(program=%u)", program
);
618 /* free existing varyings, if any */
619 for (i
= 0; i
< shProg
->TransformFeedback
.NumVarying
; i
++) {
620 free(shProg
->TransformFeedback
.VaryingNames
[i
]);
622 free(shProg
->TransformFeedback
.VaryingNames
);
624 /* allocate new memory for varying names */
625 shProg
->TransformFeedback
.VaryingNames
=
626 (GLchar
**) malloc(count
* sizeof(GLchar
*));
628 if (!shProg
->TransformFeedback
.VaryingNames
) {
629 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glTransformFeedbackVaryings()");
633 /* Save the new names and the count */
634 for (i
= 0; i
< (GLuint
) count
; i
++) {
635 shProg
->TransformFeedback
.VaryingNames
[i
] = _mesa_strdup(varyings
[i
]);
637 shProg
->TransformFeedback
.NumVarying
= count
;
639 shProg
->TransformFeedback
.BufferMode
= bufferMode
;
641 /* The varyings won't be used until shader link time */
646 * Get info about the vertex shader's outputs which are to be written
647 * to the feedback buffer(s).
650 _mesa_GetTransformFeedbackVarying(GLuint program
, GLuint index
,
651 GLsizei bufSize
, GLsizei
*length
,
652 GLsizei
*size
, GLenum
*type
, GLchar
*name
)
654 const struct gl_shader_program
*shProg
;
655 const GLchar
*varyingName
;
657 GET_CURRENT_CONTEXT(ctx
);
659 shProg
= _mesa_lookup_shader_program(ctx
, program
);
661 _mesa_error(ctx
, GL_INVALID_VALUE
,
662 "glGetTransformFeedbackVaryings(program=%u)", program
);
666 if (index
>= shProg
->TransformFeedback
.NumVarying
) {
667 _mesa_error(ctx
, GL_INVALID_VALUE
,
668 "glGetTransformFeedbackVaryings(index=%u)", index
);
672 varyingName
= shProg
->TransformFeedback
.VaryingNames
[index
];
674 v
= _mesa_lookup_parameter_index(shProg
->Varying
, -1, varyingName
);
676 struct gl_program_parameter
*param
= &shProg
->Varying
->Parameters
[v
];
678 /* return the varying's name and length */
679 _mesa_copy_string(name
, bufSize
, length
, varyingName
);
681 /* return the datatype and value's size (in datatype units) */
683 *type
= param
->DataType
;
700 static struct gl_transform_feedback_object
*
701 lookup_transform_feedback_object(GLcontext
*ctx
, GLuint name
)
704 return ctx
->TransformFeedback
.DefaultObject
;
707 return (struct gl_transform_feedback_object
*)
708 _mesa_HashLookup(ctx
->TransformFeedback
.Objects
, name
);
713 * Create new transform feedback objects. Transform feedback objects
714 * encapsulate the state related to transform feedback to allow quickly
715 * switching state (and drawing the results, below).
716 * Part of GL_ARB_transform_feedback2.
719 _mesa_GenTransformFeedbacks(GLsizei n
, GLuint
*names
)
722 GET_CURRENT_CONTEXT(ctx
);
724 ASSERT_OUTSIDE_BEGIN_END(ctx
);
727 _mesa_error(ctx
, GL_INVALID_VALUE
, "glGenTransformFeedbacks(n < 0)");
734 /* we don't need contiguous IDs, but this might be faster */
735 first
= _mesa_HashFindFreeKeyBlock(ctx
->TransformFeedback
.Objects
, n
);
738 for (i
= 0; i
< n
; i
++) {
739 struct gl_transform_feedback_object
*obj
740 = ctx
->Driver
.NewTransformFeedback(ctx
, first
+ i
);
742 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGenTransformFeedbacks");
745 names
[i
] = first
+ i
;
746 _mesa_HashInsert(ctx
->TransformFeedback
.Objects
, first
+ i
, obj
);
750 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGenTransformFeedbacks");
756 * Is the given ID a transform feedback object?
757 * Part of GL_ARB_transform_feedback2.
760 _mesa_IsTransformFeedback(GLuint name
)
762 GET_CURRENT_CONTEXT(ctx
);
764 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, GL_FALSE
);
766 if (name
&& lookup_transform_feedback_object(ctx
, name
))
774 * Bind the given transform feedback object.
775 * Part of GL_ARB_transform_feedback2.
778 _mesa_BindTransformFeedback(GLenum target
, GLuint name
)
780 struct gl_transform_feedback_object
*obj
;
781 GET_CURRENT_CONTEXT(ctx
);
783 if (target
!= GL_TRANSFORM_FEEDBACK
) {
784 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBindTransformFeedback(target)");
788 if (ctx
->TransformFeedback
.CurrentObject
->Active
&&
789 !ctx
->TransformFeedback
.CurrentObject
->Paused
) {
790 _mesa_error(ctx
, GL_INVALID_OPERATION
,
791 "glBindTransformFeedback(transform is active, or not paused)");
795 obj
= lookup_transform_feedback_object(ctx
, name
);
797 _mesa_error(ctx
, GL_INVALID_OPERATION
,
798 "glBindTransformFeedback(name=%u)", name
);
802 reference_transform_feedback_object(&ctx
->TransformFeedback
.CurrentObject
,
808 * Delete the given transform feedback objects.
809 * Part of GL_ARB_transform_feedback2.
812 _mesa_DeleteTransformFeedbacks(GLsizei n
, const GLuint
*names
)
815 GET_CURRENT_CONTEXT(ctx
);
817 ASSERT_OUTSIDE_BEGIN_END(ctx
);
820 _mesa_error(ctx
, GL_INVALID_VALUE
, "glDeleteTransformFeedbacks(n < 0)");
827 for (i
= 0; i
< n
; i
++) {
829 struct gl_transform_feedback_object
*obj
830 = lookup_transform_feedback_object(ctx
, names
[i
]);
833 _mesa_error(ctx
, GL_INVALID_OPERATION
,
834 "glDeleteTransformFeedbacks(object %u is active)",
838 _mesa_HashRemove(ctx
->TransformFeedback
.Objects
, names
[i
]);
839 /* unref, but object may not be deleted until later */
840 reference_transform_feedback_object(&obj
, NULL
);
848 * Pause transform feedback.
849 * Part of GL_ARB_transform_feedback2.
852 _mesa_PauseTransformFeedback(void)
854 struct gl_transform_feedback_object
*obj
;
855 GET_CURRENT_CONTEXT(ctx
);
857 obj
= ctx
->TransformFeedback
.CurrentObject
;
859 if (!obj
->Active
|| obj
->Paused
) {
860 _mesa_error(ctx
, GL_INVALID_OPERATION
,
861 "glPauseTransformFeedback(feedback not active or already paused)");
865 obj
->Paused
= GL_TRUE
;
867 assert(ctx
->Driver
.PauseTransformFeedback
);
868 ctx
->Driver
.PauseTransformFeedback(ctx
, obj
);
873 * Resume transform feedback.
874 * Part of GL_ARB_transform_feedback2.
877 _mesa_ResumeTransformFeedback(void)
879 struct gl_transform_feedback_object
*obj
;
880 GET_CURRENT_CONTEXT(ctx
);
882 obj
= ctx
->TransformFeedback
.CurrentObject
;
884 if (!obj
->Active
|| !obj
->Paused
) {
885 _mesa_error(ctx
, GL_INVALID_OPERATION
,
886 "glPauseTransformFeedback(feedback not active or not paused)");
890 obj
->Paused
= GL_FALSE
;
892 assert(ctx
->Driver
.ResumeTransformFeedback
);
893 ctx
->Driver
.ResumeTransformFeedback(ctx
, obj
);
898 * Draw the vertex data in a transform feedback object.
899 * \param mode GL_POINTS, GL_LINES, GL_TRIANGLE_STRIP, etc.
900 * \param name the transform feedback object
901 * The number of vertices comes from the transform feedback object.
902 * User still has to setup of the vertex attribute info with
903 * glVertexPointer, glColorPointer, etc.
904 * Part of GL_ARB_transform_feedback2.
907 _mesa_DrawTransformFeedback(GLenum mode
, GLuint name
)
909 GET_CURRENT_CONTEXT(ctx
);
910 struct gl_transform_feedback_object
*obj
=
911 lookup_transform_feedback_object(ctx
, name
);
913 if (mode
> GL_POLYGON
) {
914 _mesa_error(ctx
, GL_INVALID_ENUM
,
915 "glDrawTransformFeedback(mode=0x%x)", mode
);
919 _mesa_error(ctx
, GL_INVALID_VALUE
,
920 "glDrawTransformFeedback(name = %u)", name
);
924 /* XXX check if EndTransformFeedback has never been called while
925 * the object was bound
928 assert(ctx
->Driver
.DrawTransformFeedback
);
929 ctx
->Driver
.DrawTransformFeedback(ctx
, mode
, obj
);
938 GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED
939 GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE
940 GL_TRANSFORM_FEEDBACK_BINDING
944 #endif /* FEATURE_EXT_transform_feedback */