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 /* EXT_transform_feedback */
331 SET_BeginTransformFeedbackEXT(disp
, _mesa_BeginTransformFeedback
);
332 SET_EndTransformFeedbackEXT(disp
, _mesa_EndTransformFeedback
);
333 SET_BindBufferRangeEXT(disp
, _mesa_BindBufferRange
);
334 SET_BindBufferBaseEXT(disp
, _mesa_BindBufferBase
);
335 SET_BindBufferOffsetEXT(disp
, _mesa_BindBufferOffsetEXT
);
336 SET_TransformFeedbackVaryingsEXT(disp
, _mesa_TransformFeedbackVaryings
);
337 SET_GetTransformFeedbackVaryingEXT(disp
, _mesa_GetTransformFeedbackVarying
);
338 /* ARB_transform_feedback2 */
339 SET_BindTransformFeedback(disp
, _mesa_BindTransformFeedback
);
340 SET_DeleteTransformFeedbacks(disp
, _mesa_DeleteTransformFeedbacks
);
341 SET_GenTransformFeedbacks(disp
, _mesa_GenTransformFeedbacks
);
342 SET_IsTransformFeedback(disp
, _mesa_IsTransformFeedback
);
343 SET_PauseTransformFeedback(disp
, _mesa_PauseTransformFeedback
);
344 SET_ResumeTransformFeedback(disp
, _mesa_ResumeTransformFeedback
);
345 SET_DrawTransformFeedback(disp
, _mesa_DrawTransformFeedback
);
350 ** Begin API functions
355 _mesa_BeginTransformFeedback(GLenum mode
)
357 struct gl_transform_feedback_object
*obj
;
358 GET_CURRENT_CONTEXT(ctx
);
360 obj
= ctx
->TransformFeedback
.CurrentObject
;
369 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBeginTransformFeedback(mode)");
374 _mesa_error(ctx
, GL_INVALID_OPERATION
,
375 "glBeginTransformFeedback(already active)");
379 obj
->Active
= GL_TRUE
;
380 ctx
->TransformFeedback
.Mode
= mode
;
382 assert(ctx
->Driver
.BeginTransformFeedback
);
383 ctx
->Driver
.BeginTransformFeedback(ctx
, mode
, obj
);
388 _mesa_EndTransformFeedback(void)
390 struct gl_transform_feedback_object
*obj
;
391 GET_CURRENT_CONTEXT(ctx
);
393 obj
= ctx
->TransformFeedback
.CurrentObject
;
396 _mesa_error(ctx
, GL_INVALID_OPERATION
,
397 "glEndTransformFeedback(not active)");
401 ctx
->TransformFeedback
.CurrentObject
->Active
= GL_FALSE
;
403 assert(ctx
->Driver
.EndTransformFeedback
);
404 ctx
->Driver
.EndTransformFeedback(ctx
, obj
);
409 * Helper used by BindBufferRange() and BindBufferBase().
412 bind_buffer_range(struct gl_context
*ctx
, GLuint index
,
413 struct gl_buffer_object
*bufObj
,
414 GLintptr offset
, GLsizeiptr size
)
416 struct gl_transform_feedback_object
*obj
=
417 ctx
->TransformFeedback
.CurrentObject
;
419 /* The general binding point */
420 _mesa_reference_buffer_object(ctx
,
421 &ctx
->TransformFeedback
.CurrentBuffer
,
424 /* The per-attribute binding point */
425 _mesa_reference_buffer_object(ctx
,
426 &obj
->Buffers
[index
],
429 obj
->BufferNames
[index
] = bufObj
->Name
;
431 obj
->Offset
[index
] = offset
;
432 obj
->Size
[index
] = size
;
437 * Specify a buffer object to receive vertex shader results. Plus,
438 * specify the starting offset to place the results, and max size.
441 _mesa_BindBufferRange(GLenum target
, GLuint index
,
442 GLuint buffer
, GLintptr offset
, GLsizeiptr size
)
444 struct gl_transform_feedback_object
*obj
;
445 struct gl_buffer_object
*bufObj
;
446 GET_CURRENT_CONTEXT(ctx
);
448 if (target
!= GL_TRANSFORM_FEEDBACK_BUFFER
) {
449 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBindBufferRange(target)");
453 obj
= ctx
->TransformFeedback
.CurrentObject
;
456 _mesa_error(ctx
, GL_INVALID_OPERATION
,
457 "glBindBufferRange(transform feedback active)");
461 if (index
>= ctx
->Const
.MaxTransformFeedbackSeparateAttribs
) {
462 _mesa_error(ctx
, GL_INVALID_VALUE
, "glBindBufferRange(index=%d)", index
);
466 if ((size
<= 0) || (size
& 0x3)) {
467 /* must be positive and multiple of four */
468 _mesa_error(ctx
, GL_INVALID_VALUE
, "glBindBufferRange(size%d)", (int) size
);
473 /* must be multiple of four */
474 _mesa_error(ctx
, GL_INVALID_VALUE
,
475 "glBindBufferRange(offset=%d)", (int) offset
);
479 bufObj
= _mesa_lookup_bufferobj(ctx
, buffer
);
481 _mesa_error(ctx
, GL_INVALID_OPERATION
,
482 "glBindBufferRange(invalid buffer=%u)", buffer
);
486 if (offset
+ size
>= bufObj
->Size
) {
487 _mesa_error(ctx
, GL_INVALID_VALUE
,
488 "glBindBufferRange(offset + size %d > buffer size %d)",
489 (int) (offset
+ size
), (int) (bufObj
->Size
));
493 bind_buffer_range(ctx
, index
, bufObj
, offset
, size
);
498 * Specify a buffer object to receive vertex shader results.
499 * As above, but start at offset = 0.
502 _mesa_BindBufferBase(GLenum target
, GLuint index
, GLuint buffer
)
504 struct gl_transform_feedback_object
*obj
;
505 struct gl_buffer_object
*bufObj
;
507 GET_CURRENT_CONTEXT(ctx
);
509 if (target
!= GL_TRANSFORM_FEEDBACK_BUFFER
) {
510 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBindBufferBase(target)");
514 obj
= ctx
->TransformFeedback
.CurrentObject
;
517 _mesa_error(ctx
, GL_INVALID_OPERATION
,
518 "glBindBufferBase(transform feedback active)");
522 if (index
>= ctx
->Const
.MaxTransformFeedbackSeparateAttribs
) {
523 _mesa_error(ctx
, GL_INVALID_VALUE
, "glBindBufferBase(index=%d)", index
);
527 bufObj
= _mesa_lookup_bufferobj(ctx
, buffer
);
529 _mesa_error(ctx
, GL_INVALID_OPERATION
,
530 "glBindBufferBase(invalid buffer=%u)", buffer
);
534 /* default size is the buffer size rounded down to nearest
537 size
= bufObj
->Size
& ~0x3;
539 bind_buffer_range(ctx
, index
, bufObj
, 0, size
);
544 * Specify a buffer object to receive vertex shader results, plus the
545 * offset in the buffer to start placing results.
546 * This function is part of GL_EXT_transform_feedback, but not GL3.
549 _mesa_BindBufferOffsetEXT(GLenum target
, GLuint index
, GLuint buffer
,
552 struct gl_transform_feedback_object
*obj
;
553 struct gl_buffer_object
*bufObj
;
554 GET_CURRENT_CONTEXT(ctx
);
557 if (target
!= GL_TRANSFORM_FEEDBACK_BUFFER
) {
558 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBindBufferOffsetEXT(target)");
562 obj
= ctx
->TransformFeedback
.CurrentObject
;
565 _mesa_error(ctx
, GL_INVALID_OPERATION
,
566 "glBindBufferOffsetEXT(transform feedback active)");
570 if (index
>= ctx
->Const
.MaxTransformFeedbackSeparateAttribs
) {
571 _mesa_error(ctx
, GL_INVALID_VALUE
,
572 "glBindBufferOffsetEXT(index=%d)", index
);
576 bufObj
= _mesa_lookup_bufferobj(ctx
, buffer
);
578 _mesa_error(ctx
, GL_INVALID_OPERATION
,
579 "glBindBufferOffsetEXT(invalid buffer=%u)", buffer
);
583 /* default size is the buffer size rounded down to nearest
586 size
= (bufObj
->Size
- offset
) & ~0x3;
588 bind_buffer_range(ctx
, index
, bufObj
, offset
, size
);
593 * This function specifies the vertex shader outputs to be written
594 * to the feedback buffer(s), and in what order.
597 _mesa_TransformFeedbackVaryings(GLuint program
, GLsizei count
,
598 const GLchar
**varyings
, GLenum bufferMode
)
600 struct gl_shader_program
*shProg
;
602 GET_CURRENT_CONTEXT(ctx
);
604 switch (bufferMode
) {
605 case GL_INTERLEAVED_ATTRIBS
:
607 case GL_SEPARATE_ATTRIBS
:
610 _mesa_error(ctx
, GL_INVALID_ENUM
,
611 "glTransformFeedbackVaryings(bufferMode)");
616 (bufferMode
== GL_SEPARATE_ATTRIBS
&&
617 (GLuint
) count
> ctx
->Const
.MaxTransformFeedbackSeparateAttribs
)) {
618 _mesa_error(ctx
, GL_INVALID_VALUE
,
619 "glTransformFeedbackVaryings(count=%d)", count
);
623 shProg
= _mesa_lookup_shader_program(ctx
, program
);
625 _mesa_error(ctx
, GL_INVALID_VALUE
,
626 "glTransformFeedbackVaryings(program=%u)", program
);
630 /* free existing varyings, if any */
631 for (i
= 0; i
< shProg
->TransformFeedback
.NumVarying
; i
++) {
632 free(shProg
->TransformFeedback
.VaryingNames
[i
]);
634 free(shProg
->TransformFeedback
.VaryingNames
);
636 /* allocate new memory for varying names */
637 shProg
->TransformFeedback
.VaryingNames
=
638 (GLchar
**) malloc(count
* sizeof(GLchar
*));
640 if (!shProg
->TransformFeedback
.VaryingNames
) {
641 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glTransformFeedbackVaryings()");
645 /* Save the new names and the count */
646 for (i
= 0; i
< (GLuint
) count
; i
++) {
647 shProg
->TransformFeedback
.VaryingNames
[i
] = _mesa_strdup(varyings
[i
]);
649 shProg
->TransformFeedback
.NumVarying
= count
;
651 shProg
->TransformFeedback
.BufferMode
= bufferMode
;
653 /* The varyings won't be used until shader link time */
658 * Get info about the vertex shader's outputs which are to be written
659 * to the feedback buffer(s).
662 _mesa_GetTransformFeedbackVarying(GLuint program
, GLuint index
,
663 GLsizei bufSize
, GLsizei
*length
,
664 GLsizei
*size
, GLenum
*type
, GLchar
*name
)
666 const struct gl_shader_program
*shProg
;
667 const GLchar
*varyingName
;
669 GET_CURRENT_CONTEXT(ctx
);
671 shProg
= _mesa_lookup_shader_program(ctx
, program
);
673 _mesa_error(ctx
, GL_INVALID_VALUE
,
674 "glGetTransformFeedbackVaryings(program=%u)", program
);
678 if (index
>= shProg
->TransformFeedback
.NumVarying
) {
679 _mesa_error(ctx
, GL_INVALID_VALUE
,
680 "glGetTransformFeedbackVaryings(index=%u)", index
);
684 varyingName
= shProg
->TransformFeedback
.VaryingNames
[index
];
686 v
= _mesa_lookup_parameter_index(shProg
->Varying
, -1, varyingName
);
688 struct gl_program_parameter
*param
= &shProg
->Varying
->Parameters
[v
];
690 /* return the varying's name and length */
691 _mesa_copy_string(name
, bufSize
, length
, varyingName
);
693 /* return the datatype and value's size (in datatype units) */
695 *type
= param
->DataType
;
712 static struct gl_transform_feedback_object
*
713 lookup_transform_feedback_object(struct gl_context
*ctx
, GLuint name
)
716 return ctx
->TransformFeedback
.DefaultObject
;
719 return (struct gl_transform_feedback_object
*)
720 _mesa_HashLookup(ctx
->TransformFeedback
.Objects
, name
);
725 * Create new transform feedback objects. Transform feedback objects
726 * encapsulate the state related to transform feedback to allow quickly
727 * switching state (and drawing the results, below).
728 * Part of GL_ARB_transform_feedback2.
731 _mesa_GenTransformFeedbacks(GLsizei n
, GLuint
*names
)
734 GET_CURRENT_CONTEXT(ctx
);
736 ASSERT_OUTSIDE_BEGIN_END(ctx
);
739 _mesa_error(ctx
, GL_INVALID_VALUE
, "glGenTransformFeedbacks(n < 0)");
746 /* we don't need contiguous IDs, but this might be faster */
747 first
= _mesa_HashFindFreeKeyBlock(ctx
->TransformFeedback
.Objects
, n
);
750 for (i
= 0; i
< n
; i
++) {
751 struct gl_transform_feedback_object
*obj
752 = ctx
->Driver
.NewTransformFeedback(ctx
, first
+ i
);
754 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGenTransformFeedbacks");
757 names
[i
] = first
+ i
;
758 _mesa_HashInsert(ctx
->TransformFeedback
.Objects
, first
+ i
, obj
);
762 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGenTransformFeedbacks");
768 * Is the given ID a transform feedback object?
769 * Part of GL_ARB_transform_feedback2.
772 _mesa_IsTransformFeedback(GLuint name
)
774 GET_CURRENT_CONTEXT(ctx
);
776 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, GL_FALSE
);
778 if (name
&& lookup_transform_feedback_object(ctx
, name
))
786 * Bind the given transform feedback object.
787 * Part of GL_ARB_transform_feedback2.
790 _mesa_BindTransformFeedback(GLenum target
, GLuint name
)
792 struct gl_transform_feedback_object
*obj
;
793 GET_CURRENT_CONTEXT(ctx
);
795 if (target
!= GL_TRANSFORM_FEEDBACK
) {
796 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBindTransformFeedback(target)");
800 if (ctx
->TransformFeedback
.CurrentObject
->Active
&&
801 !ctx
->TransformFeedback
.CurrentObject
->Paused
) {
802 _mesa_error(ctx
, GL_INVALID_OPERATION
,
803 "glBindTransformFeedback(transform is active, or not paused)");
807 obj
= lookup_transform_feedback_object(ctx
, name
);
809 _mesa_error(ctx
, GL_INVALID_OPERATION
,
810 "glBindTransformFeedback(name=%u)", name
);
814 reference_transform_feedback_object(&ctx
->TransformFeedback
.CurrentObject
,
820 * Delete the given transform feedback objects.
821 * Part of GL_ARB_transform_feedback2.
824 _mesa_DeleteTransformFeedbacks(GLsizei n
, const GLuint
*names
)
827 GET_CURRENT_CONTEXT(ctx
);
829 ASSERT_OUTSIDE_BEGIN_END(ctx
);
832 _mesa_error(ctx
, GL_INVALID_VALUE
, "glDeleteTransformFeedbacks(n < 0)");
839 for (i
= 0; i
< n
; i
++) {
841 struct gl_transform_feedback_object
*obj
842 = lookup_transform_feedback_object(ctx
, names
[i
]);
845 _mesa_error(ctx
, GL_INVALID_OPERATION
,
846 "glDeleteTransformFeedbacks(object %u is active)",
850 _mesa_HashRemove(ctx
->TransformFeedback
.Objects
, names
[i
]);
851 /* unref, but object may not be deleted until later */
852 reference_transform_feedback_object(&obj
, NULL
);
860 * Pause transform feedback.
861 * Part of GL_ARB_transform_feedback2.
864 _mesa_PauseTransformFeedback(void)
866 struct gl_transform_feedback_object
*obj
;
867 GET_CURRENT_CONTEXT(ctx
);
869 obj
= ctx
->TransformFeedback
.CurrentObject
;
871 if (!obj
->Active
|| obj
->Paused
) {
872 _mesa_error(ctx
, GL_INVALID_OPERATION
,
873 "glPauseTransformFeedback(feedback not active or already paused)");
877 obj
->Paused
= GL_TRUE
;
879 assert(ctx
->Driver
.PauseTransformFeedback
);
880 ctx
->Driver
.PauseTransformFeedback(ctx
, obj
);
885 * Resume transform feedback.
886 * Part of GL_ARB_transform_feedback2.
889 _mesa_ResumeTransformFeedback(void)
891 struct gl_transform_feedback_object
*obj
;
892 GET_CURRENT_CONTEXT(ctx
);
894 obj
= ctx
->TransformFeedback
.CurrentObject
;
896 if (!obj
->Active
|| !obj
->Paused
) {
897 _mesa_error(ctx
, GL_INVALID_OPERATION
,
898 "glResumeTransformFeedback(feedback not active or not paused)");
902 obj
->Paused
= GL_FALSE
;
904 assert(ctx
->Driver
.ResumeTransformFeedback
);
905 ctx
->Driver
.ResumeTransformFeedback(ctx
, obj
);
910 * Draw the vertex data in a transform feedback object.
911 * \param mode GL_POINTS, GL_LINES, GL_TRIANGLE_STRIP, etc.
912 * \param name the transform feedback object
913 * The number of vertices comes from the transform feedback object.
914 * User still has to setup of the vertex attribute info with
915 * glVertexPointer, glColorPointer, etc.
916 * Part of GL_ARB_transform_feedback2.
919 _mesa_DrawTransformFeedback(GLenum mode
, GLuint name
)
921 GET_CURRENT_CONTEXT(ctx
);
922 struct gl_transform_feedback_object
*obj
=
923 lookup_transform_feedback_object(ctx
, name
);
925 if (mode
> GL_POLYGON
) {
926 _mesa_error(ctx
, GL_INVALID_ENUM
,
927 "glDrawTransformFeedback(mode=0x%x)", mode
);
931 _mesa_error(ctx
, GL_INVALID_VALUE
,
932 "glDrawTransformFeedback(name = %u)", name
);
936 /* XXX check if EndTransformFeedback has never been called while
937 * the object was bound
940 assert(ctx
->Driver
.DrawTransformFeedback
);
941 ctx
->Driver
.DrawTransformFeedback(ctx
, mode
, obj
);
944 #endif /* FEATURE_EXT_transform_feedback */