68a14d47c8e0c7188528970938835a9e95e9963d
[mesa.git] / src / mesa / main / transformfeedback.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2010 VMware, Inc. All Rights Reserved.
5 *
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:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
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.
22 */
23
24
25 /*
26 * Vertex transform feedback support.
27 *
28 * Authors:
29 * Brian Paul
30 */
31
32
33 #include "buffers.h"
34 #include "bufferobj.h"
35 #include "context.h"
36 #include "hash.h"
37 #include "transformfeedback.h"
38 #include "shaderapi.h"
39 #include "shaderobj.h"
40 #include "main/dispatch.h"
41
42 #include "shader/prog_parameter.h"
43 //#include "shader/shader_api.h"
44
45
46 #if FEATURE_EXT_transform_feedback
47
48
49 /**
50 * Do reference counting of transform feedback buffers.
51 */
52 static void
53 reference_transform_feedback_object(struct gl_transform_feedback_object **ptr,
54 struct gl_transform_feedback_object *obj)
55 {
56 if (*ptr == obj)
57 return;
58
59 if (*ptr) {
60 /* Unreference the old object */
61 struct gl_transform_feedback_object *oldObj = *ptr;
62
63 ASSERT(oldObj->RefCount > 0);
64 oldObj->RefCount--;
65
66 if (oldObj->RefCount == 0) {
67 GET_CURRENT_CONTEXT(ctx);
68 if (ctx)
69 ctx->Driver.DeleteTransformFeedback(ctx, oldObj);
70 }
71
72 *ptr = NULL;
73 }
74 ASSERT(!*ptr);
75
76 if (obj) {
77 /* reference new object */
78 if (obj->RefCount == 0) {
79 _mesa_problem(NULL, "referencing deleted transform feedback object");
80 *ptr = NULL;
81 }
82 else {
83 obj->RefCount++;
84 *ptr = obj;
85 }
86 }
87 }
88
89
90 /**
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.
94 *
95 * \return GL_TRUE if the mode is OK, GL_FALSE otherwise.
96 */
97 GLboolean
98 _mesa_validate_primitive_mode(GLcontext *ctx, GLenum mode)
99 {
100 if (ctx->TransformFeedback.CurrentObject->Active) {
101 switch (mode) {
102 case GL_POINTS:
103 return ctx->TransformFeedback.Mode == GL_POINTS;
104 case GL_LINES:
105 case GL_LINE_STRIP:
106 case GL_LINE_LOOP:
107 return ctx->TransformFeedback.Mode == GL_LINES;
108 default:
109 return ctx->TransformFeedback.Mode == GL_TRIANGLES;
110 }
111 }
112 return GL_TRUE;
113 }
114
115
116 /**
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
121 */
122 GLboolean
123 _mesa_validate_transform_feedback_buffers(GLcontext *ctx)
124 {
125 /* XXX to do */
126 return GL_TRUE;
127 }
128
129
130
131 /**
132 * Per-context init for transform feedback.
133 */
134 void
135 _mesa_init_transform_feedback(GLcontext *ctx)
136 {
137 if (!ctx->Driver.NewTransformFeedback) {
138 /* this feature/extension may not be supported by the driver */
139 return;
140 }
141
142 ctx->TransformFeedback.DefaultObject =
143 ctx->Driver.NewTransformFeedback(ctx, 0);
144
145 assert(ctx->TransformFeedback.DefaultObject->RefCount == 1);
146
147 reference_transform_feedback_object(&ctx->TransformFeedback.CurrentObject,
148 ctx->TransformFeedback.DefaultObject);
149
150 assert(ctx->TransformFeedback.DefaultObject->RefCount == 2);
151
152 ctx->TransformFeedback.Objects = _mesa_NewHashTable();
153
154 _mesa_reference_buffer_object(ctx,
155 &ctx->TransformFeedback.CurrentBuffer,
156 ctx->Shared->NullBufferObj);
157 }
158
159
160
161 /**
162 * Callback for _mesa_HashDeleteAll().
163 */
164 static void
165 delete_cb(GLuint key, void *data, void *userData)
166 {
167 GLcontext *ctx = (GLcontext *) userData;
168 struct gl_transform_feedback_object *obj =
169 (struct gl_transform_feedback_object *) data;
170
171 ctx->Driver.DeleteTransformFeedback(ctx, obj);
172 }
173
174
175 /**
176 * Per-context free/clean-up for transform feedback.
177 */
178 void
179 _mesa_free_transform_feedback(GLcontext *ctx)
180 {
181 if (!ctx->Driver.NewTransformFeedback) {
182 /* this feature/extension may not be supported by the driver */
183 return;
184 }
185
186 _mesa_reference_buffer_object(ctx,
187 &ctx->TransformFeedback.CurrentBuffer,
188 NULL);
189
190 /* Delete all feedback objects */
191 _mesa_HashDeleteAll(ctx->TransformFeedback.Objects, delete_cb, ctx);
192
193 /* Delete the default feedback object */
194 assert(ctx->Driver.DeleteTransformFeedback);
195 ctx->Driver.DeleteTransformFeedback(ctx,
196 ctx->TransformFeedback.DefaultObject);
197
198 ctx->TransformFeedback.CurrentObject = NULL;
199 }
200
201
202 /** Default fallback for ctx->Driver.NewTransformFeedback() */
203 static struct gl_transform_feedback_object *
204 new_transform_feedback(GLcontext *ctx, GLuint name)
205 {
206 struct gl_transform_feedback_object *obj;
207 obj = CALLOC_STRUCT(gl_transform_feedback_object);
208 if (obj) {
209 obj->Name = name;
210 obj->RefCount = 1;
211 }
212 return obj;
213 }
214
215 /** Default fallback for ctx->Driver.DeleteTransformFeedback() */
216 static void
217 delete_transform_feedback(GLcontext *ctx,
218 struct gl_transform_feedback_object *obj)
219 {
220 GLuint i;
221
222 for (i = 0; i < Elements(obj->Buffers); i++) {
223 _mesa_reference_buffer_object(ctx, &obj->Buffers[i], NULL);
224 }
225
226 free(obj);
227 }
228
229 /** Default fallback for ctx->Driver.BeginTransformFeedback() */
230 static void
231 begin_transform_feedback(GLcontext *ctx, GLenum mode,
232 struct gl_transform_feedback_object *obj)
233 {
234 /* nop */
235 }
236
237 /** Default fallback for ctx->Driver.EndTransformFeedback() */
238 static void
239 end_transform_feedback(GLcontext *ctx,
240 struct gl_transform_feedback_object *obj)
241 {
242 /* nop */
243 }
244
245 /** Default fallback for ctx->Driver.PauseTransformFeedback() */
246 static void
247 pause_transform_feedback(GLcontext *ctx,
248 struct gl_transform_feedback_object *obj)
249 {
250 /* nop */
251 }
252
253 /** Default fallback for ctx->Driver.ResumeTransformFeedback() */
254 static void
255 resume_transform_feedback(GLcontext *ctx,
256 struct gl_transform_feedback_object *obj)
257 {
258 /* nop */
259 }
260
261 /** Default fallback for ctx->Driver.DrawTransformFeedback() */
262 static void
263 draw_transform_feedback(GLcontext *ctx, GLenum mode,
264 struct gl_transform_feedback_object *obj)
265 {
266 /* XXX to do */
267 /*
268 * Get number of vertices in obj's feedback buffer.
269 * Call ctx->Exec.DrawArrays(mode, 0, count);
270 */
271 }
272
273
274 /**
275 * Plug in default device driver functions for transform feedback.
276 * Most drivers will override some/all of these.
277 */
278 void
279 _mesa_init_transform_feedback_functions(struct dd_function_table *driver)
280 {
281 driver->NewTransformFeedback = new_transform_feedback;
282 driver->DeleteTransformFeedback = delete_transform_feedback;
283 driver->BeginTransformFeedback = begin_transform_feedback;
284 driver->EndTransformFeedback = end_transform_feedback;
285 driver->PauseTransformFeedback = pause_transform_feedback;
286 driver->ResumeTransformFeedback = resume_transform_feedback;
287 driver->DrawTransformFeedback = draw_transform_feedback;
288 }
289
290
291 void
292 _mesa_init_transform_feedback_dispatch(struct _glapi_table *disp)
293 {
294 SET_BeginTransformFeedbackEXT(disp, _mesa_BeginTransformFeedback);
295 SET_EndTransformFeedbackEXT(disp, _mesa_EndTransformFeedback);
296 SET_BindBufferRangeEXT(disp, _mesa_BindBufferRange);
297 SET_BindBufferBaseEXT(disp, _mesa_BindBufferBase);
298 SET_BindBufferOffsetEXT(disp, _mesa_BindBufferOffsetEXT);
299 SET_TransformFeedbackVaryingsEXT(disp, _mesa_TransformFeedbackVaryings);
300 SET_GetTransformFeedbackVaryingEXT(disp, _mesa_GetTransformFeedbackVarying);
301 }
302
303
304 /**
305 ** Begin API functions
306 **/
307
308
309 void GLAPIENTRY
310 _mesa_BeginTransformFeedback(GLenum mode)
311 {
312 struct gl_transform_feedback_object *obj;
313 GET_CURRENT_CONTEXT(ctx);
314
315 obj = ctx->TransformFeedback.CurrentObject;
316
317 switch (mode) {
318 case GL_POINTS:
319 case GL_LINES:
320 case GL_TRIANGLES:
321 /* legal */
322 break;
323 default:
324 _mesa_error(ctx, GL_INVALID_ENUM, "glBeginTransformFeedback(mode)");
325 return;
326 }
327
328 if (obj->Active) {
329 _mesa_error(ctx, GL_INVALID_OPERATION,
330 "glBeginTransformFeedback(already active)");
331 return;
332 }
333
334 obj->Active = GL_TRUE;
335 ctx->TransformFeedback.Mode = mode;
336
337 assert(ctx->Driver.BeginTransformFeedback);
338 ctx->Driver.BeginTransformFeedback(ctx, mode, obj);
339 }
340
341
342 void GLAPIENTRY
343 _mesa_EndTransformFeedback(void)
344 {
345 struct gl_transform_feedback_object *obj;
346 GET_CURRENT_CONTEXT(ctx);
347
348 obj = ctx->TransformFeedback.CurrentObject;
349
350 if (!obj->Active) {
351 _mesa_error(ctx, GL_INVALID_OPERATION,
352 "glEndTransformFeedback(not active)");
353 return;
354 }
355
356 ctx->TransformFeedback.CurrentObject->Active = GL_FALSE;
357
358 assert(ctx->Driver.EndTransformFeedback);
359 ctx->Driver.EndTransformFeedback(ctx, obj);
360 }
361
362
363 /**
364 * Helper used by BindBufferRange() and BindBufferBase().
365 */
366 static void
367 bind_buffer_range(GLcontext *ctx, GLuint index,
368 struct gl_buffer_object *bufObj,
369 GLintptr offset, GLsizeiptr size)
370 {
371 struct gl_transform_feedback_object *obj =
372 ctx->TransformFeedback.CurrentObject;
373
374 /* The general binding point */
375 _mesa_reference_buffer_object(ctx,
376 &ctx->TransformFeedback.CurrentBuffer,
377 bufObj);
378
379 /* The per-attribute binding point */
380 _mesa_reference_buffer_object(ctx,
381 &obj->Buffers[index],
382 bufObj);
383
384 obj->BufferNames[index] = bufObj->Name;
385
386 obj->Offset[index] = offset;
387 obj->Size[index] = size;
388 }
389
390
391 /**
392 * Specify a buffer object to receive vertex shader results. Plus,
393 * specify the starting offset to place the results, and max size.
394 */
395 void GLAPIENTRY
396 _mesa_BindBufferRange(GLenum target, GLuint index,
397 GLuint buffer, GLintptr offset, GLsizeiptr size)
398 {
399 struct gl_transform_feedback_object *obj;
400 struct gl_buffer_object *bufObj;
401 GET_CURRENT_CONTEXT(ctx);
402
403 if (target != GL_TRANSFORM_FEEDBACK_BUFFER) {
404 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferRange(target)");
405 return;
406 }
407
408 obj = ctx->TransformFeedback.CurrentObject;
409
410 if (obj->Active) {
411 _mesa_error(ctx, GL_INVALID_OPERATION,
412 "glBindBufferRange(transform feedback active)");
413 return;
414 }
415
416 if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) {
417 _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index);
418 return;
419 }
420
421 if ((size <= 0) || (size & 0x3)) {
422 /* must be positive and multiple of four */
423 _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(size%d)", size);
424 return;
425 }
426
427 if (offset & 0x3) {
428 /* must be multiple of four */
429 _mesa_error(ctx, GL_INVALID_VALUE,
430 "glBindBufferRange(offset=%d)", offset);
431 return;
432 }
433
434 bufObj = _mesa_lookup_bufferobj(ctx, buffer);
435 if (!bufObj) {
436 _mesa_error(ctx, GL_INVALID_OPERATION,
437 "glBindBufferRange(invalid buffer=%u)", buffer);
438 return;
439 }
440
441 if (offset + size >= bufObj->Size) {
442 _mesa_error(ctx, GL_INVALID_VALUE,
443 "glBindBufferRange(offset + size > buffer size)", size);
444 return;
445 }
446
447 bind_buffer_range(ctx, index, bufObj, offset, size);
448 }
449
450
451 /**
452 * Specify a buffer object to receive vertex shader results.
453 * As above, but start at offset = 0.
454 */
455 void GLAPIENTRY
456 _mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer)
457 {
458 struct gl_transform_feedback_object *obj;
459 struct gl_buffer_object *bufObj;
460 GLsizeiptr size;
461 GET_CURRENT_CONTEXT(ctx);
462
463 if (target != GL_TRANSFORM_FEEDBACK_BUFFER) {
464 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferBase(target)");
465 return;
466 }
467
468 obj = ctx->TransformFeedback.CurrentObject;
469
470 if (obj->Active) {
471 _mesa_error(ctx, GL_INVALID_OPERATION,
472 "glBindBufferRange(transform feedback active)");
473 return;
474 }
475
476 if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) {
477 _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index);
478 return;
479 }
480
481 bufObj = _mesa_lookup_bufferobj(ctx, buffer);
482 if (!bufObj) {
483 _mesa_error(ctx, GL_INVALID_OPERATION,
484 "glBindBufferBase(invalid buffer=%u)", buffer);
485 return;
486 }
487
488 /* default size is the buffer size rounded down to nearest
489 * multiple of four.
490 */
491 size = bufObj->Size & ~0x3;
492
493 bind_buffer_range(ctx, index, bufObj, 0, size);
494 }
495
496
497 /**
498 * Specify a buffer object to receive vertex shader results, plus the
499 * offset in the buffer to start placing results.
500 * This function is part of GL_EXT_transform_feedback, but not GL3.
501 */
502 void GLAPIENTRY
503 _mesa_BindBufferOffsetEXT(GLenum target, GLuint index, GLuint buffer,
504 GLintptr offset)
505 {
506 struct gl_transform_feedback_object *obj;
507 struct gl_buffer_object *bufObj;
508 GET_CURRENT_CONTEXT(ctx);
509 GLsizeiptr size;
510
511 if (target != GL_TRANSFORM_FEEDBACK_BUFFER) {
512 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferOffsetEXT(target)");
513 return;
514 }
515
516 obj = ctx->TransformFeedback.CurrentObject;
517
518 if (obj->Active) {
519 _mesa_error(ctx, GL_INVALID_OPERATION,
520 "glBindBufferRange(transform feedback active)");
521 return;
522 }
523
524 if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) {
525 _mesa_error(ctx, GL_INVALID_VALUE,
526 "glBindBufferOffsetEXT(index=%d)", index);
527 return;
528 }
529
530 bufObj = _mesa_lookup_bufferobj(ctx, buffer);
531 if (!bufObj) {
532 _mesa_error(ctx, GL_INVALID_OPERATION,
533 "glBindBufferOffsetEXT(invalid buffer=%u)", buffer);
534 return;
535 }
536
537 /* default size is the buffer size rounded down to nearest
538 * multiple of four.
539 */
540 size = (bufObj->Size - offset) & ~0x3;
541
542 bind_buffer_range(ctx, index, bufObj, offset, size);
543 }
544
545
546 /**
547 * This function specifies the vertex shader outputs to be written
548 * to the feedback buffer(s), and in what order.
549 */
550 void GLAPIENTRY
551 _mesa_TransformFeedbackVaryings(GLuint program, GLsizei count,
552 const GLchar **varyings, GLenum bufferMode)
553 {
554 struct gl_shader_program *shProg;
555 GLuint i;
556 GET_CURRENT_CONTEXT(ctx);
557
558 switch (bufferMode) {
559 case GL_INTERLEAVED_ATTRIBS:
560 break;
561 case GL_SEPARATE_ATTRIBS:
562 break;
563 default:
564 _mesa_error(ctx, GL_INVALID_ENUM,
565 "glTransformFeedbackVaryings(bufferMode)");
566 return;
567 }
568
569 if (count < 0 || count > ctx->Const.MaxTransformFeedbackSeparateAttribs) {
570 _mesa_error(ctx, GL_INVALID_VALUE,
571 "glTransformFeedbackVaryings(count=%d)", count);
572 return;
573 }
574
575 shProg = _mesa_lookup_shader_program(ctx, program);
576 if (!shProg) {
577 _mesa_error(ctx, GL_INVALID_VALUE,
578 "glTransformFeedbackVaryings(program=%u)", program);
579 return;
580 }
581
582 /* free existing varyings, if any */
583 for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) {
584 free(shProg->TransformFeedback.VaryingNames[i]);
585 }
586 free(shProg->TransformFeedback.VaryingNames);
587
588 /* allocate new memory for varying names */
589 shProg->TransformFeedback.VaryingNames =
590 (GLchar **) malloc(count * sizeof(GLchar *));
591
592 if (!shProg->TransformFeedback.VaryingNames) {
593 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTransformFeedbackVaryings()");
594 return;
595 }
596
597 /* Save the new names and the count */
598 for (i = 0; i < (GLuint) count; i++) {
599 shProg->TransformFeedback.VaryingNames[i] = _mesa_strdup(varyings[i]);
600 }
601 shProg->TransformFeedback.NumVarying = count;
602
603 shProg->TransformFeedback.BufferMode = bufferMode;
604
605 /* The varyings won't be used until shader link time */
606 }
607
608
609 /**
610 * Get info about the vertex shader's outputs which are to be written
611 * to the feedback buffer(s).
612 */
613 void GLAPIENTRY
614 _mesa_GetTransformFeedbackVarying(GLuint program, GLuint index,
615 GLsizei bufSize, GLsizei *length,
616 GLsizei *size, GLenum *type, GLchar *name)
617 {
618 const struct gl_shader_program *shProg;
619 const GLchar *varyingName;
620 GLint v;
621 GET_CURRENT_CONTEXT(ctx);
622
623 shProg = _mesa_lookup_shader_program(ctx, program);
624 if (!shProg) {
625 _mesa_error(ctx, GL_INVALID_VALUE,
626 "glGetTransformFeedbackVaryings(program=%u)", program);
627 return;
628 }
629
630 if (index >= shProg->TransformFeedback.NumVarying) {
631 _mesa_error(ctx, GL_INVALID_VALUE,
632 "glGetTransformFeedbackVaryings(index=%u)", index);
633 return;
634 }
635
636 varyingName = shProg->TransformFeedback.VaryingNames[index];
637
638 v = _mesa_lookup_parameter_index(shProg->Varying, -1, varyingName);
639 if (v >= 0) {
640 struct gl_program_parameter *param = &shProg->Varying->Parameters[v];
641
642 /* return the varying's name and length */
643 _mesa_copy_string(name, bufSize, length, varyingName);
644
645 /* return the datatype and value's size (in datatype units) */
646 if (type)
647 *type = param->DataType;
648 if (size)
649 *size = param->Size;
650 }
651 else {
652 name[0] = 0;
653 if (length)
654 *length = 0;
655 if (type)
656 *type = 0;
657 if (size)
658 *size = 0;
659 }
660 }
661
662
663
664 static struct gl_transform_feedback_object *
665 lookup_transform_feedback_object(GLcontext *ctx, GLuint name)
666 {
667 if (name == 0) {
668 return ctx->TransformFeedback.DefaultObject;
669 }
670 else
671 return (struct gl_transform_feedback_object *)
672 _mesa_HashLookup(ctx->TransformFeedback.Objects, name);
673 }
674
675
676 /**
677 * Create new transform feedback objects. Transform feedback objects
678 * encapsulate the state related to transform feedback to allow quickly
679 * switching state (and drawing the results, below).
680 * Part of GL_ARB_transform_feedback2.
681 */
682 void GLAPIENTRY
683 _mesa_GenTransformFeedbacks(GLsizei n, GLuint *names)
684 {
685 GLuint first;
686 GET_CURRENT_CONTEXT(ctx);
687
688 ASSERT_OUTSIDE_BEGIN_END(ctx);
689
690 if (n < 0) {
691 _mesa_error(ctx, GL_INVALID_VALUE, "glGenTransformFeedbacks(n < 0)");
692 return;
693 }
694
695 if (!names)
696 return;
697
698 /* we don't need contiguous IDs, but this might be faster */
699 first = _mesa_HashFindFreeKeyBlock(ctx->TransformFeedback.Objects, n);
700 if (first) {
701 GLsizei i;
702 for (i = 0; i < n; i++) {
703 struct gl_transform_feedback_object *obj
704 = ctx->Driver.NewTransformFeedback(ctx, first + i);
705 if (!obj) {
706 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTransformFeedbacks");
707 return;
708 }
709 names[i] = first + i;
710 _mesa_HashInsert(ctx->TransformFeedback.Objects, first + i, obj);
711 }
712 }
713 else {
714 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTransformFeedbacks");
715 }
716 }
717
718
719 /**
720 * Is the given ID a transform feedback object?
721 * Part of GL_ARB_transform_feedback2.
722 */
723 GLboolean GLAPIENTRY
724 _mesa_IsTransformFeedback(GLuint name)
725 {
726 GET_CURRENT_CONTEXT(ctx);
727
728 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
729
730 if (name && lookup_transform_feedback_object(ctx, name))
731 return GL_TRUE;
732 else
733 return GL_FALSE;
734 }
735
736
737 /**
738 * Bind the given transform feedback object.
739 * Part of GL_ARB_transform_feedback2.
740 */
741 void GLAPIENTRY
742 _mesa_BindTransformFeedback(GLenum target, GLuint name)
743 {
744 struct gl_transform_feedback_object *obj;
745 GET_CURRENT_CONTEXT(ctx);
746
747 if (target != GL_TRANSFORM_FEEDBACK) {
748 _mesa_error(ctx, GL_INVALID_ENUM, "glBindTransformFeedback(target)");
749 return;
750 }
751
752 if (ctx->TransformFeedback.CurrentObject->Active &&
753 !ctx->TransformFeedback.CurrentObject->Paused) {
754 _mesa_error(ctx, GL_INVALID_OPERATION,
755 "glBindTransformFeedback(transform is active, or not paused)");
756 return;
757 }
758
759 obj = lookup_transform_feedback_object(ctx, name);
760 if (!obj) {
761 _mesa_error(ctx, GL_INVALID_OPERATION,
762 "glBindTransformFeedback(name=%u)", name);
763 return;
764 }
765
766 reference_transform_feedback_object(&ctx->TransformFeedback.CurrentObject,
767 obj);
768 }
769
770
771 /**
772 * Delete the given transform feedback objects.
773 * Part of GL_ARB_transform_feedback2.
774 */
775 void GLAPIENTRY
776 _mesa_DeleteTransformFeedbacks(GLsizei n, const GLuint *names)
777 {
778 GLint i;
779 GET_CURRENT_CONTEXT(ctx);
780
781 ASSERT_OUTSIDE_BEGIN_END(ctx);
782
783 if (n < 0) {
784 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteTransformFeedbacks(n < 0)");
785 return;
786 }
787
788 if (!names)
789 return;
790
791 for (i = 0; i < n; i++) {
792 if (names[i] > 0) {
793 struct gl_transform_feedback_object *obj
794 = lookup_transform_feedback_object(ctx, names[i]);
795 if (obj) {
796 if (obj->Active) {
797 _mesa_error(ctx, GL_INVALID_OPERATION,
798 "glDeleteTransformFeedbacks(object %u is active)",
799 names[i]);
800 return;
801 }
802 _mesa_HashRemove(ctx->TransformFeedback.Objects, names[i]);
803 /* unref, but object may not be deleted until later */
804 reference_transform_feedback_object(&obj, NULL);
805 }
806 }
807 }
808 }
809
810
811 /**
812 * Pause transform feedback.
813 * Part of GL_ARB_transform_feedback2.
814 */
815 void GLAPIENTRY
816 _mesa_PauseTransformFeedback(void)
817 {
818 struct gl_transform_feedback_object *obj;
819 GET_CURRENT_CONTEXT(ctx);
820
821 obj = ctx->TransformFeedback.CurrentObject;
822
823 if (!obj->Active || obj->Paused) {
824 _mesa_error(ctx, GL_INVALID_OPERATION,
825 "glPauseTransformFeedback(feedback not active or already paused)");
826 return;
827 }
828
829 obj->Paused = GL_TRUE;
830
831 assert(ctx->Driver.PauseTransformFeedback);
832 ctx->Driver.PauseTransformFeedback(ctx, obj);
833 }
834
835
836 /**
837 * Resume transform feedback.
838 * Part of GL_ARB_transform_feedback2.
839 */
840 void GLAPIENTRY
841 _mesa_ResumeTransformFeedback(void)
842 {
843 struct gl_transform_feedback_object *obj;
844 GET_CURRENT_CONTEXT(ctx);
845
846 obj = ctx->TransformFeedback.CurrentObject;
847
848 if (!obj->Active || !obj->Paused) {
849 _mesa_error(ctx, GL_INVALID_OPERATION,
850 "glPauseTransformFeedback(feedback not active or not paused)");
851 return;
852 }
853
854 obj->Paused = GL_FALSE;
855
856 assert(ctx->Driver.ResumeTransformFeedback);
857 ctx->Driver.ResumeTransformFeedback(ctx, obj);
858 }
859
860
861 /**
862 * Draw the vertex data in a transform feedback object.
863 * \param mode GL_POINTS, GL_LINES, GL_TRIANGLE_STRIP, etc.
864 * \param name the transform feedback object
865 * The number of vertices comes from the transform feedback object.
866 * User still has to setup of the vertex attribute info with
867 * glVertexPointer, glColorPointer, etc.
868 * Part of GL_ARB_transform_feedback2.
869 */
870 void GLAPIENTRY
871 _mesa_DrawTransformFeedback(GLenum mode, GLuint name)
872 {
873 GET_CURRENT_CONTEXT(ctx);
874 struct gl_transform_feedback_object *obj =
875 lookup_transform_feedback_object(ctx, name);
876
877 if (mode > GL_POLYGON) {
878 _mesa_error(ctx, GL_INVALID_ENUM,
879 "glDrawTransformFeedback(mode=0x%x)", mode);
880 return;
881 }
882 if (!obj) {
883 _mesa_error(ctx, GL_INVALID_VALUE,
884 "glDrawTransformFeedback(name = %u)", name);
885 return;
886 }
887
888 /* XXX check if EndTransformFeedback has never been called while
889 * the object was bound
890 */
891
892 assert(ctx->Driver.DrawTransformFeedback);
893 ctx->Driver.DrawTransformFeedback(ctx, mode, obj);
894 }
895
896
897 /*
898 XXX misc to do:
899
900 glGet*() for
901
902 GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED
903 GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE
904 GL_TRANSFORM_FEEDBACK_BINDING
905 */
906
907
908 #endif /* FEATURE_EXT_transform_feedback */