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"
48 * Do reference counting of transform feedback buffers.
51 reference_transform_feedback_object(struct gl_transform_feedback_object
**ptr
,
52 struct gl_transform_feedback_object
*obj
)
58 /* Unreference the old object */
59 struct gl_transform_feedback_object
*oldObj
= *ptr
;
61 ASSERT(oldObj
->RefCount
> 0);
64 if (oldObj
->RefCount
== 0) {
65 GET_CURRENT_CONTEXT(ctx
);
67 ctx
->Driver
.DeleteTransformFeedback(ctx
, oldObj
);
75 /* reference new object */
76 if (obj
->RefCount
== 0) {
77 _mesa_problem(NULL
, "referencing deleted transform feedback object");
89 * Check that all the buffer objects currently bound for transform
90 * feedback actually exist. Raise a GL_INVALID_OPERATION error if
91 * any buffers are missing.
92 * \return GL_TRUE for success, GL_FALSE if error
95 _mesa_validate_transform_feedback_buffers(struct gl_context
*ctx
)
104 * Per-context init for transform feedback.
107 _mesa_init_transform_feedback(struct gl_context
*ctx
)
109 /* core mesa expects this, even a dummy one, to be available */
110 ASSERT(ctx
->Driver
.NewTransformFeedback
);
112 ctx
->TransformFeedback
.DefaultObject
=
113 ctx
->Driver
.NewTransformFeedback(ctx
, 0);
115 assert(ctx
->TransformFeedback
.DefaultObject
->RefCount
== 1);
117 reference_transform_feedback_object(&ctx
->TransformFeedback
.CurrentObject
,
118 ctx
->TransformFeedback
.DefaultObject
);
120 assert(ctx
->TransformFeedback
.DefaultObject
->RefCount
== 2);
122 ctx
->TransformFeedback
.Objects
= _mesa_NewHashTable();
124 _mesa_reference_buffer_object(ctx
,
125 &ctx
->TransformFeedback
.CurrentBuffer
,
126 ctx
->Shared
->NullBufferObj
);
132 * Callback for _mesa_HashDeleteAll().
135 delete_cb(GLuint key
, void *data
, void *userData
)
137 struct gl_context
*ctx
= (struct gl_context
*) userData
;
138 struct gl_transform_feedback_object
*obj
=
139 (struct gl_transform_feedback_object
*) data
;
141 ctx
->Driver
.DeleteTransformFeedback(ctx
, obj
);
146 * Per-context free/clean-up for transform feedback.
149 _mesa_free_transform_feedback(struct gl_context
*ctx
)
151 /* core mesa expects this, even a dummy one, to be available */
152 ASSERT(ctx
->Driver
.NewTransformFeedback
);
154 _mesa_reference_buffer_object(ctx
,
155 &ctx
->TransformFeedback
.CurrentBuffer
,
158 /* Delete all feedback objects */
159 _mesa_HashDeleteAll(ctx
->TransformFeedback
.Objects
, delete_cb
, ctx
);
160 _mesa_DeleteHashTable(ctx
->TransformFeedback
.Objects
);
162 /* Delete the default feedback object */
163 assert(ctx
->Driver
.DeleteTransformFeedback
);
164 ctx
->Driver
.DeleteTransformFeedback(ctx
,
165 ctx
->TransformFeedback
.DefaultObject
);
167 ctx
->TransformFeedback
.CurrentObject
= NULL
;
171 /** Default fallback for ctx->Driver.NewTransformFeedback() */
172 static struct gl_transform_feedback_object
*
173 new_transform_feedback(struct gl_context
*ctx
, GLuint name
)
175 struct gl_transform_feedback_object
*obj
;
176 obj
= CALLOC_STRUCT(gl_transform_feedback_object
);
184 /** Default fallback for ctx->Driver.DeleteTransformFeedback() */
186 delete_transform_feedback(struct gl_context
*ctx
,
187 struct gl_transform_feedback_object
*obj
)
191 for (i
= 0; i
< Elements(obj
->Buffers
); i
++) {
192 _mesa_reference_buffer_object(ctx
, &obj
->Buffers
[i
], NULL
);
199 /** Default fallback for ctx->Driver.BeginTransformFeedback() */
201 begin_transform_feedback(struct gl_context
*ctx
, GLenum mode
,
202 struct gl_transform_feedback_object
*obj
)
207 /** Default fallback for ctx->Driver.EndTransformFeedback() */
209 end_transform_feedback(struct gl_context
*ctx
,
210 struct gl_transform_feedback_object
*obj
)
215 /** Default fallback for ctx->Driver.PauseTransformFeedback() */
217 pause_transform_feedback(struct gl_context
*ctx
,
218 struct gl_transform_feedback_object
*obj
)
223 /** Default fallback for ctx->Driver.ResumeTransformFeedback() */
225 resume_transform_feedback(struct gl_context
*ctx
,
226 struct gl_transform_feedback_object
*obj
)
233 * Plug in default device driver functions for transform feedback.
234 * Most drivers will override some/all of these.
237 _mesa_init_transform_feedback_functions(struct dd_function_table
*driver
)
239 driver
->NewTransformFeedback
= new_transform_feedback
;
240 driver
->DeleteTransformFeedback
= delete_transform_feedback
;
241 driver
->BeginTransformFeedback
= begin_transform_feedback
;
242 driver
->EndTransformFeedback
= end_transform_feedback
;
243 driver
->PauseTransformFeedback
= pause_transform_feedback
;
244 driver
->ResumeTransformFeedback
= resume_transform_feedback
;
249 _mesa_init_transform_feedback_dispatch(const struct gl_context
*ctx
,
250 struct _glapi_table
*disp
)
252 /* EXT_transform_feedback */
253 SET_BeginTransformFeedbackEXT(disp
, _mesa_BeginTransformFeedback
);
254 SET_EndTransformFeedbackEXT(disp
, _mesa_EndTransformFeedback
);
255 if (_mesa_is_desktop_gl(ctx
)) {
256 SET_BindBufferOffsetEXT(disp
, _mesa_BindBufferOffsetEXT
);
258 SET_TransformFeedbackVaryingsEXT(disp
, _mesa_TransformFeedbackVaryings
);
259 SET_GetTransformFeedbackVaryingEXT(disp
, _mesa_GetTransformFeedbackVarying
);
260 /* ARB_transform_feedback2 */
261 SET_BindTransformFeedback(disp
, _mesa_BindTransformFeedback
);
262 SET_DeleteTransformFeedbacks(disp
, _mesa_DeleteTransformFeedbacks
);
263 SET_GenTransformFeedbacks(disp
, _mesa_GenTransformFeedbacks
);
264 SET_IsTransformFeedback(disp
, _mesa_IsTransformFeedback
);
265 SET_PauseTransformFeedback(disp
, _mesa_PauseTransformFeedback
);
266 SET_ResumeTransformFeedback(disp
, _mesa_ResumeTransformFeedback
);
271 ** Begin API functions
276 _mesa_BeginTransformFeedback(GLenum mode
)
278 struct gl_transform_feedback_object
*obj
;
279 struct gl_transform_feedback_info
*info
;
281 GET_CURRENT_CONTEXT(ctx
);
283 obj
= ctx
->TransformFeedback
.CurrentObject
;
285 if (ctx
->Shader
.CurrentVertexProgram
== NULL
) {
286 _mesa_error(ctx
, GL_INVALID_OPERATION
,
287 "glBeginTransformFeedback(no program active)");
291 info
= &ctx
->Shader
.CurrentVertexProgram
->LinkedTransformFeedback
;
293 if (info
->NumOutputs
== 0) {
294 _mesa_error(ctx
, GL_INVALID_OPERATION
,
295 "glBeginTransformFeedback(no varyings to record)");
306 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBeginTransformFeedback(mode)");
311 _mesa_error(ctx
, GL_INVALID_OPERATION
,
312 "glBeginTransformFeedback(already active)");
316 for (i
= 0; i
< info
->NumBuffers
; ++i
) {
317 if (obj
->BufferNames
[i
] == 0) {
318 _mesa_error(ctx
, GL_INVALID_OPERATION
,
319 "glBeginTransformFeedback(binding point %d does not have "
320 "a buffer object bound)", i
);
325 FLUSH_VERTICES(ctx
, _NEW_TRANSFORM_FEEDBACK
);
326 obj
->Active
= GL_TRUE
;
327 ctx
->TransformFeedback
.Mode
= mode
;
329 assert(ctx
->Driver
.BeginTransformFeedback
);
330 ctx
->Driver
.BeginTransformFeedback(ctx
, mode
, obj
);
335 _mesa_EndTransformFeedback(void)
337 struct gl_transform_feedback_object
*obj
;
338 GET_CURRENT_CONTEXT(ctx
);
340 obj
= ctx
->TransformFeedback
.CurrentObject
;
343 _mesa_error(ctx
, GL_INVALID_OPERATION
,
344 "glEndTransformFeedback(not active)");
348 FLUSH_VERTICES(ctx
, _NEW_TRANSFORM_FEEDBACK
);
349 ctx
->TransformFeedback
.CurrentObject
->Active
= GL_FALSE
;
350 ctx
->TransformFeedback
.CurrentObject
->Paused
= GL_FALSE
;
351 ctx
->TransformFeedback
.CurrentObject
->EndedAnytime
= GL_TRUE
;
353 assert(ctx
->Driver
.EndTransformFeedback
);
354 ctx
->Driver
.EndTransformFeedback(ctx
, obj
);
359 * Helper used by BindBufferRange() and BindBufferBase().
362 bind_buffer_range(struct gl_context
*ctx
, GLuint index
,
363 struct gl_buffer_object
*bufObj
,
364 GLintptr offset
, GLsizeiptr size
)
366 struct gl_transform_feedback_object
*obj
=
367 ctx
->TransformFeedback
.CurrentObject
;
369 /* Note: no need to FLUSH_VERTICES or flag _NEW_TRANSFORM_FEEDBACK, because
370 * transform feedback buffers can't be changed while transform feedback is
374 /* The general binding point */
375 _mesa_reference_buffer_object(ctx
,
376 &ctx
->TransformFeedback
.CurrentBuffer
,
379 /* The per-attribute binding point */
380 _mesa_reference_buffer_object(ctx
,
381 &obj
->Buffers
[index
],
384 obj
->BufferNames
[index
] = bufObj
->Name
;
386 obj
->Offset
[index
] = offset
;
387 obj
->Size
[index
] = size
;
392 * Specify a buffer object to receive vertex shader results. Plus,
393 * specify the starting offset to place the results, and max size.
394 * Called from the glBindBufferRange() function.
397 _mesa_bind_buffer_range_transform_feedback(struct gl_context
*ctx
,
399 struct gl_buffer_object
*bufObj
,
403 struct gl_transform_feedback_object
*obj
;
405 obj
= ctx
->TransformFeedback
.CurrentObject
;
408 _mesa_error(ctx
, GL_INVALID_OPERATION
,
409 "glBindBufferRange(transform feedback active)");
413 if (index
>= ctx
->Const
.MaxTransformFeedbackBuffers
) {
414 _mesa_error(ctx
, GL_INVALID_VALUE
, "glBindBufferRange(index=%d)", index
);
419 /* must a multiple of four */
420 _mesa_error(ctx
, GL_INVALID_VALUE
, "glBindBufferRange(size=%d)", (int) size
);
425 /* must be multiple of four */
426 _mesa_error(ctx
, GL_INVALID_VALUE
,
427 "glBindBufferRange(offset=%d)", (int) offset
);
431 bind_buffer_range(ctx
, index
, bufObj
, offset
, size
);
436 * Specify a buffer object to receive vertex shader results.
437 * As above, but start at offset = 0.
438 * Called from the glBindBufferBase() function.
441 _mesa_bind_buffer_base_transform_feedback(struct gl_context
*ctx
,
443 struct gl_buffer_object
*bufObj
)
445 struct gl_transform_feedback_object
*obj
;
448 obj
= ctx
->TransformFeedback
.CurrentObject
;
451 _mesa_error(ctx
, GL_INVALID_OPERATION
,
452 "glBindBufferBase(transform feedback active)");
456 if (index
>= ctx
->Const
.MaxTransformFeedbackBuffers
) {
457 _mesa_error(ctx
, GL_INVALID_VALUE
, "glBindBufferBase(index=%d)", index
);
461 /* default size is the buffer size rounded down to nearest
464 size
= bufObj
->Size
& ~0x3;
466 bind_buffer_range(ctx
, index
, bufObj
, 0, size
);
471 * Specify a buffer object to receive vertex shader results, plus the
472 * offset in the buffer to start placing results.
473 * This function is part of GL_EXT_transform_feedback, but not GL3.
476 _mesa_BindBufferOffsetEXT(GLenum target
, GLuint index
, GLuint buffer
,
479 struct gl_transform_feedback_object
*obj
;
480 struct gl_buffer_object
*bufObj
;
481 GET_CURRENT_CONTEXT(ctx
);
484 if (target
!= GL_TRANSFORM_FEEDBACK_BUFFER
) {
485 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBindBufferOffsetEXT(target)");
489 obj
= ctx
->TransformFeedback
.CurrentObject
;
492 _mesa_error(ctx
, GL_INVALID_OPERATION
,
493 "glBindBufferOffsetEXT(transform feedback active)");
497 if (index
>= ctx
->Const
.MaxTransformFeedbackBuffers
) {
498 _mesa_error(ctx
, GL_INVALID_VALUE
,
499 "glBindBufferOffsetEXT(index=%d)", index
);
504 /* must be multiple of four */
505 _mesa_error(ctx
, GL_INVALID_VALUE
,
506 "glBindBufferOffsetEXT(offset=%d)", (int) offset
);
511 bufObj
= ctx
->Shared
->NullBufferObj
;
513 bufObj
= _mesa_lookup_bufferobj(ctx
, buffer
);
517 _mesa_error(ctx
, GL_INVALID_OPERATION
,
518 "glBindBufferOffsetEXT(invalid buffer=%u)", buffer
);
522 /* default size is the buffer size rounded down to nearest
525 size
= (bufObj
->Size
- offset
) & ~0x3;
527 bind_buffer_range(ctx
, index
, bufObj
, offset
, size
);
532 * This function specifies the vertex shader outputs to be written
533 * to the feedback buffer(s), and in what order.
536 _mesa_TransformFeedbackVaryings(GLuint program
, GLsizei count
,
537 const GLchar
**varyings
, GLenum bufferMode
)
539 struct gl_shader_program
*shProg
;
541 GET_CURRENT_CONTEXT(ctx
);
543 switch (bufferMode
) {
544 case GL_INTERLEAVED_ATTRIBS
:
546 case GL_SEPARATE_ATTRIBS
:
549 _mesa_error(ctx
, GL_INVALID_ENUM
,
550 "glTransformFeedbackVaryings(bufferMode)");
555 (bufferMode
== GL_SEPARATE_ATTRIBS
&&
556 (GLuint
) count
> ctx
->Const
.MaxTransformFeedbackBuffers
)) {
557 _mesa_error(ctx
, GL_INVALID_VALUE
,
558 "glTransformFeedbackVaryings(count=%d)", count
);
562 shProg
= _mesa_lookup_shader_program(ctx
, program
);
564 _mesa_error(ctx
, GL_INVALID_VALUE
,
565 "glTransformFeedbackVaryings(program=%u)", program
);
569 if (ctx
->Extensions
.ARB_transform_feedback3
) {
570 if (bufferMode
== GL_INTERLEAVED_ATTRIBS
) {
571 unsigned buffers
= 1;
573 for (i
= 0; i
< count
; i
++) {
574 if (strcmp(varyings
[i
], "gl_NextBuffer") == 0)
578 if (buffers
> ctx
->Const
.MaxTransformFeedbackBuffers
) {
579 _mesa_error(ctx
, GL_INVALID_OPERATION
,
580 "glTransformFeedbackVaryings(too many gl_NextBuffer "
585 for (i
= 0; i
< count
; i
++) {
586 if (strcmp(varyings
[i
], "gl_NextBuffer") == 0 ||
587 strcmp(varyings
[i
], "gl_SkipComponents1") == 0 ||
588 strcmp(varyings
[i
], "gl_SkipComponents2") == 0 ||
589 strcmp(varyings
[i
], "gl_SkipComponents3") == 0 ||
590 strcmp(varyings
[i
], "gl_SkipComponents4") == 0) {
591 _mesa_error(ctx
, GL_INVALID_OPERATION
,
592 "glTransformFeedbackVaryings(SEPARATE_ATTRIBS,"
601 /* free existing varyings, if any */
602 for (i
= 0; i
< (GLint
) shProg
->TransformFeedback
.NumVarying
; i
++) {
603 free(shProg
->TransformFeedback
.VaryingNames
[i
]);
605 free(shProg
->TransformFeedback
.VaryingNames
);
607 /* allocate new memory for varying names */
608 shProg
->TransformFeedback
.VaryingNames
=
609 malloc(count
* sizeof(GLchar
*));
611 if (!shProg
->TransformFeedback
.VaryingNames
) {
612 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glTransformFeedbackVaryings()");
616 /* Save the new names and the count */
617 for (i
= 0; i
< count
; i
++) {
618 shProg
->TransformFeedback
.VaryingNames
[i
] = _mesa_strdup(varyings
[i
]);
620 shProg
->TransformFeedback
.NumVarying
= count
;
622 shProg
->TransformFeedback
.BufferMode
= bufferMode
;
624 /* No need to set _NEW_TRANSFORM_FEEDBACK (or invoke FLUSH_VERTICES) since
625 * the varyings won't be used until shader link time.
631 * Get info about the vertex shader's outputs which are to be written
632 * to the feedback buffer(s).
635 _mesa_GetTransformFeedbackVarying(GLuint program
, GLuint index
,
636 GLsizei bufSize
, GLsizei
*length
,
637 GLsizei
*size
, GLenum
*type
, GLchar
*name
)
639 const struct gl_shader_program
*shProg
;
640 const struct gl_transform_feedback_info
*linked_xfb_info
;
641 GET_CURRENT_CONTEXT(ctx
);
643 shProg
= _mesa_lookup_shader_program(ctx
, program
);
645 _mesa_error(ctx
, GL_INVALID_VALUE
,
646 "glGetTransformFeedbackVaryings(program=%u)", program
);
650 linked_xfb_info
= &shProg
->LinkedTransformFeedback
;
651 if (index
>= (GLuint
) linked_xfb_info
->NumVarying
) {
652 _mesa_error(ctx
, GL_INVALID_VALUE
,
653 "glGetTransformFeedbackVaryings(index=%u)", index
);
657 /* return the varying's name and length */
658 _mesa_copy_string(name
, bufSize
, length
,
659 linked_xfb_info
->Varyings
[index
].Name
);
661 /* return the datatype and value's size (in datatype units) */
663 *type
= linked_xfb_info
->Varyings
[index
].Type
;
665 *size
= linked_xfb_info
->Varyings
[index
].Size
;
670 struct gl_transform_feedback_object
*
671 _mesa_lookup_transform_feedback_object(struct gl_context
*ctx
, GLuint name
)
674 return ctx
->TransformFeedback
.DefaultObject
;
677 return (struct gl_transform_feedback_object
*)
678 _mesa_HashLookup(ctx
->TransformFeedback
.Objects
, name
);
683 * Create new transform feedback objects. Transform feedback objects
684 * encapsulate the state related to transform feedback to allow quickly
685 * switching state (and drawing the results, below).
686 * Part of GL_ARB_transform_feedback2.
689 _mesa_GenTransformFeedbacks(GLsizei n
, GLuint
*names
)
692 GET_CURRENT_CONTEXT(ctx
);
694 ASSERT_OUTSIDE_BEGIN_END(ctx
);
697 _mesa_error(ctx
, GL_INVALID_VALUE
, "glGenTransformFeedbacks(n < 0)");
704 /* we don't need contiguous IDs, but this might be faster */
705 first
= _mesa_HashFindFreeKeyBlock(ctx
->TransformFeedback
.Objects
, n
);
708 for (i
= 0; i
< n
; i
++) {
709 struct gl_transform_feedback_object
*obj
710 = ctx
->Driver
.NewTransformFeedback(ctx
, first
+ i
);
712 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGenTransformFeedbacks");
715 names
[i
] = first
+ i
;
716 _mesa_HashInsert(ctx
->TransformFeedback
.Objects
, first
+ i
, obj
);
720 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGenTransformFeedbacks");
726 * Is the given ID a transform feedback object?
727 * Part of GL_ARB_transform_feedback2.
730 _mesa_IsTransformFeedback(GLuint name
)
732 GET_CURRENT_CONTEXT(ctx
);
734 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, GL_FALSE
);
736 if (name
&& _mesa_lookup_transform_feedback_object(ctx
, name
))
744 * Bind the given transform feedback object.
745 * Part of GL_ARB_transform_feedback2.
748 _mesa_BindTransformFeedback(GLenum target
, GLuint name
)
750 struct gl_transform_feedback_object
*obj
;
751 GET_CURRENT_CONTEXT(ctx
);
753 if (target
!= GL_TRANSFORM_FEEDBACK
) {
754 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBindTransformFeedback(target)");
758 if (ctx
->TransformFeedback
.CurrentObject
->Active
&&
759 !ctx
->TransformFeedback
.CurrentObject
->Paused
) {
760 _mesa_error(ctx
, GL_INVALID_OPERATION
,
761 "glBindTransformFeedback(transform is active, or not paused)");
765 obj
= _mesa_lookup_transform_feedback_object(ctx
, name
);
767 _mesa_error(ctx
, GL_INVALID_OPERATION
,
768 "glBindTransformFeedback(name=%u)", name
);
772 reference_transform_feedback_object(&ctx
->TransformFeedback
.CurrentObject
,
778 * Delete the given transform feedback objects.
779 * Part of GL_ARB_transform_feedback2.
782 _mesa_DeleteTransformFeedbacks(GLsizei n
, const GLuint
*names
)
785 GET_CURRENT_CONTEXT(ctx
);
787 ASSERT_OUTSIDE_BEGIN_END(ctx
);
790 _mesa_error(ctx
, GL_INVALID_VALUE
, "glDeleteTransformFeedbacks(n < 0)");
797 for (i
= 0; i
< n
; i
++) {
799 struct gl_transform_feedback_object
*obj
800 = _mesa_lookup_transform_feedback_object(ctx
, names
[i
]);
803 _mesa_error(ctx
, GL_INVALID_OPERATION
,
804 "glDeleteTransformFeedbacks(object %u is active)",
808 _mesa_HashRemove(ctx
->TransformFeedback
.Objects
, names
[i
]);
809 /* unref, but object may not be deleted until later */
810 reference_transform_feedback_object(&obj
, NULL
);
818 * Pause transform feedback.
819 * Part of GL_ARB_transform_feedback2.
822 _mesa_PauseTransformFeedback(void)
824 struct gl_transform_feedback_object
*obj
;
825 GET_CURRENT_CONTEXT(ctx
);
827 obj
= ctx
->TransformFeedback
.CurrentObject
;
829 if (!obj
->Active
|| obj
->Paused
) {
830 _mesa_error(ctx
, GL_INVALID_OPERATION
,
831 "glPauseTransformFeedback(feedback not active or already paused)");
835 FLUSH_VERTICES(ctx
, _NEW_TRANSFORM_FEEDBACK
);
836 obj
->Paused
= GL_TRUE
;
838 assert(ctx
->Driver
.PauseTransformFeedback
);
839 ctx
->Driver
.PauseTransformFeedback(ctx
, obj
);
844 * Resume transform feedback.
845 * Part of GL_ARB_transform_feedback2.
848 _mesa_ResumeTransformFeedback(void)
850 struct gl_transform_feedback_object
*obj
;
851 GET_CURRENT_CONTEXT(ctx
);
853 obj
= ctx
->TransformFeedback
.CurrentObject
;
855 if (!obj
->Active
|| !obj
->Paused
) {
856 _mesa_error(ctx
, GL_INVALID_OPERATION
,
857 "glResumeTransformFeedback(feedback not active or not paused)");
861 FLUSH_VERTICES(ctx
, _NEW_TRANSFORM_FEEDBACK
);
862 obj
->Paused
= GL_FALSE
;
864 assert(ctx
->Driver
.ResumeTransformFeedback
);
865 ctx
->Driver
.ResumeTransformFeedback(ctx
, obj
);