aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mesalib/docs/GL3.txt9
-rw-r--r--mesalib/src/gallium/auxiliary/util/u_network.c379
-rw-r--r--mesalib/src/gallium/auxiliary/util/u_network.h49
-rw-r--r--mesalib/src/glsl/ast_to_hir.cpp10
-rw-r--r--mesalib/src/glsl/ir.cpp24
-rw-r--r--mesalib/src/glsl/ir.h25
-rw-r--r--mesalib/src/glsl/ir_reader.cpp6
-rw-r--r--mesalib/src/glsl/ir_set_program_inouts.cpp47
-rw-r--r--mesalib/src/mesa/main/api_exec.c1
-rw-r--r--mesalib/src/mesa/main/dlist.c19
-rw-r--r--mesalib/src/mesa/main/mtypes.h23
-rw-r--r--mesalib/src/mesa/main/transformfeedback.c1878
-rw-r--r--mesalib/src/mesa/program/ir_to_mesa.cpp2
-rw-r--r--mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp2
14 files changed, 1280 insertions, 1194 deletions
diff --git a/mesalib/docs/GL3.txt b/mesalib/docs/GL3.txt
index 31add7403..54099451a 100644
--- a/mesalib/docs/GL3.txt
+++ b/mesalib/docs/GL3.txt
@@ -13,6 +13,7 @@ Feature Status
GL 3.0:
GLSL 1.30 (GL_EXT_gpu_shader4, etc.) started
+glBindFragDataLocation, glGetFragDataLocation not started
Conditional rendering (GL_NV_conditional_render) DONE (swrast, softpipe, i965)
Map buffer subranges (GL_ARB_map_buffer_range) DONE
Clamping controls (GL_ARB_color_buffer_float) DONE
@@ -24,14 +25,12 @@ Framebuffer objects (GL_EXT_framebuffer_object) DONE
Half-float DONE
Multisample blit DONE
Non-normalized Integer texture/framebuffer formats ~50% done
-1D/2D Texture arrays core Mesa, swrast done
+1D/2D Texture arrays DONE (gallium, swrast)
Packed depth/stencil formats DONE
Per-buffer blend and masks (GL_EXT_draw_buffers2) DONE
GL_EXT_texture_compression_rgtc DONE (swrast, gallium r600)
Red and red/green texture formats DONE (swrast, i965, gallium)
Transform feedback (GL_EXT_transform_feedback) ~50% done
- glBindFragDataLocation, glGetFragDataLocation,
- glBindBufferRange, glBindBufferBase commands
Vertex array objects (GL_APPLE_vertex_array_object) DONE
sRGB framebuffer format (GL_EXT_framebuffer_sRGB) core GL done (i965, gallium), GLX todo
glClearBuffer commands DONE
@@ -39,7 +38,7 @@ glGetStringi command DONE
glTexParameterI, glGetTexParameterI commands DONE
glVertexAttribI commands DONE (but converts int
values to floats)
-Depth format cube textures 0% done
+Depth format cube textures not started
GLX_ARB_create_context (GLX 1.4 is required) not started
@@ -99,7 +98,7 @@ GL_ARB_tessellation_shader not started
GL_ARB_texture_buffer_object_rgb32 not started
GL_ARB_texture_cube_map_array not started
GL_ARB_texture_gather not started
-GL_ARB_transform_feedback2 not started
+GL_ARB_transform_feedback2 started
GL_ARB_transform_feedback3 not started
diff --git a/mesalib/src/gallium/auxiliary/util/u_network.c b/mesalib/src/gallium/auxiliary/util/u_network.c
index d135b590f..45b3691f9 100644
--- a/mesalib/src/gallium/auxiliary/util/u_network.c
+++ b/mesalib/src/gallium/auxiliary/util/u_network.c
@@ -1,188 +1,191 @@
-
-#include "pipe/p_compiler.h"
-#include "util/u_network.h"
-#include "util/u_debug.h"
-
-#if defined(PIPE_SUBSYSTEM_WINDOWS_USER)
-# include <winsock2.h>
-# include <windows.h>
-#elif defined(PIPE_OS_LINUX) || defined(PIPE_OS_HAIKU) || defined(PIPE_OS_APPLE) || defined(PIPE_OS_CYGWIN)
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <unistd.h>
-# include <fcntl.h>
-# include <netdb.h>
-#else
-# warning "No socket implementation"
-#endif
-
-boolean
-u_socket_init()
-{
-#if defined(PIPE_SUBSYSTEM_WINDOWS_USER)
- WORD wVersionRequested;
- WSADATA wsaData;
- int err;
-
- /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
- wVersionRequested = MAKEWORD(1, 1);
-
- err = WSAStartup(wVersionRequested, &wsaData);
- if (err != 0) {
- debug_printf("WSAStartup failed with error: %d\n", err);
- return FALSE;
- }
- return TRUE;
-#elif defined(PIPE_HAVE_SOCKETS)
- return TRUE;
-#else
- return FALSE;
-#endif
-}
-
-void
-u_socket_stop()
-{
-#if defined(PIPE_SUBSYSTEM_WINDOWS_USER)
- WSACleanup();
-#endif
-}
-
-void
-u_socket_close(int s)
-{
- if (s < 0)
- return;
-
-#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_HAIKU) || defined(PIPE_OS_APPLE)
- shutdown(s, SHUT_RDWR);
- close(s);
-#elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
- shutdown(s, SD_BOTH);
- closesocket(s);
-#else
- assert(0);
-#endif
-}
-
-int u_socket_accept(int s)
-{
-#if defined(PIPE_HAVE_SOCKETS)
- return accept(s, NULL, NULL);
-#else
- return -1;
-#endif
-}
-
-int
-u_socket_send(int s, void *data, size_t size)
-{
-#if defined(PIPE_HAVE_SOCKETS)
- return send(s, data, size, 0);
-#else
- return -1;
-#endif
-}
-
-int
-u_socket_peek(int s, void *data, size_t size)
-{
-#if defined(PIPE_HAVE_SOCKETS)
- return recv(s, data, size, MSG_PEEK);
-#else
- return -1;
-#endif
-}
-
-int
-u_socket_recv(int s, void *data, size_t size)
-{
-#if defined(PIPE_HAVE_SOCKETS)
- return recv(s, data, size, 0);
-#else
- return -1;
-#endif
-}
-
-int
-u_socket_connect(const char *hostname, uint16_t port)
-{
-#if defined(PIPE_HAVE_SOCKETS)
- int s;
- struct sockaddr_in sa;
- struct hostent *host = NULL;
-
- memset(&sa, 0, sizeof(struct sockaddr_in));
- host = gethostbyname(hostname);
- if (!host)
- return -1;
-
- memcpy((char *)&sa.sin_addr,host->h_addr_list[0],host->h_length);
- sa.sin_family= host->h_addrtype;
- sa.sin_port = htons(port);
-
- s = socket(host->h_addrtype, SOCK_STREAM, IPPROTO_TCP);
- if (s < 0)
- return -1;
-
- if (connect(s, (struct sockaddr *)&sa, sizeof(sa))) {
- u_socket_close(s);
- return -1;
- }
-
- return s;
-#else
- assert(0);
- return -1;
-#endif
-}
-
-int
-u_socket_listen_on_port(uint16_t portnum)
-{
-#if defined(PIPE_HAVE_SOCKETS)
- int s;
- struct sockaddr_in sa;
- memset(&sa, 0, sizeof(struct sockaddr_in));
-
- sa.sin_family = AF_INET;
- sa.sin_port = htons(portnum);
-
- s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (s < 0)
- return -1;
-
- if (bind(s, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) == -1) {
- u_socket_close(s);
- return -1;
- }
-
- listen(s, 0);
-
- return s;
-#else
- assert(0);
- return -1;
-#endif
-}
-
-void
-u_socket_block(int s, boolean block)
-{
-#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_HAIKU) || defined(PIPE_OS_APPLE)
- int old = fcntl(s, F_GETFL, 0);
- if (old == -1)
- return;
-
- /* TODO obey block */
- if (block)
- fcntl(s, F_SETFL, old & ~O_NONBLOCK);
- else
- fcntl(s, F_SETFL, old | O_NONBLOCK);
-#elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
- u_long iMode = block ? 0 : 1;
- ioctlsocket(s, FIONBIO, &iMode);
-#else
- assert(0);
-#endif
-}
+
+#include "pipe/p_compiler.h"
+#include "util/u_network.h"
+#include "util/u_debug.h"
+
+#if defined(PIPE_SUBSYSTEM_WINDOWS_USER)
+# include <winsock2.h>
+# include <windows.h>
+#elif defined(PIPE_OS_LINUX) || defined(PIPE_OS_HAIKU) || \
+ defined(PIPE_OS_APPLE) || defined(PIPE_OS_CYGWIN) || defined(PIPE_OS_SOLARIS)
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <unistd.h>
+# include <fcntl.h>
+# include <netdb.h>
+#else
+# warning "No socket implementation"
+#endif
+
+boolean
+u_socket_init()
+{
+#if defined(PIPE_SUBSYSTEM_WINDOWS_USER)
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
+
+ /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
+ wVersionRequested = MAKEWORD(1, 1);
+
+ err = WSAStartup(wVersionRequested, &wsaData);
+ if (err != 0) {
+ debug_printf("WSAStartup failed with error: %d\n", err);
+ return FALSE;
+ }
+ return TRUE;
+#elif defined(PIPE_HAVE_SOCKETS)
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+void
+u_socket_stop()
+{
+#if defined(PIPE_SUBSYSTEM_WINDOWS_USER)
+ WSACleanup();
+#endif
+}
+
+void
+u_socket_close(int s)
+{
+ if (s < 0)
+ return;
+
+#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_HAIKU) \
+ || defined(PIPE_OS_APPLE) || defined(PIPE_OS_SOLARIS)
+ shutdown(s, SHUT_RDWR);
+ close(s);
+#elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
+ shutdown(s, SD_BOTH);
+ closesocket(s);
+#else
+ assert(0);
+#endif
+}
+
+int u_socket_accept(int s)
+{
+#if defined(PIPE_HAVE_SOCKETS)
+ return accept(s, NULL, NULL);
+#else
+ return -1;
+#endif
+}
+
+int
+u_socket_send(int s, void *data, size_t size)
+{
+#if defined(PIPE_HAVE_SOCKETS)
+ return send(s, data, size, 0);
+#else
+ return -1;
+#endif
+}
+
+int
+u_socket_peek(int s, void *data, size_t size)
+{
+#if defined(PIPE_HAVE_SOCKETS)
+ return recv(s, data, size, MSG_PEEK);
+#else
+ return -1;
+#endif
+}
+
+int
+u_socket_recv(int s, void *data, size_t size)
+{
+#if defined(PIPE_HAVE_SOCKETS)
+ return recv(s, data, size, 0);
+#else
+ return -1;
+#endif
+}
+
+int
+u_socket_connect(const char *hostname, uint16_t port)
+{
+#if defined(PIPE_HAVE_SOCKETS)
+ int s;
+ struct sockaddr_in sa;
+ struct hostent *host = NULL;
+
+ memset(&sa, 0, sizeof(struct sockaddr_in));
+ host = gethostbyname(hostname);
+ if (!host)
+ return -1;
+
+ memcpy((char *)&sa.sin_addr,host->h_addr_list[0],host->h_length);
+ sa.sin_family= host->h_addrtype;
+ sa.sin_port = htons(port);
+
+ s = socket(host->h_addrtype, SOCK_STREAM, IPPROTO_TCP);
+ if (s < 0)
+ return -1;
+
+ if (connect(s, (struct sockaddr *)&sa, sizeof(sa))) {
+ u_socket_close(s);
+ return -1;
+ }
+
+ return s;
+#else
+ assert(0);
+ return -1;
+#endif
+}
+
+int
+u_socket_listen_on_port(uint16_t portnum)
+{
+#if defined(PIPE_HAVE_SOCKETS)
+ int s;
+ struct sockaddr_in sa;
+ memset(&sa, 0, sizeof(struct sockaddr_in));
+
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons(portnum);
+
+ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (s < 0)
+ return -1;
+
+ if (bind(s, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) == -1) {
+ u_socket_close(s);
+ return -1;
+ }
+
+ listen(s, 0);
+
+ return s;
+#else
+ assert(0);
+ return -1;
+#endif
+}
+
+void
+u_socket_block(int s, boolean block)
+{
+#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_HAIKU) \
+ || defined(PIPE_OS_APPLE) || defined(PIPE_OS_SOLARIS)
+ int old = fcntl(s, F_GETFL, 0);
+ if (old == -1)
+ return;
+
+ /* TODO obey block */
+ if (block)
+ fcntl(s, F_SETFL, old & ~O_NONBLOCK);
+ else
+ fcntl(s, F_SETFL, old | O_NONBLOCK);
+#elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
+ u_long iMode = block ? 0 : 1;
+ ioctlsocket(s, FIONBIO, &iMode);
+#else
+ assert(0);
+#endif
+}
diff --git a/mesalib/src/gallium/auxiliary/util/u_network.h b/mesalib/src/gallium/auxiliary/util/u_network.h
index 5bf18c542..61fe9a3c6 100644
--- a/mesalib/src/gallium/auxiliary/util/u_network.h
+++ b/mesalib/src/gallium/auxiliary/util/u_network.h
@@ -1,24 +1,25 @@
-
-#ifndef _U_NETWORK_H_
-#define _U_NETWORK_H_
-
-#include "pipe/p_compiler.h"
-
-#if defined(PIPE_SUBSYSTEM_WINDOWS_USER)
-# define PIPE_HAVE_SOCKETS
-#elif defined(PIPE_OS_LINUX) || defined(PIPE_OS_HAIKU) || defined(PIPE_OS_APPLE)
-# define PIPE_HAVE_SOCKETS
-#endif
-
-boolean u_socket_init(void);
-void u_socket_stop(void);
-void u_socket_close(int s);
-int u_socket_listen_on_port(uint16_t portnum);
-int u_socket_accept(int s);
-int u_socket_connect(const char *host, uint16_t port);
-int u_socket_send(int s, void *data, size_t size);
-int u_socket_peek(int s, void *data, size_t size);
-int u_socket_recv(int s, void *data, size_t size);
-void u_socket_block(int s, boolean block);
-
-#endif
+
+#ifndef _U_NETWORK_H_
+#define _U_NETWORK_H_
+
+#include "pipe/p_compiler.h"
+
+#if defined(PIPE_SUBSYSTEM_WINDOWS_USER)
+# define PIPE_HAVE_SOCKETS
+#elif defined(PIPE_OS_LINUX) || defined(PIPE_OS_HAIKU) || \
+ defined(PIPE_OS_APPLE) || defined(PIPE_OS_SOLARIS)
+# define PIPE_HAVE_SOCKETS
+#endif
+
+boolean u_socket_init(void);
+void u_socket_stop(void);
+void u_socket_close(int s);
+int u_socket_listen_on_port(uint16_t portnum);
+int u_socket_accept(int s);
+int u_socket_connect(const char *host, uint16_t port);
+int u_socket_send(int s, void *data, size_t size);
+int u_socket_peek(int s, void *data, size_t size);
+int u_socket_recv(int s, void *data, size_t size);
+void u_socket_block(int s, boolean block);
+
+#endif
diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp
index 70afb67df..fa6206e5e 100644
--- a/mesalib/src/glsl/ast_to_hir.cpp
+++ b/mesalib/src/glsl/ast_to_hir.cpp
@@ -1962,11 +1962,13 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
}
if (qual->flags.q.flat)
- var->interpolation = ir_var_flat;
+ var->interpolation = INTERP_QUALIFIER_FLAT;
else if (qual->flags.q.noperspective)
- var->interpolation = ir_var_noperspective;
+ var->interpolation = INTERP_QUALIFIER_NOPERSPECTIVE;
+ else if (qual->flags.q.smooth)
+ var->interpolation = INTERP_QUALIFIER_SMOOTH;
else
- var->interpolation = ir_var_smooth;
+ var->interpolation = INTERP_QUALIFIER_NONE;
var->pixel_center_integer = qual->flags.q.pixel_center_integer;
var->origin_upper_left = qual->flags.q.origin_upper_left;
@@ -2630,7 +2632,7 @@ ast_declarator_list::hir(exec_list *instructions,
&& state->current_function == NULL
&& var->type->is_integer()
&& var->mode == ir_var_out
- && var->interpolation != ir_var_flat) {
+ && var->interpolation != INTERP_QUALIFIER_FLAT) {
_mesa_glsl_error(&loc, state, "If a vertex output is an integer, "
"then it must be qualified with 'flat'");
diff --git a/mesalib/src/glsl/ir.cpp b/mesalib/src/glsl/ir.cpp
index d968890a2..ef7300e65 100644
--- a/mesalib/src/glsl/ir.cpp
+++ b/mesalib/src/glsl/ir.cpp
@@ -1320,7 +1320,7 @@ ir_swizzle::variable_referenced() const
ir_variable::ir_variable(const struct glsl_type *type, const char *name,
ir_variable_mode mode)
: max_array_access(0), read_only(false), centroid(false), invariant(false),
- mode(mode), interpolation(ir_var_smooth)
+ mode(mode), interpolation(INTERP_QUALIFIER_NONE)
{
this->ir_type = ir_type_variable;
this->type = type;
@@ -1343,9 +1343,10 @@ const char *
ir_variable::interpolation_string() const
{
switch (this->interpolation) {
- case ir_var_smooth: return "smooth";
- case ir_var_flat: return "flat";
- case ir_var_noperspective: return "noperspective";
+ case INTERP_QUALIFIER_NONE: return "no";
+ case INTERP_QUALIFIER_SMOOTH: return "smooth";
+ case INTERP_QUALIFIER_FLAT: return "flat";
+ case INTERP_QUALIFIER_NOPERSPECTIVE: return "noperspective";
}
assert(!"Should not get here.");
@@ -1353,6 +1354,21 @@ ir_variable::interpolation_string() const
}
+glsl_interp_qualifier
+ir_variable::determine_interpolation_mode(bool flat_shade)
+{
+ if (this->interpolation != INTERP_QUALIFIER_NONE)
+ return (glsl_interp_qualifier) this->interpolation;
+ int location = this->location;
+ bool is_gl_Color =
+ location == FRAG_ATTRIB_COL0 || location == FRAG_ATTRIB_COL1;
+ if (flat_shade && is_gl_Color)
+ return INTERP_QUALIFIER_FLAT;
+ else
+ return INTERP_QUALIFIER_SMOOTH;
+}
+
+
ir_function_signature::ir_function_signature(const glsl_type *return_type)
: return_type(return_type), is_defined(false), _function(NULL)
{
diff --git a/mesalib/src/glsl/ir.h b/mesalib/src/glsl/ir.h
index b707634ea..404d4cffa 100644
--- a/mesalib/src/glsl/ir.h
+++ b/mesalib/src/glsl/ir.h
@@ -34,6 +34,7 @@
#include "list.h"
#include "ir_visitor.h"
#include "ir_hierarchical_visitor.h"
+#include "main/mtypes.h"
/**
* \defgroup IR Intermediate representation nodes
@@ -227,12 +228,6 @@ enum ir_variable_mode {
ir_var_temporary /**< Temporary variable generated during compilation. */
};
-enum ir_variable_interpolation {
- ir_var_smooth = 0,
- ir_var_flat,
- ir_var_noperspective
-};
-
/**
* \brief Layout qualifiers for gl_FragDepth.
*
@@ -288,11 +283,26 @@ public:
* \return The string that would be used in a shader to specify \c
* mode will be returned.
*
+ * This function is used to generate error messages of the form "shader
+ * uses %s interpolation qualifier", so in the case where there is no
+ * interpolation qualifier, it returns "no".
+ *
* This function should only be used on a shader input or output variable.
*/
const char *interpolation_string() const;
/**
+ * Determine how this variable should be interpolated based on its
+ * interpolation qualifier (if present), whether it is gl_Color or
+ * gl_SecondaryColor, and whether flatshading is enabled in the current GL
+ * state.
+ *
+ * The return value will always be either INTERP_QUALIFIER_SMOOTH,
+ * INTERP_QUALIFIER_NOPERSPECTIVE, or INTERP_QUALIFIER_FLAT.
+ */
+ glsl_interp_qualifier determine_interpolation_mode(bool flat_shade);
+
+ /**
* Delcared name of the variable
*/
const char *name;
@@ -1679,7 +1689,8 @@ extern bool
ir_has_call(ir_instruction *ir);
extern void
-do_set_program_inouts(exec_list *instructions, struct gl_program *prog);
+do_set_program_inouts(exec_list *instructions, struct gl_program *prog,
+ bool is_fragment_shader);
extern char *
prototype_string(const glsl_type *return_type, const char *name,
diff --git a/mesalib/src/glsl/ir_reader.cpp b/mesalib/src/glsl/ir_reader.cpp
index afb06b3be..e3a3ed97d 100644
--- a/mesalib/src/glsl/ir_reader.cpp
+++ b/mesalib/src/glsl/ir_reader.cpp
@@ -405,11 +405,11 @@ ir_reader::read_declaration(s_expression *expr)
} else if (strcmp(qualifier->value(), "inout") == 0) {
var->mode = ir_var_inout;
} else if (strcmp(qualifier->value(), "smooth") == 0) {
- var->interpolation = ir_var_smooth;
+ var->interpolation = INTERP_QUALIFIER_SMOOTH;
} else if (strcmp(qualifier->value(), "flat") == 0) {
- var->interpolation = ir_var_flat;
+ var->interpolation = INTERP_QUALIFIER_FLAT;
} else if (strcmp(qualifier->value(), "noperspective") == 0) {
- var->interpolation = ir_var_noperspective;
+ var->interpolation = INTERP_QUALIFIER_NOPERSPECTIVE;
} else {
ir_read_error(expr, "unknown qualifier: %s", qualifier->value());
return NULL;
diff --git a/mesalib/src/glsl/ir_set_program_inouts.cpp b/mesalib/src/glsl/ir_set_program_inouts.cpp
index ae3ef74c7..8c2bc30d6 100644
--- a/mesalib/src/glsl/ir_set_program_inouts.cpp
+++ b/mesalib/src/glsl/ir_set_program_inouts.cpp
@@ -26,6 +26,8 @@
*
* Sets the InputsRead and OutputsWritten of Mesa programs.
*
+ * Additionally, for fragment shaders, sets the InterpQualifier array.
+ *
* Mesa programs (gl_program, not gl_shader_program) have a set of
* flags indicating which varyings are read and written. Computing
* which are actually read from some sort of backend code can be
@@ -42,9 +44,11 @@
class ir_set_program_inouts_visitor : public ir_hierarchical_visitor {
public:
- ir_set_program_inouts_visitor(struct gl_program *prog)
+ ir_set_program_inouts_visitor(struct gl_program *prog,
+ bool is_fragment_shader)
{
this->prog = prog;
+ this->is_fragment_shader = is_fragment_shader;
this->ht = hash_table_ctor(0,
hash_table_pointer_hash,
hash_table_pointer_compare);
@@ -61,10 +65,12 @@ public:
struct gl_program *prog;
struct hash_table *ht;
+ bool is_fragment_shader;
};
static void
-mark(struct gl_program *prog, ir_variable *var, int offset, int len)
+mark(struct gl_program *prog, ir_variable *var, int offset, int len,
+ bool is_fragment_shader)
{
/* As of GLSL 1.20, varyings can only be floats, floating-point
* vectors or matrices, or arrays of them. For Mesa programs using
@@ -75,12 +81,19 @@ mark(struct gl_program *prog, ir_variable *var, int offset, int len)
*/
for (int i = 0; i < len; i++) {
- if (var->mode == ir_var_in)
- prog->InputsRead |= BITFIELD64_BIT(var->location + offset + i);
- else if (var->mode == ir_var_system_value)
- prog->SystemValuesRead |= (1 << (var->location + offset + i));
- else
- prog->OutputsWritten |= BITFIELD64_BIT(var->location + offset + i);
+ GLbitfield64 bitfield = BITFIELD64_BIT(var->location + offset + i);
+ if (var->mode == ir_var_in) {
+ prog->InputsRead |= bitfield;
+ if (is_fragment_shader) {
+ gl_fragment_program *fprog = (gl_fragment_program *) prog;
+ fprog->InterpQualifier[var->location + offset + i] =
+ (glsl_interp_qualifier) var->interpolation;
+ }
+ } else if (var->mode == ir_var_system_value) {
+ prog->SystemValuesRead |= bitfield;
+ } else {
+ prog->OutputsWritten |= bitfield;
+ }
}
}
@@ -93,9 +106,11 @@ ir_set_program_inouts_visitor::visit(ir_dereference_variable *ir)
if (ir->type->is_array()) {
mark(this->prog, ir->var, 0,
- ir->type->length * ir->type->fields.array->matrix_columns);
+ ir->type->length * ir->type->fields.array->matrix_columns,
+ this->is_fragment_shader);
} else {
- mark(this->prog, ir->var, 0, ir->type->matrix_columns);
+ mark(this->prog, ir->var, 0, ir->type->matrix_columns,
+ this->is_fragment_shader);
}
return visit_continue;
@@ -121,7 +136,8 @@ ir_set_program_inouts_visitor::visit_enter(ir_dereference_array *ir)
width = deref_var->type->fields.array->matrix_columns;
}
- mark(this->prog, var, index->value.i[0] * width, width);
+ mark(this->prog, var, index->value.i[0] * width, width,
+ this->is_fragment_shader);
return visit_continue_with_parent;
}
@@ -151,12 +167,17 @@ ir_set_program_inouts_visitor::visit_enter(ir_function_signature *ir)
}
void
-do_set_program_inouts(exec_list *instructions, struct gl_program *prog)
+do_set_program_inouts(exec_list *instructions, struct gl_program *prog,
+ bool is_fragment_shader)
{
- ir_set_program_inouts_visitor v(prog);
+ ir_set_program_inouts_visitor v(prog, is_fragment_shader);
prog->InputsRead = 0;
prog->OutputsWritten = 0;
prog->SystemValuesRead = 0;
+ if (is_fragment_shader) {
+ memset(((gl_fragment_program *) prog)->InterpQualifier, 0,
+ sizeof(((gl_fragment_program *) prog)->InterpQualifier));
+ }
visit_list_elements(&v, instructions);
}
diff --git a/mesalib/src/mesa/main/api_exec.c b/mesalib/src/mesa/main/api_exec.c
index 93214dd0b..1bc39db55 100644
--- a/mesalib/src/mesa/main/api_exec.c
+++ b/mesalib/src/mesa/main/api_exec.c
@@ -469,6 +469,7 @@ _mesa_create_exec_table(void)
SET_DepthBoundsEXT(exec, _mesa_DepthBoundsEXT);
/* 352. GL_EXT_transform_feedback */
+ /* ARB 93. GL_ARB_transform_feedback2 */
_mesa_init_transform_feedback_dispatch(exec);
/* 364. GL_EXT_provoking_vertex */
diff --git a/mesalib/src/mesa/main/dlist.c b/mesalib/src/mesa/main/dlist.c
index d901bddf8..52548fdc1 100644
--- a/mesalib/src/mesa/main/dlist.c
+++ b/mesalib/src/mesa/main/dlist.c
@@ -69,6 +69,9 @@
#if FEATURE_NV_vertex_program || FEATURE_NV_fragment_program
#include "nvprogram.h"
#endif
+#if FEATURE_EXT_transform_feedback
+#include "transformfeedback.h"
+#endif
#include "math/m_matrix.h"
@@ -6272,15 +6275,6 @@ save_EndTransformFeedback(void)
}
static void GLAPIENTRY
-save_TransformFeedbackVaryings(GLuint program, GLsizei count,
- const GLchar **varyings, GLenum bufferMode)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_problem(ctx,
- "glTransformFeedbackVarying() display list support not done");
-}
-
-static void GLAPIENTRY
save_BindTransformFeedback(GLenum target, GLuint name)
{
GET_CURRENT_CONTEXT(ctx);
@@ -10321,9 +10315,14 @@ _mesa_create_save_table(void)
#endif
#if FEATURE_EXT_transform_feedback
+ /* These are not compiled into display lists: */
+ SET_BindBufferBaseEXT(table, _mesa_BindBufferBase);
+ SET_BindBufferOffsetEXT(table, _mesa_BindBufferOffsetEXT);
+ SET_BindBufferRangeEXT(table, _mesa_BindBufferRange);
+ SET_TransformFeedbackVaryingsEXT(table, _mesa_TransformFeedbackVaryings);
+ /* These are: */
SET_BeginTransformFeedbackEXT(table, save_BeginTransformFeedback);
SET_EndTransformFeedbackEXT(table, save_EndTransformFeedback);
- SET_TransformFeedbackVaryingsEXT(table, save_TransformFeedbackVaryings);
SET_BindTransformFeedback(table, save_BindTransformFeedback);
SET_PauseTransformFeedback(table, save_PauseTransformFeedback);
SET_ResumeTransformFeedback(table, save_ResumeTransformFeedback);
diff --git a/mesalib/src/mesa/main/mtypes.h b/mesalib/src/mesa/main/mtypes.h
index 411768641..aa3fa6aec 100644
--- a/mesalib/src/mesa/main/mtypes.h
+++ b/mesalib/src/mesa/main/mtypes.h
@@ -1790,6 +1790,22 @@ typedef enum
} gl_system_value;
+/**
+ * The possible interpolation qualifiers that can be applied to a fragment
+ * shader input in GLSL.
+ *
+ * Note: INTERP_QUALIFIER_NONE must be 0 so that memsetting the
+ * gl_fragment_program data structure to 0 causes the default behavior.
+ */
+enum glsl_interp_qualifier
+{
+ INTERP_QUALIFIER_NONE = 0,
+ INTERP_QUALIFIER_SMOOTH,
+ INTERP_QUALIFIER_FLAT,
+ INTERP_QUALIFIER_NOPERSPECTIVE
+};
+
+
/** Vertex and fragment instructions */
struct prog_instruction;
struct gl_program_parameter_list;
@@ -1890,6 +1906,13 @@ struct gl_fragment_program
GLboolean OriginUpperLeft;
GLboolean PixelCenterInteger;
enum gl_frag_depth_layout FragDepthLayout;
+
+ /**
+ * GLSL interpolation qualifier associated with each fragment shader input.
+ * For inputs that do not have an interpolation qualifier specified in
+ * GLSL, the value is INTERP_QUALIFIER_NONE.
+ */
+ enum glsl_interp_qualifier InterpQualifier[FRAG_ATTRIB_MAX];
};
diff --git a/mesalib/src/mesa/main/transformfeedback.c b/mesalib/src/mesa/main/transformfeedback.c
index 85c213552..b5fb98ecb 100644
--- a/mesalib/src/mesa/main/transformfeedback.c
+++ b/mesalib/src/mesa/main/transformfeedback.c
@@ -1,934 +1,944 @@
-/*
- * 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 "hash.h"
-#include "mfeatures.h"
-#include "mtypes.h"
-#include "transformfeedback.h"
-#include "shaderapi.h"
-#include "shaderobj.h"
-#include "main/dispatch.h"
-
-#include "program/prog_parameter.h"
-
-
-#if FEATURE_EXT_transform_feedback
-
-
-/**
- * Do reference counting of transform feedback buffers.
- */
-static void
-reference_transform_feedback_object(struct gl_transform_feedback_object **ptr,
- struct gl_transform_feedback_object *obj)
-{
- if (*ptr == obj)
- return;
-
- if (*ptr) {
- /* Unreference the old object */
- struct gl_transform_feedback_object *oldObj = *ptr;
-
- ASSERT(oldObj->RefCount > 0);
- oldObj->RefCount--;
-
- if (oldObj->RefCount == 0) {
- GET_CURRENT_CONTEXT(ctx);
- if (ctx)
- ctx->Driver.DeleteTransformFeedback(ctx, oldObj);
- }
-
- *ptr = NULL;
- }
- ASSERT(!*ptr);
-
- if (obj) {
- /* reference new object */
- if (obj->RefCount == 0) {
- _mesa_problem(NULL, "referencing deleted transform feedback object");
- *ptr = NULL;
- }
- else {
- obj->RefCount++;
- *ptr = obj;
- }
- }
-}
-
-
-/**
- * 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(struct gl_context *ctx, GLenum mode)
-{
- if (ctx->TransformFeedback.CurrentObject->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(struct gl_context *ctx)
-{
- /* XXX to do */
- return GL_TRUE;
-}
-
-
-
-/**
- * Per-context init for transform feedback.
- */
-void
-_mesa_init_transform_feedback(struct gl_context *ctx)
-{
- /* core mesa expects this, even a dummy one, to be available */
- ASSERT(ctx->Driver.NewTransformFeedback);
-
- ctx->TransformFeedback.DefaultObject =
- ctx->Driver.NewTransformFeedback(ctx, 0);
-
- assert(ctx->TransformFeedback.DefaultObject->RefCount == 1);
-
- reference_transform_feedback_object(&ctx->TransformFeedback.CurrentObject,
- ctx->TransformFeedback.DefaultObject);
-
- assert(ctx->TransformFeedback.DefaultObject->RefCount == 2);
-
- ctx->TransformFeedback.Objects = _mesa_NewHashTable();
-
- _mesa_reference_buffer_object(ctx,
- &ctx->TransformFeedback.CurrentBuffer,
- ctx->Shared->NullBufferObj);
-}
-
-
-
-/**
- * Callback for _mesa_HashDeleteAll().
- */
-static void
-delete_cb(GLuint key, void *data, void *userData)
-{
- struct gl_context *ctx = (struct gl_context *) userData;
- struct gl_transform_feedback_object *obj =
- (struct gl_transform_feedback_object *) data;
-
- ctx->Driver.DeleteTransformFeedback(ctx, obj);
-}
-
-
-/**
- * Per-context free/clean-up for transform feedback.
- */
-void
-_mesa_free_transform_feedback(struct gl_context *ctx)
-{
- /* core mesa expects this, even a dummy one, to be available */
- ASSERT(ctx->Driver.NewTransformFeedback);
-
- _mesa_reference_buffer_object(ctx,
- &ctx->TransformFeedback.CurrentBuffer,
- NULL);
-
- /* Delete all feedback objects */
- _mesa_HashDeleteAll(ctx->TransformFeedback.Objects, delete_cb, ctx);
- _mesa_DeleteHashTable(ctx->TransformFeedback.Objects);
-
- /* Delete the default feedback object */
- assert(ctx->Driver.DeleteTransformFeedback);
- ctx->Driver.DeleteTransformFeedback(ctx,
- ctx->TransformFeedback.DefaultObject);
-
- ctx->TransformFeedback.CurrentObject = NULL;
-}
-
-
-#else /* FEATURE_EXT_transform_feedback */
-
-/* forward declarations */
-static struct gl_transform_feedback_object *
-new_transform_feedback(struct gl_context *ctx, GLuint name);
-
-static void
-delete_transform_feedback(struct gl_context *ctx,
- struct gl_transform_feedback_object *obj);
-
-/* dummy per-context init/clean-up for transform feedback */
-void
-_mesa_init_transform_feedback(struct gl_context *ctx)
-{
- ctx->TransformFeedback.DefaultObject = new_transform_feedback(ctx, 0);
- ctx->TransformFeedback.CurrentObject = ctx->TransformFeedback.DefaultObject;
- _mesa_reference_buffer_object(ctx,
- &ctx->TransformFeedback.CurrentBuffer,
- ctx->Shared->NullBufferObj);
-}
-
-void
-_mesa_free_transform_feedback(struct gl_context *ctx)
-{
- _mesa_reference_buffer_object(ctx,
- &ctx->TransformFeedback.CurrentBuffer,
- NULL);
- ctx->TransformFeedback.CurrentObject = NULL;
- delete_transform_feedback(ctx, ctx->TransformFeedback.DefaultObject);
-}
-
-#endif /* FEATURE_EXT_transform_feedback */
-
-
-/** Default fallback for ctx->Driver.NewTransformFeedback() */
-static struct gl_transform_feedback_object *
-new_transform_feedback(struct gl_context *ctx, GLuint name)
-{
- struct gl_transform_feedback_object *obj;
- obj = CALLOC_STRUCT(gl_transform_feedback_object);
- if (obj) {
- obj->Name = name;
- obj->RefCount = 1;
- }
- return obj;
-}
-
-/** Default fallback for ctx->Driver.DeleteTransformFeedback() */
-static void
-delete_transform_feedback(struct gl_context *ctx,
- struct gl_transform_feedback_object *obj)
-{
- GLuint i;
-
- for (i = 0; i < Elements(obj->Buffers); i++) {
- _mesa_reference_buffer_object(ctx, &obj->Buffers[i], NULL);
- }
-
- free(obj);
-}
-
-
-#if FEATURE_EXT_transform_feedback
-
-
-/** Default fallback for ctx->Driver.BeginTransformFeedback() */
-static void
-begin_transform_feedback(struct gl_context *ctx, GLenum mode,
- struct gl_transform_feedback_object *obj)
-{
- /* nop */
-}
-
-/** Default fallback for ctx->Driver.EndTransformFeedback() */
-static void
-end_transform_feedback(struct gl_context *ctx,
- struct gl_transform_feedback_object *obj)
-{
- /* nop */
-}
-
-/** Default fallback for ctx->Driver.PauseTransformFeedback() */
-static void
-pause_transform_feedback(struct gl_context *ctx,
- struct gl_transform_feedback_object *obj)
-{
- /* nop */
-}
-
-/** Default fallback for ctx->Driver.ResumeTransformFeedback() */
-static void
-resume_transform_feedback(struct gl_context *ctx,
- struct gl_transform_feedback_object *obj)
-{
- /* nop */
-}
-
-/** Default fallback for ctx->Driver.DrawTransformFeedback() */
-static void
-draw_transform_feedback(struct gl_context *ctx, GLenum mode,
- struct gl_transform_feedback_object *obj)
-{
- /* XXX to do */
- /*
- * Get number of vertices in obj's feedback buffer.
- * Call ctx->Exec.DrawArrays(mode, 0, count);
- */
-}
-
-
-/**
- * Plug in default device driver functions for transform feedback.
- * Most drivers will override some/all of these.
- */
-void
-_mesa_init_transform_feedback_functions(struct dd_function_table *driver)
-{
- driver->NewTransformFeedback = new_transform_feedback;
- driver->DeleteTransformFeedback = delete_transform_feedback;
- driver->BeginTransformFeedback = begin_transform_feedback;
- driver->EndTransformFeedback = end_transform_feedback;
- driver->PauseTransformFeedback = pause_transform_feedback;
- driver->ResumeTransformFeedback = resume_transform_feedback;
- driver->DrawTransformFeedback = draw_transform_feedback;
-}
-
-
-void
-_mesa_init_transform_feedback_dispatch(struct _glapi_table *disp)
-{
- SET_BeginTransformFeedbackEXT(disp, _mesa_BeginTransformFeedback);
- SET_EndTransformFeedbackEXT(disp, _mesa_EndTransformFeedback);
- SET_BindBufferRangeEXT(disp, _mesa_BindBufferRange);
- SET_BindBufferBaseEXT(disp, _mesa_BindBufferBase);
- SET_BindBufferOffsetEXT(disp, _mesa_BindBufferOffsetEXT);
- SET_TransformFeedbackVaryingsEXT(disp, _mesa_TransformFeedbackVaryings);
- SET_GetTransformFeedbackVaryingEXT(disp, _mesa_GetTransformFeedbackVarying);
-}
-
-
-/**
- ** Begin API functions
- **/
-
-
-void GLAPIENTRY
-_mesa_BeginTransformFeedback(GLenum mode)
-{
- struct gl_transform_feedback_object *obj;
- GET_CURRENT_CONTEXT(ctx);
-
- obj = ctx->TransformFeedback.CurrentObject;
-
- switch (mode) {
- case GL_POINTS:
- case GL_LINES:
- case GL_TRIANGLES:
- /* legal */
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM, "glBeginTransformFeedback(mode)");
- return;
- }
-
- if (obj->Active) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBeginTransformFeedback(already active)");
- return;
- }
-
- obj->Active = GL_TRUE;
- ctx->TransformFeedback.Mode = mode;
-
- assert(ctx->Driver.BeginTransformFeedback);
- ctx->Driver.BeginTransformFeedback(ctx, mode, obj);
-}
-
-
-void GLAPIENTRY
-_mesa_EndTransformFeedback(void)
-{
- struct gl_transform_feedback_object *obj;
- GET_CURRENT_CONTEXT(ctx);
-
- obj = ctx->TransformFeedback.CurrentObject;
-
- if (!obj->Active) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glEndTransformFeedback(not active)");
- return;
- }
-
- ctx->TransformFeedback.CurrentObject->Active = GL_FALSE;
-
- assert(ctx->Driver.EndTransformFeedback);
- ctx->Driver.EndTransformFeedback(ctx, obj);
-}
-
-
-/**
- * Helper used by BindBufferRange() and BindBufferBase().
- */
-static void
-bind_buffer_range(struct gl_context *ctx, GLuint index,
- struct gl_buffer_object *bufObj,
- GLintptr offset, GLsizeiptr size)
-{
- struct gl_transform_feedback_object *obj =
- ctx->TransformFeedback.CurrentObject;
-
- /* The general binding point */
- _mesa_reference_buffer_object(ctx,
- &ctx->TransformFeedback.CurrentBuffer,
- bufObj);
-
- /* The per-attribute binding point */
- _mesa_reference_buffer_object(ctx,
- &obj->Buffers[index],
- bufObj);
-
- obj->BufferNames[index] = bufObj->Name;
-
- obj->Offset[index] = offset;
- obj->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_transform_feedback_object *obj;
- struct gl_buffer_object *bufObj;
- GET_CURRENT_CONTEXT(ctx);
-
- if (target != GL_TRANSFORM_FEEDBACK_BUFFER) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferRange(target)");
- return;
- }
-
- obj = ctx->TransformFeedback.CurrentObject;
-
- if (obj->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)", (int) size);
- return;
- }
-
- if (offset & 0x3) {
- /* must be multiple of four */
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glBindBufferRange(offset=%d)", (int) 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 %d > buffer size %d)",
- (int) (offset + size), (int) (bufObj->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_transform_feedback_object *obj;
- struct gl_buffer_object *bufObj;
- GLsizeiptr size;
- GET_CURRENT_CONTEXT(ctx);
-
- if (target != GL_TRANSFORM_FEEDBACK_BUFFER) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferBase(target)");
- return;
- }
-
- obj = ctx->TransformFeedback.CurrentObject;
-
- if (obj->Active) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBindBufferBase(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_transform_feedback_object *obj;
- 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;
- }
-
- obj = ctx->TransformFeedback.CurrentObject;
-
- if (obj->Active) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBindBufferOffsetEXT(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->DataType;
- if (size)
- *size = param->Size;
- }
- else {
- name[0] = 0;
- if (length)
- *length = 0;
- if (type)
- *type = 0;
- if (size)
- *size = 0;
- }
-}
-
-
-
-static struct gl_transform_feedback_object *
-lookup_transform_feedback_object(struct gl_context *ctx, GLuint name)
-{
- if (name == 0) {
- return ctx->TransformFeedback.DefaultObject;
- }
- else
- return (struct gl_transform_feedback_object *)
- _mesa_HashLookup(ctx->TransformFeedback.Objects, name);
-}
-
-
-/**
- * Create new transform feedback objects. Transform feedback objects
- * encapsulate the state related to transform feedback to allow quickly
- * switching state (and drawing the results, below).
- * Part of GL_ARB_transform_feedback2.
- */
-void GLAPIENTRY
-_mesa_GenTransformFeedbacks(GLsizei n, GLuint *names)
-{
- GLuint first;
- GET_CURRENT_CONTEXT(ctx);
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (n < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGenTransformFeedbacks(n < 0)");
- return;
- }
-
- if (!names)
- return;
-
- /* we don't need contiguous IDs, but this might be faster */
- first = _mesa_HashFindFreeKeyBlock(ctx->TransformFeedback.Objects, n);
- if (first) {
- GLsizei i;
- for (i = 0; i < n; i++) {
- struct gl_transform_feedback_object *obj
- = ctx->Driver.NewTransformFeedback(ctx, first + i);
- if (!obj) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTransformFeedbacks");
- return;
- }
- names[i] = first + i;
- _mesa_HashInsert(ctx->TransformFeedback.Objects, first + i, obj);
- }
- }
- else {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTransformFeedbacks");
- }
-}
-
-
-/**
- * Is the given ID a transform feedback object?
- * Part of GL_ARB_transform_feedback2.
- */
-GLboolean GLAPIENTRY
-_mesa_IsTransformFeedback(GLuint name)
-{
- GET_CURRENT_CONTEXT(ctx);
-
- ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
-
- if (name && lookup_transform_feedback_object(ctx, name))
- return GL_TRUE;
- else
- return GL_FALSE;
-}
-
-
-/**
- * Bind the given transform feedback object.
- * Part of GL_ARB_transform_feedback2.
- */
-void GLAPIENTRY
-_mesa_BindTransformFeedback(GLenum target, GLuint name)
-{
- struct gl_transform_feedback_object *obj;
- GET_CURRENT_CONTEXT(ctx);
-
- if (target != GL_TRANSFORM_FEEDBACK) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glBindTransformFeedback(target)");
- return;
- }
-
- if (ctx->TransformFeedback.CurrentObject->Active &&
- !ctx->TransformFeedback.CurrentObject->Paused) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBindTransformFeedback(transform is active, or not paused)");
- return;
- }
-
- obj = lookup_transform_feedback_object(ctx, name);
- if (!obj) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBindTransformFeedback(name=%u)", name);
- return;
- }
-
- reference_transform_feedback_object(&ctx->TransformFeedback.CurrentObject,
- obj);
-}
-
-
-/**
- * Delete the given transform feedback objects.
- * Part of GL_ARB_transform_feedback2.
- */
-void GLAPIENTRY
-_mesa_DeleteTransformFeedbacks(GLsizei n, const GLuint *names)
-{
- GLint i;
- GET_CURRENT_CONTEXT(ctx);
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (n < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteTransformFeedbacks(n < 0)");
- return;
- }
-
- if (!names)
- return;
-
- for (i = 0; i < n; i++) {
- if (names[i] > 0) {
- struct gl_transform_feedback_object *obj
- = lookup_transform_feedback_object(ctx, names[i]);
- if (obj) {
- if (obj->Active) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glDeleteTransformFeedbacks(object %u is active)",
- names[i]);
- return;
- }
- _mesa_HashRemove(ctx->TransformFeedback.Objects, names[i]);
- /* unref, but object may not be deleted until later */
- reference_transform_feedback_object(&obj, NULL);
- }
- }
- }
-}
-
-
-/**
- * Pause transform feedback.
- * Part of GL_ARB_transform_feedback2.
- */
-void GLAPIENTRY
-_mesa_PauseTransformFeedback(void)
-{
- struct gl_transform_feedback_object *obj;
- GET_CURRENT_CONTEXT(ctx);
-
- obj = ctx->TransformFeedback.CurrentObject;
-
- if (!obj->Active || obj->Paused) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glPauseTransformFeedback(feedback not active or already paused)");
- return;
- }
-
- obj->Paused = GL_TRUE;
-
- assert(ctx->Driver.PauseTransformFeedback);
- ctx->Driver.PauseTransformFeedback(ctx, obj);
-}
-
-
-/**
- * Resume transform feedback.
- * Part of GL_ARB_transform_feedback2.
- */
-void GLAPIENTRY
-_mesa_ResumeTransformFeedback(void)
-{
- struct gl_transform_feedback_object *obj;
- GET_CURRENT_CONTEXT(ctx);
-
- obj = ctx->TransformFeedback.CurrentObject;
-
- if (!obj->Active || !obj->Paused) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glResumeTransformFeedback(feedback not active or not paused)");
- return;
- }
-
- obj->Paused = GL_FALSE;
-
- assert(ctx->Driver.ResumeTransformFeedback);
- ctx->Driver.ResumeTransformFeedback(ctx, obj);
-}
-
-
-/**
- * Draw the vertex data in a transform feedback object.
- * \param mode GL_POINTS, GL_LINES, GL_TRIANGLE_STRIP, etc.
- * \param name the transform feedback object
- * The number of vertices comes from the transform feedback object.
- * User still has to setup of the vertex attribute info with
- * glVertexPointer, glColorPointer, etc.
- * Part of GL_ARB_transform_feedback2.
- */
-void GLAPIENTRY
-_mesa_DrawTransformFeedback(GLenum mode, GLuint name)
-{
- GET_CURRENT_CONTEXT(ctx);
- struct gl_transform_feedback_object *obj =
- lookup_transform_feedback_object(ctx, name);
-
- if (mode > GL_POLYGON) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glDrawTransformFeedback(mode=0x%x)", mode);
- return;
- }
- if (!obj) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glDrawTransformFeedback(name = %u)", name);
- return;
- }
-
- /* XXX check if EndTransformFeedback has never been called while
- * the object was bound
- */
-
- assert(ctx->Driver.DrawTransformFeedback);
- ctx->Driver.DrawTransformFeedback(ctx, mode, obj);
-}
-
-
-#endif /* FEATURE_EXT_transform_feedback */
+/*
+ * 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 "hash.h"
+#include "mfeatures.h"
+#include "mtypes.h"
+#include "transformfeedback.h"
+#include "shaderapi.h"
+#include "shaderobj.h"
+#include "main/dispatch.h"
+
+#include "program/prog_parameter.h"
+
+
+#if FEATURE_EXT_transform_feedback
+
+
+/**
+ * Do reference counting of transform feedback buffers.
+ */
+static void
+reference_transform_feedback_object(struct gl_transform_feedback_object **ptr,
+ struct gl_transform_feedback_object *obj)
+{
+ if (*ptr == obj)
+ return;
+
+ if (*ptr) {
+ /* Unreference the old object */
+ struct gl_transform_feedback_object *oldObj = *ptr;
+
+ ASSERT(oldObj->RefCount > 0);
+ oldObj->RefCount--;
+
+ if (oldObj->RefCount == 0) {
+ GET_CURRENT_CONTEXT(ctx);
+ if (ctx)
+ ctx->Driver.DeleteTransformFeedback(ctx, oldObj);
+ }
+
+ *ptr = NULL;
+ }
+ ASSERT(!*ptr);
+
+ if (obj) {
+ /* reference new object */
+ if (obj->RefCount == 0) {
+ _mesa_problem(NULL, "referencing deleted transform feedback object");
+ *ptr = NULL;
+ }
+ else {
+ obj->RefCount++;
+ *ptr = obj;
+ }
+ }
+}
+
+
+/**
+ * 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(struct gl_context *ctx, GLenum mode)
+{
+ if (ctx->TransformFeedback.CurrentObject->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(struct gl_context *ctx)
+{
+ /* XXX to do */
+ return GL_TRUE;
+}
+
+
+
+/**
+ * Per-context init for transform feedback.
+ */
+void
+_mesa_init_transform_feedback(struct gl_context *ctx)
+{
+ /* core mesa expects this, even a dummy one, to be available */
+ ASSERT(ctx->Driver.NewTransformFeedback);
+
+ ctx->TransformFeedback.DefaultObject =
+ ctx->Driver.NewTransformFeedback(ctx, 0);
+
+ assert(ctx->TransformFeedback.DefaultObject->RefCount == 1);
+
+ reference_transform_feedback_object(&ctx->TransformFeedback.CurrentObject,
+ ctx->TransformFeedback.DefaultObject);
+
+ assert(ctx->TransformFeedback.DefaultObject->RefCount == 2);
+
+ ctx->TransformFeedback.Objects = _mesa_NewHashTable();
+
+ _mesa_reference_buffer_object(ctx,
+ &ctx->TransformFeedback.CurrentBuffer,
+ ctx->Shared->NullBufferObj);
+}
+
+
+
+/**
+ * Callback for _mesa_HashDeleteAll().
+ */
+static void
+delete_cb(GLuint key, void *data, void *userData)
+{
+ struct gl_context *ctx = (struct gl_context *) userData;
+ struct gl_transform_feedback_object *obj =
+ (struct gl_transform_feedback_object *) data;
+
+ ctx->Driver.DeleteTransformFeedback(ctx, obj);
+}
+
+
+/**
+ * Per-context free/clean-up for transform feedback.
+ */
+void
+_mesa_free_transform_feedback(struct gl_context *ctx)
+{
+ /* core mesa expects this, even a dummy one, to be available */
+ ASSERT(ctx->Driver.NewTransformFeedback);
+
+ _mesa_reference_buffer_object(ctx,
+ &ctx->TransformFeedback.CurrentBuffer,
+ NULL);
+
+ /* Delete all feedback objects */
+ _mesa_HashDeleteAll(ctx->TransformFeedback.Objects, delete_cb, ctx);
+ _mesa_DeleteHashTable(ctx->TransformFeedback.Objects);
+
+ /* Delete the default feedback object */
+ assert(ctx->Driver.DeleteTransformFeedback);
+ ctx->Driver.DeleteTransformFeedback(ctx,
+ ctx->TransformFeedback.DefaultObject);
+
+ ctx->TransformFeedback.CurrentObject = NULL;
+}
+
+
+#else /* FEATURE_EXT_transform_feedback */
+
+/* forward declarations */
+static struct gl_transform_feedback_object *
+new_transform_feedback(struct gl_context *ctx, GLuint name);
+
+static void
+delete_transform_feedback(struct gl_context *ctx,
+ struct gl_transform_feedback_object *obj);
+
+/* dummy per-context init/clean-up for transform feedback */
+void
+_mesa_init_transform_feedback(struct gl_context *ctx)
+{
+ ctx->TransformFeedback.DefaultObject = new_transform_feedback(ctx, 0);
+ ctx->TransformFeedback.CurrentObject = ctx->TransformFeedback.DefaultObject;
+ _mesa_reference_buffer_object(ctx,
+ &ctx->TransformFeedback.CurrentBuffer,
+ ctx->Shared->NullBufferObj);
+}
+
+void
+_mesa_free_transform_feedback(struct gl_context *ctx)
+{
+ _mesa_reference_buffer_object(ctx,
+ &ctx->TransformFeedback.CurrentBuffer,
+ NULL);
+ ctx->TransformFeedback.CurrentObject = NULL;
+ delete_transform_feedback(ctx, ctx->TransformFeedback.DefaultObject);
+}
+
+#endif /* FEATURE_EXT_transform_feedback */
+
+
+/** Default fallback for ctx->Driver.NewTransformFeedback() */
+static struct gl_transform_feedback_object *
+new_transform_feedback(struct gl_context *ctx, GLuint name)
+{
+ struct gl_transform_feedback_object *obj;
+ obj = CALLOC_STRUCT(gl_transform_feedback_object);
+ if (obj) {
+ obj->Name = name;
+ obj->RefCount = 1;
+ }
+ return obj;
+}
+
+/** Default fallback for ctx->Driver.DeleteTransformFeedback() */
+static void
+delete_transform_feedback(struct gl_context *ctx,
+ struct gl_transform_feedback_object *obj)
+{
+ GLuint i;
+
+ for (i = 0; i < Elements(obj->Buffers); i++) {
+ _mesa_reference_buffer_object(ctx, &obj->Buffers[i], NULL);
+ }
+
+ free(obj);
+}
+
+
+#if FEATURE_EXT_transform_feedback
+
+
+/** Default fallback for ctx->Driver.BeginTransformFeedback() */
+static void
+begin_transform_feedback(struct gl_context *ctx, GLenum mode,
+ struct gl_transform_feedback_object *obj)
+{
+ /* nop */
+}
+
+/** Default fallback for ctx->Driver.EndTransformFeedback() */
+static void
+end_transform_feedback(struct gl_context *ctx,
+ struct gl_transform_feedback_object *obj)
+{
+ /* nop */
+}
+
+/** Default fallback for ctx->Driver.PauseTransformFeedback() */
+static void
+pause_transform_feedback(struct gl_context *ctx,
+ struct gl_transform_feedback_object *obj)
+{
+ /* nop */
+}
+
+/** Default fallback for ctx->Driver.ResumeTransformFeedback() */
+static void
+resume_transform_feedback(struct gl_context *ctx,
+ struct gl_transform_feedback_object *obj)
+{
+ /* nop */
+}
+
+/** Default fallback for ctx->Driver.DrawTransformFeedback() */
+static void
+draw_transform_feedback(struct gl_context *ctx, GLenum mode,
+ struct gl_transform_feedback_object *obj)
+{
+ /* XXX to do */
+ /*
+ * Get number of vertices in obj's feedback buffer.
+ * Call ctx->Exec.DrawArrays(mode, 0, count);
+ */
+}
+
+
+/**
+ * Plug in default device driver functions for transform feedback.
+ * Most drivers will override some/all of these.
+ */
+void
+_mesa_init_transform_feedback_functions(struct dd_function_table *driver)
+{
+ driver->NewTransformFeedback = new_transform_feedback;
+ driver->DeleteTransformFeedback = delete_transform_feedback;
+ driver->BeginTransformFeedback = begin_transform_feedback;
+ driver->EndTransformFeedback = end_transform_feedback;
+ driver->PauseTransformFeedback = pause_transform_feedback;
+ driver->ResumeTransformFeedback = resume_transform_feedback;
+ driver->DrawTransformFeedback = draw_transform_feedback;
+}
+
+
+void
+_mesa_init_transform_feedback_dispatch(struct _glapi_table *disp)
+{
+ /* EXT_transform_feedback */
+ SET_BeginTransformFeedbackEXT(disp, _mesa_BeginTransformFeedback);
+ SET_EndTransformFeedbackEXT(disp, _mesa_EndTransformFeedback);
+ SET_BindBufferRangeEXT(disp, _mesa_BindBufferRange);
+ SET_BindBufferBaseEXT(disp, _mesa_BindBufferBase);
+ SET_BindBufferOffsetEXT(disp, _mesa_BindBufferOffsetEXT);
+ SET_TransformFeedbackVaryingsEXT(disp, _mesa_TransformFeedbackVaryings);
+ SET_GetTransformFeedbackVaryingEXT(disp, _mesa_GetTransformFeedbackVarying);
+ /* ARB_transform_feedback2 */
+ SET_BindTransformFeedback(disp, _mesa_BindTransformFeedback);
+ SET_DeleteTransformFeedbacks(disp, _mesa_DeleteTransformFeedbacks);
+ SET_GenTransformFeedbacks(disp, _mesa_GenTransformFeedbacks);
+ SET_IsTransformFeedback(disp, _mesa_IsTransformFeedback);
+ SET_PauseTransformFeedback(disp, _mesa_PauseTransformFeedback);
+ SET_ResumeTransformFeedback(disp, _mesa_ResumeTransformFeedback);
+ SET_DrawTransformFeedback(disp, _mesa_DrawTransformFeedback);
+}
+
+
+/**
+ ** Begin API functions
+ **/
+
+
+void GLAPIENTRY
+_mesa_BeginTransformFeedback(GLenum mode)
+{
+ struct gl_transform_feedback_object *obj;
+ GET_CURRENT_CONTEXT(ctx);
+
+ obj = ctx->TransformFeedback.CurrentObject;
+
+ switch (mode) {
+ case GL_POINTS:
+ case GL_LINES:
+ case GL_TRIANGLES:
+ /* legal */
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBeginTransformFeedback(mode)");
+ return;
+ }
+
+ if (obj->Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBeginTransformFeedback(already active)");
+ return;
+ }
+
+ obj->Active = GL_TRUE;
+ ctx->TransformFeedback.Mode = mode;
+
+ assert(ctx->Driver.BeginTransformFeedback);
+ ctx->Driver.BeginTransformFeedback(ctx, mode, obj);
+}
+
+
+void GLAPIENTRY
+_mesa_EndTransformFeedback(void)
+{
+ struct gl_transform_feedback_object *obj;
+ GET_CURRENT_CONTEXT(ctx);
+
+ obj = ctx->TransformFeedback.CurrentObject;
+
+ if (!obj->Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glEndTransformFeedback(not active)");
+ return;
+ }
+
+ ctx->TransformFeedback.CurrentObject->Active = GL_FALSE;
+
+ assert(ctx->Driver.EndTransformFeedback);
+ ctx->Driver.EndTransformFeedback(ctx, obj);
+}
+
+
+/**
+ * Helper used by BindBufferRange() and BindBufferBase().
+ */
+static void
+bind_buffer_range(struct gl_context *ctx, GLuint index,
+ struct gl_buffer_object *bufObj,
+ GLintptr offset, GLsizeiptr size)
+{
+ struct gl_transform_feedback_object *obj =
+ ctx->TransformFeedback.CurrentObject;
+
+ /* The general binding point */
+ _mesa_reference_buffer_object(ctx,
+ &ctx->TransformFeedback.CurrentBuffer,
+ bufObj);
+
+ /* The per-attribute binding point */
+ _mesa_reference_buffer_object(ctx,
+ &obj->Buffers[index],
+ bufObj);
+
+ obj->BufferNames[index] = bufObj->Name;
+
+ obj->Offset[index] = offset;
+ obj->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_transform_feedback_object *obj;
+ struct gl_buffer_object *bufObj;
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (target != GL_TRANSFORM_FEEDBACK_BUFFER) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferRange(target)");
+ return;
+ }
+
+ obj = ctx->TransformFeedback.CurrentObject;
+
+ if (obj->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)", (int) size);
+ return;
+ }
+
+ if (offset & 0x3) {
+ /* must be multiple of four */
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glBindBufferRange(offset=%d)", (int) 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 %d > buffer size %d)",
+ (int) (offset + size), (int) (bufObj->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_transform_feedback_object *obj;
+ struct gl_buffer_object *bufObj;
+ GLsizeiptr size;
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (target != GL_TRANSFORM_FEEDBACK_BUFFER) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferBase(target)");
+ return;
+ }
+
+ obj = ctx->TransformFeedback.CurrentObject;
+
+ if (obj->Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindBufferBase(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_transform_feedback_object *obj;
+ 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;
+ }
+
+ obj = ctx->TransformFeedback.CurrentObject;
+
+ if (obj->Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindBufferOffsetEXT(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 ||
+ (bufferMode == GL_SEPARATE_ATTRIBS &&
+ 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->DataType;
+ if (size)
+ *size = param->Size;
+ }
+ else {
+ name[0] = 0;
+ if (length)
+ *length = 0;
+ if (type)
+ *type = 0;
+ if (size)
+ *size = 0;
+ }
+}
+
+
+
+static struct gl_transform_feedback_object *
+lookup_transform_feedback_object(struct gl_context *ctx, GLuint name)
+{
+ if (name == 0) {
+ return ctx->TransformFeedback.DefaultObject;
+ }
+ else
+ return (struct gl_transform_feedback_object *)
+ _mesa_HashLookup(ctx->TransformFeedback.Objects, name);
+}
+
+
+/**
+ * Create new transform feedback objects. Transform feedback objects
+ * encapsulate the state related to transform feedback to allow quickly
+ * switching state (and drawing the results, below).
+ * Part of GL_ARB_transform_feedback2.
+ */
+void GLAPIENTRY
+_mesa_GenTransformFeedbacks(GLsizei n, GLuint *names)
+{
+ GLuint first;
+ GET_CURRENT_CONTEXT(ctx);
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (n < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGenTransformFeedbacks(n < 0)");
+ return;
+ }
+
+ if (!names)
+ return;
+
+ /* we don't need contiguous IDs, but this might be faster */
+ first = _mesa_HashFindFreeKeyBlock(ctx->TransformFeedback.Objects, n);
+ if (first) {
+ GLsizei i;
+ for (i = 0; i < n; i++) {
+ struct gl_transform_feedback_object *obj
+ = ctx->Driver.NewTransformFeedback(ctx, first + i);
+ if (!obj) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTransformFeedbacks");
+ return;
+ }
+ names[i] = first + i;
+ _mesa_HashInsert(ctx->TransformFeedback.Objects, first + i, obj);
+ }
+ }
+ else {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTransformFeedbacks");
+ }
+}
+
+
+/**
+ * Is the given ID a transform feedback object?
+ * Part of GL_ARB_transform_feedback2.
+ */
+GLboolean GLAPIENTRY
+_mesa_IsTransformFeedback(GLuint name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
+
+ if (name && lookup_transform_feedback_object(ctx, name))
+ return GL_TRUE;
+ else
+ return GL_FALSE;
+}
+
+
+/**
+ * Bind the given transform feedback object.
+ * Part of GL_ARB_transform_feedback2.
+ */
+void GLAPIENTRY
+_mesa_BindTransformFeedback(GLenum target, GLuint name)
+{
+ struct gl_transform_feedback_object *obj;
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (target != GL_TRANSFORM_FEEDBACK) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBindTransformFeedback(target)");
+ return;
+ }
+
+ if (ctx->TransformFeedback.CurrentObject->Active &&
+ !ctx->TransformFeedback.CurrentObject->Paused) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindTransformFeedback(transform is active, or not paused)");
+ return;
+ }
+
+ obj = lookup_transform_feedback_object(ctx, name);
+ if (!obj) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindTransformFeedback(name=%u)", name);
+ return;
+ }
+
+ reference_transform_feedback_object(&ctx->TransformFeedback.CurrentObject,
+ obj);
+}
+
+
+/**
+ * Delete the given transform feedback objects.
+ * Part of GL_ARB_transform_feedback2.
+ */
+void GLAPIENTRY
+_mesa_DeleteTransformFeedbacks(GLsizei n, const GLuint *names)
+{
+ GLint i;
+ GET_CURRENT_CONTEXT(ctx);
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (n < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteTransformFeedbacks(n < 0)");
+ return;
+ }
+
+ if (!names)
+ return;
+
+ for (i = 0; i < n; i++) {
+ if (names[i] > 0) {
+ struct gl_transform_feedback_object *obj
+ = lookup_transform_feedback_object(ctx, names[i]);
+ if (obj) {
+ if (obj->Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glDeleteTransformFeedbacks(object %u is active)",
+ names[i]);
+ return;
+ }
+ _mesa_HashRemove(ctx->TransformFeedback.Objects, names[i]);
+ /* unref, but object may not be deleted until later */
+ reference_transform_feedback_object(&obj, NULL);
+ }
+ }
+ }
+}
+
+
+/**
+ * Pause transform feedback.
+ * Part of GL_ARB_transform_feedback2.
+ */
+void GLAPIENTRY
+_mesa_PauseTransformFeedback(void)
+{
+ struct gl_transform_feedback_object *obj;
+ GET_CURRENT_CONTEXT(ctx);
+
+ obj = ctx->TransformFeedback.CurrentObject;
+
+ if (!obj->Active || obj->Paused) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glPauseTransformFeedback(feedback not active or already paused)");
+ return;
+ }
+
+ obj->Paused = GL_TRUE;
+
+ assert(ctx->Driver.PauseTransformFeedback);
+ ctx->Driver.PauseTransformFeedback(ctx, obj);
+}
+
+
+/**
+ * Resume transform feedback.
+ * Part of GL_ARB_transform_feedback2.
+ */
+void GLAPIENTRY
+_mesa_ResumeTransformFeedback(void)
+{
+ struct gl_transform_feedback_object *obj;
+ GET_CURRENT_CONTEXT(ctx);
+
+ obj = ctx->TransformFeedback.CurrentObject;
+
+ if (!obj->Active || !obj->Paused) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glResumeTransformFeedback(feedback not active or not paused)");
+ return;
+ }
+
+ obj->Paused = GL_FALSE;
+
+ assert(ctx->Driver.ResumeTransformFeedback);
+ ctx->Driver.ResumeTransformFeedback(ctx, obj);
+}
+
+
+/**
+ * Draw the vertex data in a transform feedback object.
+ * \param mode GL_POINTS, GL_LINES, GL_TRIANGLE_STRIP, etc.
+ * \param name the transform feedback object
+ * The number of vertices comes from the transform feedback object.
+ * User still has to setup of the vertex attribute info with
+ * glVertexPointer, glColorPointer, etc.
+ * Part of GL_ARB_transform_feedback2.
+ */
+void GLAPIENTRY
+_mesa_DrawTransformFeedback(GLenum mode, GLuint name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_transform_feedback_object *obj =
+ lookup_transform_feedback_object(ctx, name);
+
+ if (mode > GL_POLYGON) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glDrawTransformFeedback(mode=0x%x)", mode);
+ return;
+ }
+ if (!obj) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glDrawTransformFeedback(name = %u)", name);
+ return;
+ }
+
+ /* XXX check if EndTransformFeedback has never been called while
+ * the object was bound
+ */
+
+ assert(ctx->Driver.DrawTransformFeedback);
+ ctx->Driver.DrawTransformFeedback(ctx, mode, obj);
+}
+
+#endif /* FEATURE_EXT_transform_feedback */
diff --git a/mesalib/src/mesa/program/ir_to_mesa.cpp b/mesalib/src/mesa/program/ir_to_mesa.cpp
index bdbb6b938..93563bdaa 100644
--- a/mesalib/src/mesa/program/ir_to_mesa.cpp
+++ b/mesalib/src/mesa/program/ir_to_mesa.cpp
@@ -3191,7 +3191,7 @@ get_mesa_program(struct gl_context *ctx,
prog->Instructions = mesa_instructions;
prog->NumInstructions = num_instructions;
- do_set_program_inouts(shader->ir, prog);
+ do_set_program_inouts(shader->ir, prog, shader->Type == GL_FRAGMENT_SHADER);
count_resources(prog);
check_resources(ctx, shader_program, prog);
diff --git a/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
index 145bd7dcd..67a1b513b 100644
--- a/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
+++ b/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
@@ -4966,7 +4966,7 @@ get_mesa_program(struct gl_context *ctx,
prog->Instructions = NULL;
prog->NumInstructions = 0;
- do_set_program_inouts(shader->ir, prog);
+ do_set_program_inouts(shader->ir, prog, shader->Type == GL_FRAGMENT_SHADER);
count_resources(v, prog);
check_resources(ctx, shader_program, v, prog);