summaryrefslogtreecommitdiffstats
path: root/src/mesa/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/main')
-rw-r--r--src/mesa/main/bufferobj.c9
-rw-r--r--src/mesa/main/config.h5
-rw-r--r--src/mesa/main/context.c10
-rw-r--r--src/mesa/main/enable.c16
-rw-r--r--src/mesa/main/extensions.c6
-rw-r--r--src/mesa/main/fbobject.c2
-rw-r--r--src/mesa/main/get.c152
-rw-r--r--src/mesa/main/get_gen.py33
-rw-r--r--src/mesa/main/hash.c36
-rw-r--r--src/mesa/main/mfeatures.h124
-rw-r--r--src/mesa/main/mtypes.h43
-rw-r--r--src/mesa/main/queryobj.c130
-rw-r--r--src/mesa/main/texparam.c8
-rw-r--r--src/mesa/main/transformfeedback.c427
-rw-r--r--src/mesa/main/transformfeedback.h71
15 files changed, 930 insertions, 142 deletions
diff --git a/src/mesa/main/bufferobj.c b/src/mesa/main/bufferobj.c
index 1854b980beb..235cafcf1ed 100644
--- a/src/mesa/main/bufferobj.c
+++ b/src/mesa/main/bufferobj.c
@@ -47,7 +47,7 @@
/*#define BOUNDS_CHECK*/
-#ifdef FEATURE_OES_mapbuffer
+#if FEATURE_OES_mapbuffer
#define DEFAULT_ACCESS GL_MAP_WRITE_BIT
#else
#define DEFAULT_ACCESS (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)
@@ -83,6 +83,13 @@ get_buffer_target(GLcontext *ctx, GLenum target)
return &ctx->CopyWriteBuffer;
}
break;
+#if FEATURE_EXT_transform_feedback
+ case GL_TRANSFORM_FEEDBACK_BUFFER:
+ if (ctx->Extensions.EXT_transform_feedback) {
+ return &ctx->TransformFeedback.CurrentBuffer;
+ }
+ break;
+#endif
default:
return NULL;
}
diff --git a/src/mesa/main/config.h b/src/mesa/main/config.h
index 2eac1cc2ed9..30b48e4bd08 100644
--- a/src/mesa/main/config.h
+++ b/src/mesa/main/config.h
@@ -262,6 +262,11 @@
/** For GL_ATI_envmap_bump - support bump mapping on first 8 units */
#define SUPPORTED_ATI_BUMP_UNITS 0xff
+/** For GL_EXT_transform_feedback */
+#define MAX_FEEDBACK_ATTRIBS 32
+
+
+
/**
* \name Mesa-specific parameters
*/
diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c
index 73126b95755..2074b32b250 100644
--- a/src/mesa/main/context.c
+++ b/src/mesa/main/context.c
@@ -123,6 +123,7 @@
#include "stencil.h"
#include "texcompress_s3tc.h"
#include "texstate.h"
+#include "transformfeedback.h"
#include "mtypes.h"
#include "varray.h"
#include "version.h"
@@ -560,6 +561,11 @@ _mesa_init_constants(GLcontext *ctx)
/* GL_EXT_provoking_vertex */
ctx->Const.QuadsFollowProvokingVertexConvention = GL_TRUE;
+
+ /* GL_EXT_transform_feedback */
+ ctx->Const.MaxTransformFeedbackSeparateAttribs = MAX_FEEDBACK_ATTRIBS;
+ ctx->Const.MaxTransformFeedbackSeparateComponents = 4 * MAX_FEEDBACK_ATTRIBS;
+ ctx->Const.MaxTransformFeedbackInterleavedComponents = 4 * MAX_FEEDBACK_ATTRIBS;
}
@@ -684,6 +690,7 @@ init_attrib_groups(GLcontext *ctx)
_mesa_init_shader_state( ctx );
_mesa_init_stencil( ctx );
_mesa_init_transform( ctx );
+ _mesa_init_transform_feedback( ctx );
_mesa_init_varray( ctx );
_mesa_init_viewport( ctx );
@@ -873,7 +880,7 @@ _mesa_initialize_context(GLcontext *ctx,
ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE;
}
-#ifdef FEATURE_extra_context_init
+#if FEATURE_extra_context_init
_mesa_initialize_context_extra(ctx);
#endif
@@ -969,6 +976,7 @@ _mesa_free_context_data( GLcontext *ctx )
_mesa_free_sync_data(ctx);
#endif
_mesa_free_varray_data(ctx);
+ _mesa_free_transform_feedback(ctx);
_mesa_delete_array_object(ctx, ctx->Array.DefaultArrayObj);
diff --git a/src/mesa/main/enable.c b/src/mesa/main/enable.c
index f5c88a63e6e..f9decc31ab7 100644
--- a/src/mesa/main/enable.c
+++ b/src/mesa/main/enable.c
@@ -982,6 +982,16 @@ _mesa_set_enable(GLcontext *ctx, GLenum cap, GLboolean state)
ctx->Texture.CubeMapSeamless = state;
break;
+#if FEATURE_EXT_transform_feedback
+ case GL_RASTERIZER_DISCARD:
+ CHECK_EXTENSION(EXT_transform_feedback, cap);
+ if (ctx->TransformFeedback.RasterDiscard != state) {
+ ctx->TransformFeedback.RasterDiscard = state;
+ FLUSH_VERTICES(ctx, _NEW_TRANSFORM);
+ }
+ break;
+#endif
+
default:
_mesa_error(ctx, GL_INVALID_ENUM,
"%s(0x%x)", state ? "glEnable" : "glDisable", cap);
@@ -1493,6 +1503,12 @@ _mesa_IsEnabled( GLenum cap )
CHECK_EXTENSION(ARB_seamless_cube_map);
return ctx->Texture.CubeMapSeamless;
+#if FEATURE_EXT_transform_feedback
+ case GL_RASTERIZER_DISCARD:
+ CHECK_EXTENSION(EXT_transform_feedback);
+ return ctx->TransformFeedback.RasterDiscard;
+#endif
+
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glIsEnabled(0x%x)", (int) cap);
return GL_FALSE;
diff --git a/src/mesa/main/extensions.c b/src/mesa/main/extensions.c
index 30245d6aafa..f7b0e5abf59 100644
--- a/src/mesa/main/extensions.c
+++ b/src/mesa/main/extensions.c
@@ -146,6 +146,7 @@ static const struct {
{ OFF, "GL_EXT_texture_sRGB", F(EXT_texture_sRGB) },
{ OFF, "GL_EXT_texture_swizzle", F(EXT_texture_swizzle) },
{ OFF, "GL_EXT_timer_query", F(EXT_timer_query) },
+ { OFF, "GL_EXT_transform_feedback", F(EXT_transform_feedback) },
{ ON, "GL_EXT_vertex_array", F(EXT_vertex_array) },
{ OFF, "GL_EXT_vertex_array_bgra", F(EXT_vertex_array_bgra) },
{ OFF, "GL_EXT_vertex_array_set", F(EXT_vertex_array_set) },
@@ -319,6 +320,9 @@ _mesa_enable_sw_extensions(GLcontext *ctx)
ctx->Extensions.EXT_texture_sRGB = GL_TRUE;
#endif
ctx->Extensions.EXT_texture_swizzle = GL_TRUE;
+#if FEATURE_EXT_transform_feedback
+ ctx->Extensions.EXT_transform_feedback = GL_TRUE;
+#endif
ctx->Extensions.EXT_vertex_array_bgra = GL_TRUE;
/*ctx->Extensions.IBM_multimode_draw_arrays = GL_TRUE;*/
ctx->Extensions.MESA_pack_invert = GL_TRUE;
@@ -480,7 +484,7 @@ _mesa_enable_2_1_extensions(GLcontext *ctx)
#if FEATURE_EXT_texture_sRGB
ctx->Extensions.EXT_texture_sRGB = GL_TRUE;
#endif
-#ifdef FEATURE_ARB_shading_language_120
+#if FEATURE_ARB_shading_language_120
ctx->Extensions.ARB_shading_language_120 = GL_TRUE;
#endif
}
diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c
index 07827348694..e3e006bb948 100644
--- a/src/mesa/main/fbobject.c
+++ b/src/mesa/main/fbobject.c
@@ -629,7 +629,7 @@ _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb)
}
}
-#ifndef FEATURE_OES_framebuffer_object
+#if !FEATURE_OES_framebuffer_object
/* Check that all DrawBuffers are present */
for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) {
if (fb->ColorDrawBuffer[j] != GL_NONE) {
diff --git a/src/mesa/main/get.c b/src/mesa/main/get.c
index 266fda40ec5..eaa6d7f7307 100644
--- a/src/mesa/main/get.c
+++ b/src/mesa/main/get.c
@@ -1922,6 +1922,26 @@ _mesa_GetBooleanv( GLenum pname, GLboolean *params )
CHECK_EXT1(ARB_sync, "GetBooleanv");
params[0] = INT64_TO_BOOLEAN(ctx->Const.MaxServerWaitTimeout);
break;
+ case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
+ CHECK_EXT1(EXT_transform_feedback, "GetBooleanv");
+ params[0] = INT_TO_BOOLEAN(ctx->TransformFeedback.CurrentBuffer->Name);
+ break;
+ case GL_RASTERIZER_DISCARD:
+ CHECK_EXT1(EXT_transform_feedback, "GetBooleanv");
+ params[0] = ctx->TransformFeedback.RasterDiscard;
+ break;
+ case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:
+ CHECK_EXT1(EXT_transform_feedback, "GetBooleanv");
+ params[0] = INT_TO_BOOLEAN(ctx->Const.MaxTransformFeedbackInterleavedComponents);
+ break;
+ case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
+ CHECK_EXT1(EXT_transform_feedback, "GetBooleanv");
+ params[0] = INT_TO_BOOLEAN(ctx->Const.MaxTransformFeedbackSeparateAttribs);
+ break;
+ case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS:
+ CHECK_EXT1(EXT_transform_feedback, "GetBooleanv");
+ params[0] = INT_TO_BOOLEAN(ctx->Const.MaxTransformFeedbackSeparateComponents);
+ break;
case GL_NUM_EXTENSIONS:
params[0] = INT_TO_BOOLEAN(_mesa_get_extension_count(ctx));
break;
@@ -3793,6 +3813,26 @@ _mesa_GetFloatv( GLenum pname, GLfloat *params )
CHECK_EXT1(ARB_sync, "GetFloatv");
params[0] = (GLfloat)(ctx->Const.MaxServerWaitTimeout);
break;
+ case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
+ CHECK_EXT1(EXT_transform_feedback, "GetFloatv");
+ params[0] = (GLfloat)(ctx->TransformFeedback.CurrentBuffer->Name);
+ break;
+ case GL_RASTERIZER_DISCARD:
+ CHECK_EXT1(EXT_transform_feedback, "GetFloatv");
+ params[0] = BOOLEAN_TO_FLOAT(ctx->TransformFeedback.RasterDiscard);
+ break;
+ case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:
+ CHECK_EXT1(EXT_transform_feedback, "GetFloatv");
+ params[0] = (GLfloat)(ctx->Const.MaxTransformFeedbackInterleavedComponents);
+ break;
+ case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
+ CHECK_EXT1(EXT_transform_feedback, "GetFloatv");
+ params[0] = (GLfloat)(ctx->Const.MaxTransformFeedbackSeparateAttribs);
+ break;
+ case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS:
+ CHECK_EXT1(EXT_transform_feedback, "GetFloatv");
+ params[0] = (GLfloat)(ctx->Const.MaxTransformFeedbackSeparateComponents);
+ break;
case GL_NUM_EXTENSIONS:
params[0] = (GLfloat)(_mesa_get_extension_count(ctx));
break;
@@ -5664,6 +5704,26 @@ _mesa_GetIntegerv( GLenum pname, GLint *params )
CHECK_EXT1(ARB_sync, "GetIntegerv");
params[0] = INT64_TO_INT(ctx->Const.MaxServerWaitTimeout);
break;
+ case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
+ CHECK_EXT1(EXT_transform_feedback, "GetIntegerv");
+ params[0] = ctx->TransformFeedback.CurrentBuffer->Name;
+ break;
+ case GL_RASTERIZER_DISCARD:
+ CHECK_EXT1(EXT_transform_feedback, "GetIntegerv");
+ params[0] = BOOLEAN_TO_INT(ctx->TransformFeedback.RasterDiscard);
+ break;
+ case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:
+ CHECK_EXT1(EXT_transform_feedback, "GetIntegerv");
+ params[0] = ctx->Const.MaxTransformFeedbackInterleavedComponents;
+ break;
+ case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
+ CHECK_EXT1(EXT_transform_feedback, "GetIntegerv");
+ params[0] = ctx->Const.MaxTransformFeedbackSeparateAttribs;
+ break;
+ case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS:
+ CHECK_EXT1(EXT_transform_feedback, "GetIntegerv");
+ params[0] = ctx->Const.MaxTransformFeedbackSeparateComponents;
+ break;
case GL_NUM_EXTENSIONS:
params[0] = _mesa_get_extension_count(ctx);
break;
@@ -7536,6 +7596,26 @@ _mesa_GetInteger64v( GLenum pname, GLint64 *params )
CHECK_EXT1(ARB_sync, "GetInteger64v");
params[0] = ctx->Const.MaxServerWaitTimeout;
break;
+ case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
+ CHECK_EXT1(EXT_transform_feedback, "GetInteger64v");
+ params[0] = (GLint64)(ctx->TransformFeedback.CurrentBuffer->Name);
+ break;
+ case GL_RASTERIZER_DISCARD:
+ CHECK_EXT1(EXT_transform_feedback, "GetInteger64v");
+ params[0] = BOOLEAN_TO_INT64(ctx->TransformFeedback.RasterDiscard);
+ break;
+ case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:
+ CHECK_EXT1(EXT_transform_feedback, "GetInteger64v");
+ params[0] = (GLint64)(ctx->Const.MaxTransformFeedbackInterleavedComponents);
+ break;
+ case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
+ CHECK_EXT1(EXT_transform_feedback, "GetInteger64v");
+ params[0] = (GLint64)(ctx->Const.MaxTransformFeedbackSeparateAttribs);
+ break;
+ case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS:
+ CHECK_EXT1(EXT_transform_feedback, "GetInteger64v");
+ params[0] = (GLint64)(ctx->Const.MaxTransformFeedbackSeparateComponents);
+ break;
case GL_NUM_EXTENSIONS:
params[0] = (GLint64)(_mesa_get_extension_count(ctx));
break;
@@ -7606,6 +7686,30 @@ _mesa_GetBooleanIndexedv( GLenum pname, GLuint index, GLboolean *params )
params[2] = INT_TO_BOOLEAN(ctx->Color.ColorMask[index][BCOMP] ? 1 : 0);
params[3] = INT_TO_BOOLEAN(ctx->Color.ColorMask[index][ACOMP] ? 1 : 0);
break;
+ case GL_TRANSFORM_FEEDBACK_BUFFER_START:
+ CHECK_EXT1(EXT_transform_feedback, "GetBooleanIndexedv");
+ if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetBooleanIndexedv(index=%u), index", pname);
+ return;
+ }
+ params[0] = INT64_TO_BOOLEAN(ctx->TransformFeedback.Offset[index]);
+ break;
+ case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
+ CHECK_EXT1(EXT_transform_feedback, "GetBooleanIndexedv");
+ if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetBooleanIndexedv(index=%u), index", pname);
+ return;
+ }
+ params[0] = INT64_TO_BOOLEAN(ctx->TransformFeedback.Size[index]);
+ break;
+ case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
+ CHECK_EXT1(EXT_transform_feedback, "GetBooleanIndexedv");
+ if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetBooleanIndexedv(index=%u), index", pname);
+ return;
+ }
+ params[0] = INT_TO_BOOLEAN(ctx->TransformFeedback.Buffers[index]->Name);
+ break;
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glGetBooleanIndexedv(pname=0x%x)", pname);
}
@@ -7640,6 +7744,30 @@ _mesa_GetIntegerIndexedv( GLenum pname, GLuint index, GLint *params )
params[2] = ctx->Color.ColorMask[index][BCOMP] ? 1 : 0;
params[3] = ctx->Color.ColorMask[index][ACOMP] ? 1 : 0;
break;
+ case GL_TRANSFORM_FEEDBACK_BUFFER_START:
+ CHECK_EXT1(EXT_transform_feedback, "GetIntegerIndexedv");
+ if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetIntegerIndexedv(index=%u), index", pname);
+ return;
+ }
+ params[0] = INT64_TO_INT(ctx->TransformFeedback.Offset[index]);
+ break;
+ case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
+ CHECK_EXT1(EXT_transform_feedback, "GetIntegerIndexedv");
+ if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetIntegerIndexedv(index=%u), index", pname);
+ return;
+ }
+ params[0] = INT64_TO_INT(ctx->TransformFeedback.Size[index]);
+ break;
+ case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
+ CHECK_EXT1(EXT_transform_feedback, "GetIntegerIndexedv");
+ if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetIntegerIndexedv(index=%u), index", pname);
+ return;
+ }
+ params[0] = ctx->TransformFeedback.Buffers[index]->Name;
+ break;
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glGetIntegerIndexedv(pname=0x%x)", pname);
}
@@ -7675,6 +7803,30 @@ _mesa_GetInteger64Indexedv( GLenum pname, GLuint index, GLint64 *params )
params[2] = (GLint64)(ctx->Color.ColorMask[index][BCOMP] ? 1 : 0);
params[3] = (GLint64)(ctx->Color.ColorMask[index][ACOMP] ? 1 : 0);
break;
+ case GL_TRANSFORM_FEEDBACK_BUFFER_START:
+ CHECK_EXT1(EXT_transform_feedback, "GetInteger64Indexedv");
+ if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetInteger64Indexedv(index=%u), index", pname);
+ return;
+ }
+ params[0] = ctx->TransformFeedback.Offset[index];
+ break;
+ case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
+ CHECK_EXT1(EXT_transform_feedback, "GetInteger64Indexedv");
+ if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetInteger64Indexedv(index=%u), index", pname);
+ return;
+ }
+ params[0] = ctx->TransformFeedback.Size[index];
+ break;
+ case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
+ CHECK_EXT1(EXT_transform_feedback, "GetInteger64Indexedv");
+ if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetInteger64Indexedv(index=%u), index", pname);
+ return;
+ }
+ params[0] = (GLint64)(ctx->TransformFeedback.Buffers[index]->Name);
+ break;
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glGetInteger64Indexedv(pname=0x%x)", pname);
}
diff --git a/src/mesa/main/get_gen.py b/src/mesa/main/get_gen.py
index cecb86d76a1..bfaca1536d1 100644
--- a/src/mesa/main/get_gen.py
+++ b/src/mesa/main/get_gen.py
@@ -1122,6 +1122,23 @@ StateVars = [
( "GL_MAX_SERVER_WAIT_TIMEOUT", GLint64, ["ctx->Const.MaxServerWaitTimeout"], "",
NoState, ["ARB_sync"] ),
+ # GL_EXT_transform_feedback
+ ( "GL_TRANSFORM_FEEDBACK_BUFFER_BINDING", GLint,
+ ["ctx->TransformFeedback.CurrentBuffer->Name"], "",
+ NoState, ["EXT_transform_feedback"] ),
+ ( "GL_RASTERIZER_DISCARD", GLboolean,
+ ["ctx->TransformFeedback.RasterDiscard"], "",
+ NoState, ["EXT_transform_feedback"] ),
+ ( "GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS", GLint,
+ ["ctx->Const.MaxTransformFeedbackInterleavedComponents"], "",
+ NoState, ["EXT_transform_feedback"] ),
+ ( "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS", GLint,
+ ["ctx->Const.MaxTransformFeedbackSeparateAttribs"], "",
+ NoState, ["EXT_transform_feedback"] ),
+ ( "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS", GLint,
+ ["ctx->Const.MaxTransformFeedbackSeparateComponents"], "",
+ NoState, ["EXT_transform_feedback"] ),
+
# GL3
( "GL_NUM_EXTENSIONS", GLint, ["_mesa_get_extension_count(ctx)"], "", NoState, NoExt ),
( "GL_MAJOR_VERSION", GLint, ["ctx->VersionMajor"], "", NoState, NoExt ),
@@ -1134,6 +1151,7 @@ StateVars = [
# The tuples are the same as above, with one exception: the "optional"
# code field is instead the max legal index value.
IndexedStateVars = [
+ # GL_EXT_draw_buffers2 / GL3
( "GL_BLEND", GLint, ["((ctx->Color.BlendEnabled >> index) & 1)"],
"ctx->Const.MaxDrawBuffers", NoState, ["EXT_draw_buffers2"] ),
( "GL_COLOR_WRITEMASK", GLint,
@@ -1142,6 +1160,21 @@ IndexedStateVars = [
"ctx->Color.ColorMask[index][BCOMP] ? 1 : 0",
"ctx->Color.ColorMask[index][ACOMP] ? 1 : 0" ],
"ctx->Const.MaxDrawBuffers", NoState, ["EXT_draw_buffers2"] ),
+
+ # GL_EXT_transform_feedback
+ ( "GL_TRANSFORM_FEEDBACK_BUFFER_START", GLint64,
+ ["ctx->TransformFeedback.Offset[index]"],
+ "ctx->Const.MaxTransformFeedbackSeparateAttribs",
+ NoState, ["EXT_transform_feedback"] ),
+ ( "GL_TRANSFORM_FEEDBACK_BUFFER_SIZE", GLint64,
+ ["ctx->TransformFeedback.Size[index]"],
+ "ctx->Const.MaxTransformFeedbackSeparateAttribs",
+ NoState, ["EXT_transform_feedback"] ),
+ ( "GL_TRANSFORM_FEEDBACK_BUFFER_BINDING", GLint,
+ ["ctx->TransformFeedback.Buffers[index]->Name"],
+ "ctx->Const.MaxTransformFeedbackSeparateAttribs",
+ NoState, ["EXT_transform_feedback"] ),
+
# XXX more to come...
]
diff --git a/src/mesa/main/hash.c b/src/mesa/main/hash.c
index 975775469d9..b624e6ecac1 100644
--- a/src/mesa/main/hash.c
+++ b/src/mesa/main/hash.c
@@ -120,15 +120,11 @@ _mesa_DeleteHashTable(struct _mesa_HashTable *table)
/**
- * Lookup an entry in the hash table.
- *
- * \param table the hash table.
- * \param key the key.
- *
- * \return pointer to user's data or NULL if key not in table
+ * Lookup an entry in the hash table, without locking.
+ * \sa _mesa_HashLookup
*/
-void *
-_mesa_HashLookup(struct _mesa_HashTable *table, GLuint key)
+static INLINE void *
+_mesa_HashLookup_unlocked(struct _mesa_HashTable *table, GLuint key)
{
GLuint pos;
const struct HashEntry *entry;
@@ -137,20 +133,36 @@ _mesa_HashLookup(struct _mesa_HashTable *table, GLuint key)
assert(key);
pos = HASH_FUNC(key);
- _glthread_LOCK_MUTEX(table->Mutex);
entry = table->Table[pos];
while (entry) {
if (entry->Key == key) {
- _glthread_UNLOCK_MUTEX(table->Mutex);
return entry->Data;
}
entry = entry->Next;
}
- _glthread_UNLOCK_MUTEX(table->Mutex);
return NULL;
}
+/**
+ * Lookup an entry in the hash table.
+ *
+ * \param table the hash table.
+ * \param key the key.
+ *
+ * \return pointer to user's data or NULL if key not in table
+ */
+void *
+_mesa_HashLookup(struct _mesa_HashTable *table, GLuint key)
+{
+ void *res;
+ assert(table);
+ _glthread_LOCK_MUTEX(table->Mutex);
+ res = _mesa_HashLookup_unlocked(table, key);
+ _glthread_UNLOCK_MUTEX(table->Mutex);
+ return res;
+}
+
/**
* Insert a key/pointer pair into the hash table.
@@ -447,7 +459,7 @@ _mesa_HashFindFreeKeyBlock(struct _mesa_HashTable *table, GLuint numKeys)
GLuint freeStart = 1;
GLuint key;
for (key = 1; key != maxKey; key++) {
- if (_mesa_HashLookup(table, key)) {
+ if (_mesa_HashLookup_unlocked(table, key)) {
/* darn, this key is already in use */
freeCount = 0;
freeStart = key+1;
diff --git a/src/mesa/main/mfeatures.h b/src/mesa/main/mfeatures.h
index cb96c4d1d05..6ed05da7ac8 100644
--- a/src/mesa/main/mfeatures.h
+++ b/src/mesa/main/mfeatures.h
@@ -68,62 +68,84 @@
* enabled or not.
*/
+#ifndef FEATURE_ES1
+#define FEATURE_ES1 0
+#endif
+#ifndef FEATURE_ES2
+#define FEATURE_ES2 0
+#endif
+
+#define FEATURE_ES (FEATURE_ES1 || FEATURE_ES2)
+
+#ifndef FEATURE_GL
+#define FEATURE_GL !FEATURE_ES
+#endif
+
#ifdef IN_DRI_DRIVER
-#define FEATURE_remap_table 1
+#define FEATURE_remap_table 1
#else
-#define FEATURE_remap_table 0
+#define FEATURE_remap_table 0
#endif
-#define FEATURE_accum _HAVE_FULL_GL
-#define FEATURE_arrayelt _HAVE_FULL_GL
-#define FEATURE_attrib_stack _HAVE_FULL_GL
+#define FEATURE_dispatch 1
+#define FEATURE_texgen 1
+#define FEATURE_userclip 1
+
+#define FEATURE_accum FEATURE_GL
+#define FEATURE_arrayelt FEATURE_GL
+#define FEATURE_attrib_stack FEATURE_GL
/* this disables vtxfmt, api_loopback, and api_noop completely */
-#define FEATURE_beginend _HAVE_FULL_GL
-#define FEATURE_colortable _HAVE_FULL_GL
-#define FEATURE_convolve _HAVE_FULL_GL
-#define FEATURE_dispatch _HAVE_FULL_GL
-#define FEATURE_dlist (_HAVE_FULL_GL && FEATURE_arrayelt && FEATURE_beginend)
-#define FEATURE_draw_read_buffer _HAVE_FULL_GL
-#define FEATURE_drawpix _HAVE_FULL_GL
-#define FEATURE_evaluators _HAVE_FULL_GL
-#define FEATURE_feedback _HAVE_FULL_GL
-#define FEATURE_fixedpt 0
-#define FEATURE_histogram _HAVE_FULL_GL
-#define FEATURE_pixel_transfer _HAVE_FULL_GL
-#define FEATURE_point_size_array 0
-#define FEATURE_queryobj _HAVE_FULL_GL
-#define FEATURE_rastpos _HAVE_FULL_GL
-#define FEATURE_texgen _HAVE_FULL_GL
-#define FEATURE_texture_fxt1 _HAVE_FULL_GL
-#define FEATURE_texture_s3tc _HAVE_FULL_GL
-#define FEATURE_userclip _HAVE_FULL_GL
-#define FEATURE_vertex_array_byte 0
-#define FEATURE_es2_glsl 0
-
-#define FEATURE_ARB_fragment_program _HAVE_FULL_GL
-#define FEATURE_ARB_framebuffer_object _HAVE_FULL_GL
-#define FEATURE_ARB_map_buffer_range _HAVE_FULL_GL
-#define FEATURE_ARB_pixel_buffer_object _HAVE_FULL_GL
-#define FEATURE_ARB_vertex_buffer_object _HAVE_FULL_GL
-#define FEATURE_ARB_vertex_program _HAVE_FULL_GL
-#define FEATURE_ARB_vertex_shader _HAVE_FULL_GL
-#define FEATURE_ARB_fragment_shader _HAVE_FULL_GL
-#define FEATURE_ARB_shader_objects (FEATURE_ARB_vertex_shader || FEATURE_ARB_fragment_shader)
-#define FEATURE_ARB_shading_language_100 FEATURE_ARB_shader_objects
-#define FEATURE_ARB_shading_language_120 FEATURE_ARB_shader_objects
-#define FEATURE_ARB_sync _HAVE_FULL_GL
-
-#define FEATURE_EXT_framebuffer_blit _HAVE_FULL_GL
-#define FEATURE_EXT_framebuffer_object _HAVE_FULL_GL
-#define FEATURE_EXT_pixel_buffer_object _HAVE_FULL_GL
-#define FEATURE_APPLE_object_purgeable _HAVE_FULL_GL
-#define FEATURE_EXT_texture_sRGB _HAVE_FULL_GL
-#define FEATURE_ATI_fragment_shader _HAVE_FULL_GL
-#define FEATURE_NV_fence _HAVE_FULL_GL
-#define FEATURE_NV_fragment_program _HAVE_FULL_GL
-#define FEATURE_NV_vertex_program _HAVE_FULL_GL
-
-#define FEATURE_OES_EGL_image _HAVE_FULL_GL
+#define FEATURE_beginend FEATURE_GL
+#define FEATURE_colortable FEATURE_GL
+#define FEATURE_convolve FEATURE_GL
+#define FEATURE_dlist (FEATURE_GL && FEATURE_arrayelt && FEATURE_beginend)
+#define FEATURE_draw_read_buffer FEATURE_GL
+#define FEATURE_drawpix FEATURE_GL
+#define FEATURE_evaluators FEATURE_GL
+#define FEATURE_feedback FEATURE_GL
+#define FEATURE_histogram FEATURE_GL
+#define FEATURE_pixel_transfer FEATURE_GL
+#define FEATURE_queryobj FEATURE_GL
+#define FEATURE_rastpos FEATURE_GL
+#define FEATURE_texture_fxt1 FEATURE_GL
+#define FEATURE_texture_s3tc FEATURE_GL
+
+#define FEATURE_extra_context_init FEATURE_ES
+#define FEATURE_fixedpt FEATURE_ES
+#define FEATURE_point_size_array FEATURE_ES
+#define FEATURE_vertex_array_byte FEATURE_ES
+
+#define FEATURE_es2_glsl FEATURE_ES2
+
+#define FEATURE_ARB_fragment_program 1
+#define FEATURE_ARB_vertex_program 1
+#define FEATURE_ARB_vertex_shader 1
+#define FEATURE_ARB_fragment_shader 1
+#define FEATURE_ARB_shader_objects (FEATURE_ARB_vertex_shader || FEATURE_ARB_fragment_shader)
+#define FEATURE_ARB_shading_language_100 FEATURE_ARB_shader_objects
+#define FEATURE_ARB_shading_language_120 FEATURE_ARB_shader_objects
+
+#define FEATURE_ARB_framebuffer_object (FEATURE_GL && FEATURE_EXT_framebuffer_object)
+#define FEATURE_ARB_map_buffer_range FEATURE_GL
+#define FEATURE_ARB_pixel_buffer_object (FEATURE_GL && FEATURE_EXT_pixel_buffer_object)
+#define FEATURE_ARB_sync FEATURE_GL
+#define FEATURE_ARB_vertex_buffer_object 1
+
+#define FEATURE_EXT_framebuffer_blit FEATURE_GL
+#define FEATURE_EXT_framebuffer_object 1
+#define FEATURE_EXT_pixel_buffer_object 1
+#define FEATURE_EXT_texture_sRGB FEATURE_GL
+#define FEATURE_EXT_transform_feedback FEATURE_GL
+
+#define FEATURE_APPLE_object_purgeable FEATURE_GL
+#define FEATURE_ATI_fragment_shader FEATURE_GL
+#define FEATURE_NV_fence FEATURE_GL
+#define FEATURE_NV_fragment_program FEATURE_GL
+#define FEATURE_NV_vertex_program FEATURE_GL
+#define FEATURE_OES_EGL_image 1
+#define FEATURE_OES_draw_texture FEATURE_ES1
+#define FEATURE_OES_framebuffer_object FEATURE_ES
+#define FEATURE_OES_mapbuffer FEATURE_ES
#endif /* FEATURES_H */
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index 82e004f3486..7657efb0773 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -1910,6 +1910,11 @@ struct gl_query_state
/** GL_NV_conditional_render */
struct gl_query_object *CondRenderQuery;
+
+ /** GL_EXT_transform_feedback */
+ struct gl_query_object *PrimitivesGenerated;
+ struct gl_query_object *PrimitivesWritten;
+
GLenum CondRenderMode;
};
@@ -1976,6 +1981,13 @@ struct gl_shader_program
/** User-defined attribute bindings (glBindAttribLocation) */
struct gl_program_parameter_list *Attributes;
+ /** Transform feedback varyings */
+ struct {
+ GLenum BufferMode;
+ GLuint NumVarying;
+ GLchar **VaryingNames; /**< Array [NumVarying] of char * */
+ } TransformFeedback;
+
/* post-link info: */
struct gl_vertex_program *VertexProgram; /**< Linked vertex program */
struct gl_fragment_program *FragmentProgram; /**< Linked fragment prog */
@@ -2017,6 +2029,29 @@ struct gl_shader_state
/**
+ * Context state for transform feedback.
+ */
+struct gl_transform_feedback
+{
+ GLboolean Active; /**< Is transform feedback enabled? */
+ GLenum Mode; /**< GL_POINTS, GL_LINES or GL_TRIANGLES */
+ /** Start of feedback data in dest buffer */
+ GLintptr Offset[MAX_FEEDBACK_ATTRIBS];
+ /** Max data to put into dest buffer (in bytes) */
+ GLsizeiptr Size[MAX_FEEDBACK_ATTRIBS];
+ GLboolean RasterDiscard; /**< GL_RASTERIZER_DISCARD */
+
+ /** The general binding point (GL_TRANSFORM_FEEDBACK_BUFFER) */
+ struct gl_buffer_object *CurrentBuffer;
+
+ /** The feedback buffers */
+ GLuint BufferNames[MAX_FEEDBACK_ATTRIBS];
+ struct gl_buffer_object *Buffers[MAX_FEEDBACK_ATTRIBS];
+};
+
+
+
+/**
* State which can be shared by multiple contexts:
*/
struct gl_shared_state
@@ -2388,6 +2423,11 @@ struct gl_constants
/**< OpenGL version 3.x */
GLbitfield ContextFlags; /**< Ex: GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT */
+
+ /** GL_EXT_transform_feedback */
+ GLuint MaxTransformFeedbackSeparateAttribs;
+ GLuint MaxTransformFeedbackSeparateComponents;
+ GLuint MaxTransformFeedbackInterleavedComponents;
};
@@ -2489,6 +2529,7 @@ struct gl_extensions
GLboolean EXT_texture_mirror_clamp;
GLboolean EXT_texture_sRGB;
GLboolean EXT_texture_swizzle;
+ GLboolean EXT_transform_feedback;
GLboolean EXT_timer_query;
GLboolean EXT_vertex_array;
GLboolean EXT_vertex_array_bgra;
@@ -2956,6 +2997,8 @@ struct __GLcontextRec
struct gl_query_state Query; /**< occlusion, timer queries */
+ struct gl_transform_feedback TransformFeedback;
+
struct gl_buffer_object *CopyReadBuffer; /**< GL_ARB_copy_buffer */
struct gl_buffer_object *CopyWriteBuffer; /**< GL_ARB_copy_buffer */
/*@}*/
diff --git a/src/mesa/main/queryobj.c b/src/mesa/main/queryobj.c
index e14511a3883..a907dac836b 100644
--- a/src/mesa/main/queryobj.c
+++ b/src/mesa/main/queryobj.c
@@ -130,6 +130,42 @@ _mesa_init_query_object_functions(struct dd_function_table *driver)
}
+/**
+ * Return pointer to the query object binding point for the given target.
+ * \return NULL if invalid target, else the address of binding point
+ */
+static struct gl_query_object **
+get_query_binding_point(GLcontext *ctx, GLenum target)
+{
+ switch (target) {
+ case GL_SAMPLES_PASSED_ARB:
+ if (ctx->Extensions.ARB_occlusion_query)
+ return &ctx->Query.CurrentOcclusionObject;
+ else
+ return NULL;
+ case GL_TIME_ELAPSED_EXT:
+ if (ctx->Extensions.EXT_timer_query)
+ return &ctx->Query.CurrentTimerObject;
+ else
+ return NULL;
+#if FEATURE_EXT_transform_feedback
+ case GL_PRIMITIVES_GENERATED:
+ if (ctx->Extensions.EXT_transform_feedback)
+ return &ctx->Query.PrimitivesGenerated;
+ else
+ return NULL;
+ case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
+ if (ctx->Extensions.EXT_transform_feedback)
+ return &ctx->Query.PrimitivesWritten;
+ else
+ return NULL;
+#endif
+ default:
+ return NULL;
+ }
+}
+
+
void GLAPIENTRY
_mesa_GenQueriesARB(GLsizei n, GLuint *ids)
{
@@ -214,36 +250,16 @@ _mesa_IsQueryARB(GLuint id)
static void GLAPIENTRY
_mesa_BeginQueryARB(GLenum target, GLuint id)
{
- struct gl_query_object *q;
+ struct gl_query_object *q, **bindpt;
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
FLUSH_VERTICES(ctx, _NEW_DEPTH);
- switch (target) {
- case GL_SAMPLES_PASSED_ARB:
- if (!ctx->Extensions.ARB_occlusion_query) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)");
- return;
- }
- if (ctx->Query.CurrentOcclusionObject) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB");
- return;
- }
- break;
- case GL_TIME_ELAPSED_EXT:
- if (!ctx->Extensions.EXT_timer_query) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)");
- return;
- }
- if (ctx->Query.CurrentTimerObject) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB");
- return;
- }
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)");
- return;
+ bindpt = get_query_binding_point(ctx, target);
+ if (!bindpt) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)");
+ return;
}
if (id == 0) {
@@ -275,12 +291,8 @@ _mesa_BeginQueryARB(GLenum target, GLuint id)
q->Result = 0;
q->Ready = GL_FALSE;
- if (target == GL_SAMPLES_PASSED_ARB) {
- ctx->Query.CurrentOcclusionObject = q;
- }
- else if (target == GL_TIME_ELAPSED_EXT) {
- ctx->Query.CurrentTimerObject = q;
- }
+ /* XXX should probably refcount query objects */
+ *bindpt = q;
ctx->Driver.BeginQuery(ctx, q);
}
@@ -289,34 +301,22 @@ _mesa_BeginQueryARB(GLenum target, GLuint id)
static void GLAPIENTRY
_mesa_EndQueryARB(GLenum target)
{
- struct gl_query_object *q;
+ struct gl_query_object *q, **bindpt;
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
FLUSH_VERTICES(ctx, _NEW_DEPTH);
- switch (target) {
- case GL_SAMPLES_PASSED_ARB:
- if (!ctx->Extensions.ARB_occlusion_query) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
- return;
- }
- q = ctx->Query.CurrentOcclusionObject;
- ctx->Query.CurrentOcclusionObject = NULL;
- break;
- case GL_TIME_ELAPSED_EXT:
- if (!ctx->Extensions.EXT_timer_query) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
- return;
- }
- q = ctx->Query.CurrentTimerObject;
- ctx->Query.CurrentTimerObject = NULL;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
- return;
+ bindpt = get_query_binding_point(ctx, target);
+ if (!bindpt) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
+ return;
}
+ /* XXX should probably refcount query objects */
+ q = *bindpt;
+ *bindpt = NULL;
+
if (!q || !q->Active) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glEndQueryARB(no matching glBeginQueryARB)");
@@ -331,30 +331,18 @@ _mesa_EndQueryARB(GLenum target)
void GLAPIENTRY
_mesa_GetQueryivARB(GLenum target, GLenum pname, GLint *params)
{
- struct gl_query_object *q;
+ struct gl_query_object *q, **bindpt;
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
- switch (target) {
- case GL_SAMPLES_PASSED_ARB:
- if (!ctx->Extensions.ARB_occlusion_query) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
- return;
- }
- q = ctx->Query.CurrentOcclusionObject;
- break;
- case GL_TIME_ELAPSED_EXT:
- if (!ctx->Extensions.EXT_timer_query) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
- return;
- }
- q = ctx->Query.CurrentTimerObject;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivARB(target)");
- return;
+ bindpt = get_query_binding_point(ctx, target);
+ if (!bindpt) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)");
+ return;
}
+ q = *bindpt;
+
switch (pname) {
case GL_QUERY_COUNTER_BITS_ARB:
*params = 8 * sizeof(q->Result);
diff --git a/src/mesa/main/texparam.c b/src/mesa/main/texparam.c
index 714c4cfd523..ca03404f12f 100644
--- a/src/mesa/main/texparam.c
+++ b/src/mesa/main/texparam.c
@@ -371,7 +371,7 @@ set_tex_parameteri(GLcontext *ctx,
}
return GL_FALSE;
-#ifdef FEATURE_OES_draw_texture
+#if FEATURE_OES_draw_texture
case GL_TEXTURE_CROP_RECT_OES:
texObj->CropRect[0] = params[0];
texObj->CropRect[1] = params[1];
@@ -604,7 +604,7 @@ _mesa_TexParameterfv(GLenum target, GLenum pname, const GLfloat *params)
}
break;
-#ifdef FEATURE_OES_draw_texture
+#if FEATURE_OES_draw_texture
case GL_TEXTURE_CROP_RECT_OES:
{
/* convert float params to int */
@@ -1160,7 +1160,7 @@ _mesa_GetTexParameterfv( GLenum target, GLenum pname, GLfloat *params )
else
error = GL_TRUE;
break;
-#ifdef FEATURE_OES_draw_texture
+#if FEATURE_OES_draw_texture
case GL_TEXTURE_CROP_RECT_OES:
params[0] = obj->CropRect[0];
params[1] = obj->CropRect[1];
@@ -1330,7 +1330,7 @@ _mesa_GetTexParameteriv( GLenum target, GLenum pname, GLint *params )
error = GL_TRUE;
}
break;
-#ifdef FEATURE_OES_draw_texture
+#if FEATURE_OES_draw_texture
case GL_TEXTURE_CROP_RECT_OES:
params[0] = obj->CropRect[0];
params[1] = obj->CropRect[1];
diff --git a/src/mesa/main/transformfeedback.c b/src/mesa/main/transformfeedback.c
new file mode 100644
index 00000000000..3490110baef
--- /dev/null
+++ b/src/mesa/main/transformfeedback.c
@@ -0,0 +1,427 @@
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 2010 VMware, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*
+ * Vertex transform feedback support.
+ *
+ * Authors:
+ * Brian Paul
+ */
+
+
+#include "buffers.h"
+#include "bufferobj.h"
+#include "context.h"
+#include "enums.h"
+#include "transformfeedback.h"
+
+#include "shader/prog_parameter.h"
+#include "shader/shader_api.h"
+
+
+/**
+ * Check if the given primitive mode (as in glBegin(mode)) is compatible
+ * with the current transform feedback mode (if it's enabled).
+ * This is to be called from glBegin(), glDrawArrays(), glDrawElements(), etc.
+ *
+ * \return GL_TRUE if the mode is OK, GL_FALSE otherwise.
+ */
+GLboolean
+_mesa_validate_primitive_mode(GLcontext *ctx, GLenum mode)
+{
+ if (ctx->TransformFeedback.Active) {
+ switch (mode) {
+ case GL_POINTS:
+ return ctx->TransformFeedback.Mode == GL_POINTS;
+ case GL_LINES:
+ case GL_LINE_STRIP:
+ case GL_LINE_LOOP:
+ return ctx->TransformFeedback.Mode == GL_LINES;
+ default:
+ return ctx->TransformFeedback.Mode == GL_TRIANGLES;
+ }
+ }
+ return GL_TRUE;
+}
+
+
+/**
+ * Check that all the buffer objects currently bound for transform
+ * feedback actually exist. Raise a GL_INVALID_OPERATION error if
+ * any buffers are missing.
+ * \return GL_TRUE for success, GL_FALSE if error
+ */
+GLboolean
+_mesa_validate_transform_feedback_buffers(GLcontext *ctx)
+{
+
+ return GL_TRUE;
+}
+
+
+
+/**
+ * Per-context init for transform feedback.
+ */
+void
+_mesa_init_transform_feedback(GLcontext *ctx)
+{
+ _mesa_reference_buffer_object(ctx,
+ &ctx->TransformFeedback.CurrentBuffer,
+ ctx->Shared->NullBufferObj);
+}
+
+
+/**
+ * Per-context free/clean-up for transform feedback.
+ */
+void
+_mesa_free_transform_feedback(GLcontext *ctx)
+{
+ _mesa_reference_buffer_object(ctx,
+ &ctx->TransformFeedback.CurrentBuffer,
+ NULL);
+}
+
+
+void GLAPIENTRY
+_mesa_BeginTransformFeedback(GLenum mode)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ switch (mode) {
+ case GL_POINTS:
+ case GL_LINES:
+ case GL_TRIANGLES:
+ /* legal */
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBeginTransformFeedback(mode)");
+ return;
+ }
+
+ if (ctx->TransformFeedback.Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBeginTransformFeedback(already active)");
+ return;
+ }
+
+ ctx->TransformFeedback.Active = GL_TRUE;
+ ctx->TransformFeedback.Mode = mode;
+}
+
+
+void GLAPIENTRY
+_mesa_EndTransformFeedback(void)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (!ctx->TransformFeedback.Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glEndTransformFeedback(not active)");
+ return;
+ }
+
+ ctx->TransformFeedback.Active = GL_FALSE;
+}
+
+
+/**
+ * Helper used by BindBufferRange() and BindBufferBase().
+ */
+static void
+bind_buffer_range(GLcontext *ctx, GLuint index,
+ struct gl_buffer_object *bufObj,
+ GLintptr offset, GLsizeiptr size)
+{
+ /* The general binding point */
+ _mesa_reference_buffer_object(ctx,
+ &ctx->TransformFeedback.CurrentBuffer,
+ bufObj);
+
+ /* The per-attribute binding point */
+ _mesa_reference_buffer_object(ctx,
+ &ctx->TransformFeedback.Buffers[index],
+ bufObj);
+
+ ctx->TransformFeedback.BufferNames[index] = bufObj->Name;
+
+ ctx->TransformFeedback.Offset[index] = offset;
+ ctx->TransformFeedback.Size[index] = size;
+}
+
+
+/**
+ * Specify a buffer object to receive vertex shader results. Plus,
+ * specify the starting offset to place the results, and max size.
+ */
+void GLAPIENTRY
+_mesa_BindBufferRange(GLenum target, GLuint index,
+ GLuint buffer, GLintptr offset, GLsizeiptr size)
+{
+ struct gl_buffer_object *bufObj;
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (target != GL_TRANSFORM_FEEDBACK_BUFFER) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferRange(target)");
+ return;
+ }
+
+ if (ctx->TransformFeedback.Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindBufferRange(transform feedback active)");
+ return;
+ }
+
+ if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index);
+ return;
+ }
+
+ if ((size <= 0) || (size & 0x3)) {
+ /* must be positive and multiple of four */
+ _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(size%d)", size);
+ return;
+ }
+
+ if (offset & 0x3) {
+ /* must be multiple of four */
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glBindBufferRange(offset=%d)", offset);
+ return;
+ }
+
+ bufObj = _mesa_lookup_bufferobj(ctx, buffer);
+ if (!bufObj) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindBufferRange(invalid buffer=%u)", buffer);
+ return;
+ }
+
+ if (offset + size >= bufObj->Size) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glBindBufferRange(offset + size > buffer size)", size);
+ return;
+ }
+
+ bind_buffer_range(ctx, index, bufObj, offset, size);
+}
+
+
+/**
+ * Specify a buffer object to receive vertex shader results.
+ * As above, but start at offset = 0.
+ */
+void GLAPIENTRY
+_mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer)
+{
+ struct gl_buffer_object *bufObj;
+ GET_CURRENT_CONTEXT(ctx);
+ GLsizeiptr size;
+
+ if (target != GL_TRANSFORM_FEEDBACK_BUFFER) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferBase(target)");
+ return;
+ }
+
+ if (ctx->TransformFeedback.Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindBufferRange(transform feedback active)");
+ return;
+ }
+
+ if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index);
+ return;
+ }
+
+ bufObj = _mesa_lookup_bufferobj(ctx, buffer);
+ if (!bufObj) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindBufferBase(invalid buffer=%u)", buffer);
+ return;
+ }
+
+ /* default size is the buffer size rounded down to nearest
+ * multiple of four.
+ */
+ size = bufObj->Size & ~0x3;
+
+ bind_buffer_range(ctx, index, bufObj, 0, size);
+}
+
+
+/**
+ * Specify a buffer object to receive vertex shader results, plus the
+ * offset in the buffer to start placing results.
+ * This function is part of GL_EXT_transform_feedback, but not GL3.
+ */
+void GLAPIENTRY
+_mesa_BindBufferOffsetEXT(GLenum target, GLuint index, GLuint buffer,
+ GLintptr offset)
+{
+ struct gl_buffer_object *bufObj;
+ GET_CURRENT_CONTEXT(ctx);
+ GLsizeiptr size;
+
+ if (target != GL_TRANSFORM_FEEDBACK_BUFFER) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferOffsetEXT(target)");
+ return;
+ }
+
+ if (ctx->TransformFeedback.Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindBufferRange(transform feedback active)");
+ return;
+ }
+
+ if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glBindBufferOffsetEXT(index=%d)", index);
+ return;
+ }
+
+ bufObj = _mesa_lookup_bufferobj(ctx, buffer);
+ if (!bufObj) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindBufferOffsetEXT(invalid buffer=%u)", buffer);
+ return;
+ }
+
+ /* default size is the buffer size rounded down to nearest
+ * multiple of four.
+ */
+ size = (bufObj->Size - offset) & ~0x3;
+
+ bind_buffer_range(ctx, index, bufObj, offset, size);
+}
+
+
+/**
+ * This function specifies the vertex shader outputs to be written
+ * to the feedback buffer(s), and in what order.
+ */
+void GLAPIENTRY
+_mesa_TransformFeedbackVaryings(GLuint program, GLsizei count,
+ const GLchar **varyings, GLenum bufferMode)
+{
+ struct gl_shader_program *shProg;
+ GLuint i;
+ GET_CURRENT_CONTEXT(ctx);
+
+ switch (bufferMode) {
+ case GL_INTERLEAVED_ATTRIBS:
+ break;
+ case GL_SEPARATE_ATTRIBS:
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glTransformFeedbackVaryings(bufferMode)");
+ return;
+ }
+
+ if (count < 0 || count > ctx->Const.MaxTransformFeedbackSeparateAttribs) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glTransformFeedbackVaryings(count=%d)", count);
+ return;
+ }
+
+ shProg = _mesa_lookup_shader_program(ctx, program);
+ if (!shProg) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glTransformFeedbackVaryings(program=%u)", program);
+ return;
+ }
+
+ /* free existing varyings, if any */
+ for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) {
+ free(shProg->TransformFeedback.VaryingNames[i]);
+ }
+ free(shProg->TransformFeedback.VaryingNames);
+
+ /* allocate new memory for varying names */
+ shProg->TransformFeedback.VaryingNames =
+ (GLchar **) malloc(count * sizeof(GLchar *));
+
+ if (!shProg->TransformFeedback.VaryingNames) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTransformFeedbackVaryings()");
+ return;
+ }
+
+ /* Save the new names and the count */
+ for (i = 0; i < (GLuint) count; i++) {
+ shProg->TransformFeedback.VaryingNames[i] = _mesa_strdup(varyings[i]);
+ }
+ shProg->TransformFeedback.NumVarying = count;
+
+ shProg->TransformFeedback.BufferMode = bufferMode;
+
+ /* The varyings won't be used until shader link time */
+}
+
+
+/**
+ * Get info about the vertex shader's outputs which are to be written
+ * to the feedback buffer(s).
+ */
+void GLAPIENTRY
+_mesa_GetTransformFeedbackVarying(GLuint program, GLuint index,
+ GLsizei bufSize, GLsizei *length,
+ GLsizei *size, GLenum *type, GLchar *name)
+{
+ const struct gl_shader_program *shProg;
+ const GLchar *varyingName;
+ GLint v;
+ GET_CURRENT_CONTEXT(ctx);
+
+ shProg = _mesa_lookup_shader_program(ctx, program);
+ if (!shProg) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetTransformFeedbackVaryings(program=%u)", program);
+ return;
+ }
+
+ if (index >= shProg->TransformFeedback.NumVarying) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetTransformFeedbackVaryings(index=%u)", index);
+ return;
+ }
+
+ varyingName = shProg->TransformFeedback.VaryingNames[index];
+
+ v = _mesa_lookup_parameter_index(shProg->Varying, -1, varyingName);
+ if (v >= 0) {
+ struct gl_program_parameter *param = &shProg->Varying->Parameters[v];
+
+ /* return the varying's name and length */
+ _mesa_copy_string(name, bufSize, length, varyingName);
+
+ /* return the datatype and value's size (in datatype units) */
+ if (type)
+ *type = param->Type;
+ if (size)
+ *size = param->Size;
+ }
+}
+
diff --git a/src/mesa/main/transformfeedback.h b/src/mesa/main/transformfeedback.h
new file mode 100644
index 00000000000..e89cc414736
--- /dev/null
+++ b/src/mesa/main/transformfeedback.h
@@ -0,0 +1,71 @@
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 2010 VMware, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef TRANSFORM_FEEDBACK_H
+#define TRANSFORM_FEEDBACK_H
+
+#include "glheader.h"
+
+
+extern GLboolean
+_mesa_validate_primitive_mode(GLcontext *ctx, GLenum mode);
+
+extern GLboolean
+_mesa_validate_transform_feedback_buffers(GLcontext *ctx);
+
+extern void
+_mesa_init_transform_feedback(GLcontext *ctx);
+
+extern void
+_mesa_free_transform_feedback(GLcontext *ctx);
+
+
+extern void GLAPIENTRY
+_mesa_BeginTransformFeedback(GLenum mode);
+
+extern void GLAPIENTRY
+_mesa_EndTransformFeedback(void);
+
+extern void GLAPIENTRY
+_mesa_BindBufferRange(GLenum target, GLuint index,
+ GLuint buffer, GLintptr offset, GLsizeiptr size);
+
+extern void GLAPIENTRY
+_mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer);
+
+extern void GLAPIENTRY
+_mesa_BindBufferOffsetEXT(GLenum target, GLuint index, GLuint buffer,
+ GLintptr offset);
+
+extern void GLAPIENTRY
+_mesa_TransformFeedbackVaryings(GLuint program, GLsizei count,
+ const GLchar **varyings, GLenum bufferMode);
+
+extern void GLAPIENTRY
+_mesa_GetTransformFeedbackVarying(GLuint program, GLuint index,
+ GLsizei bufSize, GLsizei *length,
+ GLsizei *size, GLenum *type, GLchar *name);
+
+
+#endif /* TRANSFORM_FEEDBACK_H */